A Python client for the Mass Dynamics API.
pip install "git+https://github.com/MassDynamics/md-python.git"That tracks main. To pin a specific release instead, append its tag — the full list is on the
tags page:
pip install "git+https://github.com/MassDynamics/md-python.git@v0.3.12-60"CI mints a new tag on every merge to main, so prefer the unpinned form unless you have a reason
to hold a specific version.
from md_python import MDClient
client = MDClient(api_token="your_api_token")The client defaults to the v2 API. For v1 usage, see V1.md.
- Uploads: Create, retrieve, and manage file uploads
- Datasets: Create, list, retry, cancel, and delete datasets
- Entities: Query entity metadata across datasets
- Jobs: List available dataset jobs
- Health: Check API health status
Uploads replace v1 experiments. They handle file ingestion and workflow triggering.
from md_python import Upload, ExperimentDesign, SampleMetadata
experiment_design = ExperimentDesign(data=[
["filename", "sample_name", "condition"],
["evidence.txt", "sample1", "control"],
["proteinGroups.txt", "sample2", "treated"],
])
sample_metadata = SampleMetadata(data=[
["sample_name", "condition"],
["sample1", "control"],
["sample2", "treated"],
])
# Create an upload from S3
upload = Upload(
name="My Upload",
source="maxquant",
s3_bucket="my-bucket",
s3_prefix="data/",
filenames=["evidence.txt", "proteinGroups.txt"],
experiment_design=experiment_design,
sample_metadata=sample_metadata,
)
upload_id = client.uploads.create(upload)
# Create an upload from local files
upload = Upload(
name="My Upload",
source="maxquant",
file_location="/path/to/files",
filenames=["evidence.txt", "proteinGroups.txt"],
experiment_design=experiment_design,
sample_metadata=sample_metadata,
)
upload_id = client.uploads.create(upload)
# Get upload by ID
upload = client.uploads.get_by_id(upload_id)
# Get upload sample metadata
metadata = client.uploads.get_sample_metadata(upload_id)
# Update sample metadata
sample_metadata = SampleMetadata(data=[
["sample_name", "condition"],
["sample1", "control"],
["sample2", "treated"],
])
client.uploads.update_sample_metadata(upload_id, sample_metadata)
# Query uploads with filters and pagination
result = client.uploads.query(status=["completed"], source=["maxquant"], search="my upload", page=1)
uploads = result["data"]
pagination = result["pagination"]
# Delete an upload
client.uploads.delete(upload_id)
# Wait for upload processing to complete
upload = client.uploads.wait_until_complete(upload_id)from uuid import UUID
from md_python import Dataset
# Create a dataset
dataset = Dataset(
input_dataset_ids=[UUID("existing-dataset-id")],
name="Processed Data",
job_slug="pairwise_comparison",
job_run_params={"condition_column": "condition"},
)
dataset_id = client.datasets.create(dataset)
# Get a single dataset by ID (includes error_message)
dataset = client.datasets.get_by_id(dataset_id)
# List datasets for an upload (uses the query endpoint internally)
datasets = client.datasets.list_by_upload(upload_id)
# Query datasets with filters and pagination
result = client.datasets.query(upload_id=upload_id, state=["COMPLETED"], type=["INTENSITY"], page=1)
datasets = result["data"]
pagination = result["pagination"]
# Get a presigned URL for table download (csv or parquet)
url = client.datasets.download_table_url(dataset_id, "table_name", format="csv")
# Find the initial intensity dataset
initial = client.datasets.find_initial_dataset(upload_id)
# Retry a failed dataset
client.datasets.retry(dataset_id)
# Cancel a processing dataset
client.datasets.cancel(dataset_id)
# Delete a dataset
client.datasets.delete(dataset_id)
# Wait for a dataset to complete
ds = client.datasets.wait_until_complete(upload_id, dataset_id)# Query entity metadata (proteins, genes, peptides) across datasets
result = client.entities.query(keyword="BRCA1", dataset_ids=["dataset-id-1", "dataset-id-2"])
entities = result["results"]
# Returns network graph that represents the mapping of input `entity_ids`
# to other entities using the specified mapping mode
result = client.entities.graph(
mode='protein_to_metabolite',
dataset_ids=[
"c7215a65-dd68-4051-a158-f369b6eeed6a",
"82d4d3ba-3733-4987-91d8-7f83d2afba09",
"7e880efc-349d-42c6-869e-671af57bb970",
"643d23ec-65a2-44c4-ada4-694032183945",
"8b398f3e-6f3f-4a37-a5ea-bfe0a2edb4d6",
"de83ea45-45fc-4242-9455-64b8236a6aac",
"d7d5582f-7b15-405a-bed2-9d81f1a32ff6",
"d2a485ca-df13-4974-8c05-c5adcdf7669c",
"48ee0eeb-3d2e-422f-bdeb-41938ffad5b4",
"5a6ce013-d77a-4eb4-8eb6-715f044ef2bc",
"8a02d25c-68e5-4def-b090-fc4fe39f011d",
"def259ea-9caa-4416-b2bd-750983138041"
],
entity_ids=[
"P19367",
],
)client.jobs.list() returns Job objects describing every analysis flow the API exposes.
Each carries a properties dict — the parameter definition the UI renders — which is the
source of truth for what belongs in a dataset's job_run_params.
from md_python.models import Job
# List available dataset jobs
jobs = client.jobs.list()
job = next(j for j in jobs if j.slug == "pairwise_comparison")
job.slug # "pairwise_comparison"
job.name # "pairwise comparison"
job.run_type # "PAIRWISE"
job.is_published # True
job.description # HTML description shown in the UI
job.properties # {field_name: {fieldType, default, rules, ...}, ...}
# Inspect the parameters a job accepts
for name, spec in job.properties.items():
required = any(r.get("name") == "is_required" for r in spec.get("rules", []))
print(name, spec.get("fieldType"), spec.get("default"), "REQUIRED" if required else "")Two things to know when turning properties into job_run_params:
input_datasetsis listed but is not ajob_run_paramskey. The server populates it from theinput_dataset_idsyou pass toclient.datasets.create().- Some fields only apply in combination. For example
filter_values_criteriais a string selector ("percentage"or"count") with a matching sibling field —filter_threshold_percentageorfilter_threshold_count. Send the one that matches.
Changed in 0.3.5:
client.jobs.list()previously returnedList[Dict[str, Any]]and now returnsList[Job]. Code that readjob["slug"]should readjob.slug. Note also that the raw payload spelled the published flagisPublished, whereJobexposesis_published.
health_status = client.health.check()client = MDClient(
api_token="your_api_token",
base_url="https://xxx.massdynamics-example-installation.com/api",
)For v1 API usage, pass version="v1" or see V1.md.
client = MDClient(api_token="your_api_token", version="v1")git clone https://github.com/MassDynamics/md-python.git
cd md-python
pip install -e ".[dev]"
pytest