Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
9384684
introduce CroissantWrapper; add -d; logging; write zip
jswelling Aug 14, 2026
de508ac
separate CroissantWrapper
jswelling Aug 18, 2026
abb5621
use a scratch directory; save only zip
jswelling Aug 18, 2026
e68ccdf
working on provenance. WIP.
jswelling Aug 20, 2026
9c05578
walk_ancestors is working. WIP.
jswelling Aug 21, 2026
18197c5
working walk_ancestors
jswelling Aug 25, 2026
08620e9
better docstring for walk_ancestors
jswelling Aug 25, 2026
bc6b25f
croissant provenance fully functional
jswelling Aug 26, 2026
9569375
croissant now knows about files but not records
jswelling Aug 26, 2026
eb6052f
support version, cite_as, license, date_published for croissant
jswelling Aug 27, 2026
6d18f77
previous_version_uuid should be previous_revision_uuid
jswelling Aug 27, 2026
35b2643
add some edam codes; fix edam logic
jswelling Aug 27, 2026
e4612a3
first pass rocrate prov for derived dataset. WIP.
jswelling Aug 28, 2026
cda7854
fix derived dataset workflow agent
jswelling Aug 28, 2026
932e00d
workflow crate passes validation
jswelling Aug 31, 2026
ab54f5a
cleanup
jswelling Aug 31, 2026
59397b5
more cleanup
jswelling Aug 31, 2026
5cd94bb
refactor out extractors
jswelling Sep 1, 2026
950f722
move pipeline_steps to extractors
jswelling Sep 1, 2026
1b0a5c1
introduce WrappedEntity
jswelling Sep 1, 2026
4e09468
use WrappedEntity throughout
jswelling Sep 1, 2026
d7388ca
working on workflow steps. WIP.
jswelling Sep 1, 2026
a797e39
checkpoint (WIP)
jswelling Sep 1, 2026
77766ac
fix cwl info for steps
jswelling Sep 2, 2026
655794e
hardcode CWL version
jswelling Sep 2, 2026
119a6ec
add full workflow description
jswelling Sep 2, 2026
16f23b5
working but incomplete primary ds provenance
jswelling Sep 3, 2026
efa30a0
black/lint
jswelling Sep 3, 2026
0b3e27b
spelling error
jswelling Sep 3, 2026
dd3f5f9
black
jswelling Sep 3, 2026
e30381b
croissant[dev] requires black 23.11.0
jswelling Sep 3, 2026
fd9c3e1
lint
jswelling Sep 3, 2026
743d9eb
black
jswelling Sep 3, 2026
de7bb48
add pyproject.toml
jswelling Sep 3, 2026
8e84c2d
trying to fix python 3.13 pandas build error
jswelling Sep 3, 2026
9cdb341
clean up get() defaults
jswelling Sep 5, 2026
6b9a69e
use parent doi_url if necessary
jswelling Sep 8, 2026
bf41e3e
fix croissant handling of snare-seq
jswelling Sep 8, 2026
fdd99b9
better info for failed entity fetches
jswelling Sep 8, 2026
35683a6
allow python steps to support IVT
jswelling Sep 8, 2026
4b482ef
more flexible EDAM code handling
jswelling Sep 8, 2026
261e3ef
support datasets with missing workflow info
jswelling Sep 9, 2026
0d6b0e1
armor against earlier contributor format
jswelling Sep 9, 2026
f452a49
make robust against missing file attributes
jswelling Sep 9, 2026
b97f721
support EDAM 2333
jswelling Sep 9, 2026
c07b4a6
armor against missing sample description
jswelling Sep 9, 2026
15dc521
fix walk_ancestors
jswelling Sep 10, 2026
4d83df3
small lru cache for fetches
jswelling Sep 10, 2026
d72e390
linting
jswelling Sep 10, 2026
7a82ec4
Add EDAM 3003
jswelling Sep 11, 2026
0d09c5c
croissant citeAs to BiBTeX
jswelling Sep 15, 2026
1555ec6
linting
jswelling Sep 15, 2026
280b97c
adding keywords. WIP.
jswelling Sep 15, 2026
e5a80f9
working keywords for rocrate and croissant
jswelling Sep 15, 2026
b85d439
lint
jswelling Sep 16, 2026
691431f
missing import in inactive code?
jswelling Sep 17, 2026
d8e9682
flake8
jswelling Sep 17, 2026
056b71c
added entity_iri(); black
jswelling Sep 29, 2026
db99ab7
flake8
jswelling Sep 29, 2026
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
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tool.isort]
profile = "black"
multi_line_output = 3

90 changes: 90 additions & 0 deletions src/crate_builder_script/api_calls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Handle requests to HuBMAP APIs."""
import logging
import os
from functools import lru_cache
from pprint import pformat
from typing import Any

import requests

LOGGER = logging.getLogger(__name__)

ENTITY_API = "https://entity.api.hubmapconsortium.org"
ASSETS_API = "https://assets.hubmapconsortium.org"
UUID_API = "https://uuid.api.hubmapconsortium.org"

AUTH_TOK = os.environ["AUTH_TOK"]

HUBMAP = "https://hubmapconsortium.org/"
Comment thread
jswelling marked this conversation as resolved.

HUBMAP_ORG_ENTITY = HUBMAP # for lack of a better choice

ENTITY_BASE = "https://portal.hubmapconsortium.org/browse/"

HUBMAP_ORG_ENTITY = HUBMAP # for lack of a better choice


def entity_iri(entity: Any) -> str:
"""Return a resolvable IRI for a HuBMAP entity (dataset / sample / donor).

Raw datasets and multi-assay splits carry `doi_url`; processed datasets, samples
and donors do not, and fall back to the portal browse URL, which resolves by
HuBMAP ID for every entity type.
"""
return entity.get("doi_url") or ENTITY_BASE + (entity.get("hubmap_id") or "")


@lru_cache(maxsize=8)
def fetch_entity_info(target_id: str) -> dict[str, Any]:
"""Fetch a dataset's entity information."""
LOGGER.debug("FETCH %s", target_id)
try:
resp = requests.get(
ENTITY_API + f"/entities/{target_id}",
headers={"Authorization": f"Bearer {AUTH_TOK}"},
)
resp.raise_for_status()
except Exception as excp:
raise RuntimeError(f"Fetch of entity {target_id} failed: {excp}") from excp
ds_info = resp.json()
LOGGER.debug("TOP LEVEL for %s:\n%s", target_id, pformat(ds_info, depth=1))
LOGGER.debug(
"INGEST METADATA:\n%s", pformat(ds_info.get("ingest_metadata", {}), depth=2)
)
LOGGER.debug("METADATA:\n%s", pformat(ds_info.get("metadata", {}), depth=2))
LOGGER.debug(
"DIRECT ANCESTORS: %s\n%s",
[elt["hubmap_id"] for elt in ds_info.get("direct_ancestors", [])],
pformat(ds_info.get("direct_ancestors"), depth=2),
)
LOGGER.debug(
"DIRECT ANCESTOR:\n%s", pformat(ds_info.get("direct_ancestor"), depth=2)
)
if "direct_ancestors" in ds_info:
first_ancestor = ds_info["direct_ancestors"][0]
elif "direct_ancestor" in ds_info:
first_ancestor = ds_info["direct_ancestor"]
else:
first_ancestor = {}
LOGGER.debug(
"ANCESTOR INGEST MD\n%s", pformat(first_ancestor.get("ingest_metadata", {}))
)
LOGGER.debug("ANCESTOR MD\n%s", pformat(first_ancestor.get("metadata", {})))
return ds_info


@lru_cache(maxsize=8)
def fetch_uuid_files_info(target_id: str) -> dict[str, Any]:
"""Fetch files informaion from the UUID API."""
resp = requests.get(
UUID_API + f"/{target_id}/files",
headers={"Authorization": f"Bearer {AUTH_TOK}"},
)
resp.raise_for_status()
# LOGGER.debug("UUID FILES first 10:\n%s", pformat(resp.json()[:10]))
return resp.json()


def asset_url(uuid: str, rel_path: str) -> str:
"""Build the URL by which a file should be available from the ASSETS API."""
return f"{ASSETS_API}/{uuid}/{rel_path}"
Loading
Loading