Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 1 addition & 80 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,80 +1 @@
# Contributing

## Installation

This project requires Artifactory credentials. For local development, one can
obtain these from their jfrog user profile
[here](https://mdsol.jfrog.io/ui/admin/artifactory/user_profile)

### Installation (Docker - recommended)

To setup your python docker container, download the [engineering helper scripts](https://github.com/mdsol/engineering-helper-scripts/blob/6484ac03490c0562cee26aca89bfbed11e5124e2/.travis.yml#L6) into a
directory parallel to this one and run

`PACKAGE_GROUPS="dev,test" ../engineering-helper-scripts/docker/build_container.sh .12factor/Dockerfile --build-arg PACKAGE_GROUPS`

Once your container is built, you can then use `docker compose up` to get
terminal access and attach to the container.

By using Docker compose, any work you do inside the container will be copied
into your local machine. This is especially useful when the poetry lock file
needs to be regenerated by running `poetry lock` inside the container.

NOTE: As poetry is not built into the final layer you'll need to build an
image with the python_packages as a target in order to update the lock file.

`PACKAGE_GROUPS="dev,test" ../engineering-helper-scripts/docker/build_container.sh .12factor/Dockerfile --build-arg PACKAGE_GROUPS --target=python_packages`

NOTE2: Make sure `.dockerignore` is updated to just include the files/folders you need in your build context.

### Installation (Local)

In order to install this package, you will first need to install poetry.
See [here](https://python-poetry.org/docs/#installation) for instructions.

You can configure poetry via:

WARNING: Do not check your config file into version control or build it into a Docker image. Doing so will compromise your API KEY.

```bash
poetry config http-basic.mdsol <ARTIFACTORY_USERNAME> <ARTIFACTORY_PASSWORD>
```

Once these are in place, you can install the package inside a local
virtual environment via:

```bash
poetry install
```

## Testing

This project uses [pytest](https://docs.pytest.org/en/7.1.x/contents.html)
for automated testing

You can run the test suite within the projects virtual environment via:

```bash
poetry run pytest
```

Or activate a shell and run the test inside the environment:

```bash
poetry shell
pytest
```

You can also distribute the execution of the test suite on multiple CPUs:

```bash
pytest -n <n_cpu>
```

See [pytest's documentation](https://docs.pytest.org/en/latest/contents.html)
for a more detailed guide.

## Branching

Please branch out of main, and open a PR. Merges require at least one reviewer.
All tests must pass in travis before merge.
**Public contribution is currently not allowed.**
Comment thread
nmakarava-mdsol marked this conversation as resolved.
55 changes: 10 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,17 @@
# dataconnect-library-python
# Medidata DataConnect Python library

Python SDK for the [Medidata DataConnect](https://github.com/mdsol/dataconnect-library-r) service.
## Overview

---
This Python library is built by Medidata to give technical users of Medidata Clinical Data Studio and Medidata Data Connect, including clinical programmers, data scientists, and statisticians, access to relevant data directly within their existing Python environment. You can use it with core Python functionality and other Python libraries in your workflow.

## Transport note
**Note**: This Python library is supported for use in Python environments only. Compatibility with non-Python IDEs is not guaranteed or supported.

The DataConnect service uses **Apache Arrow Flight** (gRPC binary protocol), and **not** a plain REST/HTTP API. `pyarrow.flight` is the primary transport
dependency.
# Versioned Documentation

---
This directory contains documentation snapshots for each release of the `dataconnect` Python library.

## Installation
## Available Versions

```bash
pip install dataconnect # core (pyarrow)
pip install dataconnect[pandas] # + pandas for .to_pandas() on results
```

Requires **Python ≥ 3.13**.

---

## Quick start

```python
from uuid import UUID

from dataconnect import DataConnectClient


with DataConnectClient.connect(
host="dataconnect.example.com",
port=443,
token="your-bearer-token",
) as client:

result = client.get_studies(search_study_name="ACME")
print(result.total) # total number of studies accessible to the user
print(result.studies) # list of Study objects

pagination = client.get_datasets(study_environment_uuid=UUID("cec9f2a7-07ba-4fa8-bfcf-34fbc5d56793"))
datasets = pagination.items

```
## Development

```bash
pip install -e ".[dev]"
pytest
```
| Version | Documentation | Current version |
|---------|---------------------------------------------|-----------------|
|1.0.0 | [README-v1.0.0.md](readme/README-v1.0.0.md) | Yes |
202 changes: 202 additions & 0 deletions readme/README-v1.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# DataConnect Python Library v1.0.0

The DataConnect Python library provides a Python client for connecting to Medidata DataConnect and retrieving relevant data programmatically.
To use this library, you must have a valid iMedidata account and access to required building blocks in the Medidata Platform. For details, see the Medidata [Knowledge Hub](https://learn.medidata.com/en-US/bundle/data-connect/page/developer_center.html).

## Table of Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Authentication and Connectivity](#authentication-and-connectivity)
- [Functions](#functions)
- [connect()](#connect)
- [get_studies()](#get_studies)
- [get_datasets()](#get_datasets)
- [get_dataset_versions()](#get_dataset_versions)
- [fetch_data()](#fetch_data)
- [close()](#close)
- [Errors](#errors)
- [Reporting known issues](#reporting-known-issues)
- [Backend](#backend)
- [Licensing](#licensing)
Comment thread
nmakarava-mdsol marked this conversation as resolved.

## Installation

To install, follow the [Installation Guide](https://github.com/mdsol/dataconnect-library-r/blob/main/vignettes/dataconnect/readme/vignettes/pythonLibrary_setup.md).

## Quick Start

For end-to-end examples, see the [Usage Guide]().

### Authentication and Connectivity

* **Retrieving data:** You must have a user token to establish a connection between your Python environment and Medidata Data Connect. You can generate this token through Data Connect’s Developer Center. For details, visit the [knowledge hub](https://learn.medidata.com/en-US/bundle/data-connect/page/developer_center.html). Medidata recommends that you save the token in a local file and input it into the below initiation function.

* **Publish data:** You must have a project token to publish a dataset from your Python environment to Medidata Data Connect. You can generate this token through Data Connect > Transformations, by creating a Custom Code project. For details, visit the [knowledge hub](https://learn.medidata.com/en-US/bundle/data-connect/page/generate_custom_code_projects.html).

## Functions

The main public entry point is `DataconnectClient`.

### connect()

#### Description
Creates a connected client.

#### Usage
`connect(token="")`

#### Arguments
| Argument | Type | Description |
|---|---|---|
| host | str | Server host. Default host="enodia-gateway.platform.imedidata.com" |
| port | int | Server port. Default port="443" |
| use_tls | bool | Denotes whether to use TLS. Default use_tls = True |
| token | str | Authentication token, this is the user authentication token generated from the Developer Center in Medidata Data Connect |

#### Output
DataconnectClient object. This enables you to interact with Medidata Data Connect data in Python environment.

---

### get_studies()

#### Description
Retrieves a list of studies where the user has permission to manage custom code projects. Use the optional study name search parameter to filter results.

#### Usage
`get_studies(search_study_name=None)`

#### Arguments
| Argument | Type | Description |
|---|---|---|
| search_study_name | str or None | Optional. The approximate name of the study |

#### Output
Returns a list containing `total_records` (total studies available) and a `studies` array. Each study includes `name`, `uuid`, and an environments array. Each environment includes `name` and `uuid`.

---

### get_datasets()

#### Description
Retrieves datasets for a specific study environment and returns paginated results.

#### Usage
`get_datasets(study_environment_uuid, search_dataset_name="", page=1, page_size=50)`

#### Arguments
| Argument | Type | Description |
|---|---|---|
| study_environment_uuid | UUID | Unique iMedidata study environment identifier. You can find this in iMedidata’s Developer Info details |
| search_dataset_name | str | Optional. The approximate name of the dataset |
| page | int | Optional. Page number for paginated results. Default: 1 |
| page_size | int | Optional. Number of results per page. Default: 50 |

#### Output
Returns a list containing `total_records` (total datasets available across all pages), `pagination` and `datasets` array.

---

### get_dataset_versions()

#### Description
Retrieves all available versions for a dataset.

#### Usage
`get_dataset_versions(dataset_uuid)`

#### Arguments
| Argument | Type | Description |
|---|---|---|
| dataset_uuid | UUID | Unique iMedidata dataset identifier. This is available in the output of datasets() function |

#### Output
Returns all available versions of the dataset.

---

### fetch_data()

#### Description
Fetches dataset rows into a pandas DataFrame.

#### Usage
`fetch_data(dataset_uuid, first_n_rows=None)`

#### Arguments
| Argument | Type | Description |
|---|---|---|
| dataset_uuid | UUID | Unique iMedidata dataset identifier. This is available in the output of datasets() and dataset_versions() functions |
| first_n_rows | int or None | Optional positive row limit |

#### Output
Returns data from a specific dataset.

---

### close()

#### Description
Closes the underlying transport connection.

#### Usage
`close()`

#### Arguments
None

#### Output
None

## Errors
The library raises exceptions for many reasons, such as invalid parameters, authentication errors, and validation failures. We have introduced error codes for each category of errors to be handled programmatically.

| Error Code | Type | Scenario|
| :--- | :--- |:---|
| AUTHZ_001 | Authorization | Authorization service check failed |
| VAL_002 | Validation - Page Number | Page number is not a positive integer
| VAL_003 | Validation - Page Size | Page size is out of range [1, 100]
| VAL_004 | Validation - Study Parameter | Invalid study uuid
| VAL_005 | Validation - Study Environment Parameter | Missing or invalid study environment uuid
| VAL_006 | Validation - Dataset Parameter | Invalid dataset uuid
| VAL_007 | Validation - Configuration Error | Required input parameters are missing or invalid in configuration
| VAL_008 | Validation - Project Token | Invalid project token
| VAL_009 | Validation - Unsupported Data Type | Unsupported data types.
| VAL_010 | Validation - Unsupported Data Type | Unsupported datetime formats.
| VAL_011 | Validation - Pagination | Pagination is out of range
| VAL_012 | Validation - Concurrency | Project actively being published
| VAL_013 | Validation - Formatting Error | Data validation failed. One or more records contain formatting errors.
| RES_002 | Resource Exceptions - Study Environment | No authorized Study Environments found for the authenticated user
| RES_003 | Resource Exceptions - Invalid parameter | Incorrect UUID combination.
| RES_004 | Resource Exceptions - Invalid parameter | Incorrect UUID combination.
| RES_005 | Resource Exceptions - Study Group | Study Group not found for the Dataset's Study Environment.
| RES_006 | Resource Exceptions - Study | Study Group not found for the Dataset's Study Environment.
| RES_007 | Resource Exceptions - Client Division | Client Division not found for the Dataset's Study Environment.
| RES_008 | Resource Exceptions - Custom Code Project | Transformation Project is not found.
| INT_001 | Internal Application Exception | Something went wrong on our end.
Comment thread
nmakarava-mdsol marked this conversation as resolved.

# Reporting known issues

If you believe you have found an issue, please contact Medidata Support by submitting a ticket to Medidata Support. All issue reports should include a minimal reproducible example to ensure our team can diagnose the issue.

Additionally, all known issues are available [here](https://learn.medidata.com/en-US/bundle/current-issues/page/current_known_issues_for_data_connect.html).

# Backend

This library uses the Arrow open source library and the Iceberg open table format to enable data interoperability across platforms.

* [Apache arrow](https://arrow.apache.org/docs/r/): This library uses Arrow’s highly efficient format [pyarrow](https://arrow.apache.org/cookbook/py/flight.html) to transfer massive datasets over the network, allowing users to access & interact with remote datasets.

* [Apache Iceberg](https://iceberg.apache.org/): This is the open table format underlying Medidata Data Connect's structured data management to support high-performance and reliable data analytics and storage.

# Licensing

BY DOWNLOADING THIS FILE (“DOWNLOAD”) YOU AGREE TO THE FOLLOWING TERMS:
MEDIDATA SOLUTIONS, INC. AND ITS AFFILIATES (COLLECTIVELY “MEDIDATA”) GRANT A FREE OF CHARGE, NON-EXCLUSIVE AND NON-TRANSFERABLE RIGHT TO USE THE DOWNLOAD. USE OF THIS DOWNLOAD IS PERMITTED FOR INTERNAL BUSINESS PURPOSES ONLY.

THIS DOWNLOAD IS MADE AVAILABLE ON AN "AS IS" BASIS WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, ORAL OR WRITTEN, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT.

MEDIDATA SHALL HAVE NO LIABILITY FOR DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES, INCLUDING, WITHOUT LIMITATION, CLAIMS FOR LOST PROFITS, BUSINESS INTERRUPTION AND LOSS OF DATA THAT IN ANY WAY RELATE TO THIS DOWNLOAD, WHETHER OR NOT MEDIDATA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.

YOUR USE OF THIS DOWNLOAD SHALL BE AT YOUR SOLE RISK. NO SUPPORT OF ANY KIND OF THE DOWNLOAD IS PROVIDED BY MEDIDATA.
44 changes: 44 additions & 0 deletions vignettes/pythonLibrary_setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Data Connect Python Library - Setup

Choose one of the following approaches.

### Option 1: Install from source (recommended for this repository)

```bash
git clone <repository-url>
cd dataconnect-library-python
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e .
Comment thread
nmakarava-mdsol marked this conversation as resolved.
```

### Option 2: Install using Poetry

```bash
git clone <repository-url>
cd dataconnect-library-python
poetry install
poetry shell
```

## Quick Start

```python
from uuid import UUID

from Dataconnect import DataconnectClient

with DataconnectClient.connect(token="your-bearer-token") as client:
studies = client.get_studies()
print(f"Found {len(studies)} studies")

if studies and studies[0].environments:
study_environment_uuid = studies[0].environments[0].uuid
datasets_data = client.get_datasets(study_environment_uuid=study_environment_uuid, page=1, page_size=10)
print(f"Found {datasets_data.total_records} datasets")

if datasets_data.items:
dataset_uuid = UUID(datasets_data.items[0].dataset_uuid)
df = client.fetch_data(dataset_uuid, first_n_rows=100)
print(df.head())
```
Loading