aabatlas 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aabatlas-0.1.0/.gitignore +20 -0
- aabatlas-0.1.0/LICENSE +21 -0
- aabatlas-0.1.0/PKG-INFO +60 -0
- aabatlas-0.1.0/README.md +38 -0
- aabatlas-0.1.0/pyproject.toml +34 -0
- aabatlas-0.1.0/src/aabatlas/__init__.py +18 -0
- aabatlas-0.1.0/src/aabatlas/_source.py +40 -0
- aabatlas-0.1.0/src/aabatlas/citation.py +25 -0
- aabatlas-0.1.0/src/aabatlas/datasets.py +84 -0
- aabatlas-0.1.0/src/aabatlas/download.py +48 -0
- aabatlas-0.1.0/tests/conftest.py +15 -0
- aabatlas-0.1.0/tests/test_datasets.py +39 -0
aabatlas-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexandre Marques
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to
|
|
7
|
+
deal in the Software without restriction, including without limitation the
|
|
8
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
9
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
DEALINGS IN THE SOFTWARE.
|
aabatlas-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aabatlas
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Client for the antibodyome-atlas, a curated catalog of autoantibody profiling datasets and papers
|
|
5
|
+
Project-URL: Homepage, https://github.com/ahcm088/antibodyome-atlas
|
|
6
|
+
Project-URL: Issues, https://github.com/ahcm088/antibodyome-atlas/issues
|
|
7
|
+
Author-email: Alexandre Marques <marquesufcg@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ArrayExpress,GEO,autoantibody,bioinformatics,proteomics
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Requires-Dist: pandas>=1.5
|
|
18
|
+
Requires-Dist: requests>=2.31
|
|
19
|
+
Provides-Extra: test
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# aabatlas
|
|
24
|
+
|
|
25
|
+
Python client for the [antibodyome-atlas](https://github.com/ahcm088/antibodyome-atlas), a curated catalog of autoantibody profiling datasets and papers. See `schema/README.md` in the atlas repo for the data model. Mirrors the R client, [AAbAtlas](../r-package).
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
Not yet on PyPI. Until then, install from GitHub:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install "git+https://github.com/ahcm088/antibodyome-atlas.git#subdirectory=python-package"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import aabatlas
|
|
39
|
+
|
|
40
|
+
# browse
|
|
41
|
+
ds = aabatlas.list_datasets()
|
|
42
|
+
ds[(ds["record_type"] == "DATASET") & (ds["total_sample_n"] > 100)][["atlas_id", "title", "total_sample_n"]]
|
|
43
|
+
|
|
44
|
+
# one record, with its publication and platforms resolved
|
|
45
|
+
rec = aabatlas.get_dataset("AAB-000004")
|
|
46
|
+
rec["title"]
|
|
47
|
+
rec["publication"]["citation"]
|
|
48
|
+
|
|
49
|
+
# citation ready to paste into a manuscript
|
|
50
|
+
aabatlas.get_citation("AAB-000004")
|
|
51
|
+
|
|
52
|
+
# download the underlying file
|
|
53
|
+
aabatlas.download("AAB-000004")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
By default every function reads the latest curated data (`ref="main"`). Pin a release tag for reproducibility in a publication:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
aabatlas.list_datasets(ref="v1.0.0")
|
|
60
|
+
```
|
aabatlas-0.1.0/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# aabatlas
|
|
2
|
+
|
|
3
|
+
Python client for the [antibodyome-atlas](https://github.com/ahcm088/antibodyome-atlas), a curated catalog of autoantibody profiling datasets and papers. See `schema/README.md` in the atlas repo for the data model. Mirrors the R client, [AAbAtlas](../r-package).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Not yet on PyPI. Until then, install from GitHub:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install "git+https://github.com/ahcm088/antibodyome-atlas.git#subdirectory=python-package"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import aabatlas
|
|
17
|
+
|
|
18
|
+
# browse
|
|
19
|
+
ds = aabatlas.list_datasets()
|
|
20
|
+
ds[(ds["record_type"] == "DATASET") & (ds["total_sample_n"] > 100)][["atlas_id", "title", "total_sample_n"]]
|
|
21
|
+
|
|
22
|
+
# one record, with its publication and platforms resolved
|
|
23
|
+
rec = aabatlas.get_dataset("AAB-000004")
|
|
24
|
+
rec["title"]
|
|
25
|
+
rec["publication"]["citation"]
|
|
26
|
+
|
|
27
|
+
# citation ready to paste into a manuscript
|
|
28
|
+
aabatlas.get_citation("AAB-000004")
|
|
29
|
+
|
|
30
|
+
# download the underlying file
|
|
31
|
+
aabatlas.download("AAB-000004")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
By default every function reads the latest curated data (`ref="main"`). Pin a release tag for reproducibility in a publication:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
aabatlas.list_datasets(ref="v1.0.0")
|
|
38
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aabatlas"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Client for the antibodyome-atlas, a curated catalog of autoantibody profiling datasets and papers"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Alexandre Marques", email = "marquesufcg@gmail.com" }]
|
|
13
|
+
keywords = ["autoantibody", "proteomics", "bioinformatics", "GEO", "ArrayExpress"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Science/Research",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"requests>=2.31",
|
|
23
|
+
"pandas>=1.5",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
test = ["pytest>=7.0"]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/ahcm088/antibodyome-atlas"
|
|
31
|
+
Issues = "https://github.com/ahcm088/antibodyome-atlas/issues"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/aabatlas"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Client for the antibodyome-atlas."""
|
|
2
|
+
from ._source import raw_url
|
|
3
|
+
from .citation import get_citation
|
|
4
|
+
from .datasets import get_dataset, list_datasets, list_link_status, list_platforms, list_publications
|
|
5
|
+
from .download import download
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"list_datasets",
|
|
11
|
+
"list_publications",
|
|
12
|
+
"list_platforms",
|
|
13
|
+
"list_link_status",
|
|
14
|
+
"get_dataset",
|
|
15
|
+
"get_citation",
|
|
16
|
+
"download",
|
|
17
|
+
"raw_url",
|
|
18
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Internal: fetch and parse the atlas's GitHub-hosted JSON manifests."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
_FILES = ("datasets", "publications", "platforms", "link_status", "seeds")
|
|
8
|
+
_USER_AGENT = "aabatlas-python/0.1 (+https://github.com/ahcm088/antibodyome-atlas)"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def raw_url(file: str, ref: str = "main") -> str:
|
|
12
|
+
"""Build the raw GitHub URL for one of the atlas's metadata files.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
file:
|
|
17
|
+
One of "datasets", "publications", "platforms", "link_status", "seeds".
|
|
18
|
+
ref:
|
|
19
|
+
Git ref (branch, tag, or commit SHA) to read from. Defaults to
|
|
20
|
+
"main" (the latest curated data). Pin to a release tag (e.g.
|
|
21
|
+
"v1.0.0") for reproducible results in a publication.
|
|
22
|
+
"""
|
|
23
|
+
if file not in _FILES:
|
|
24
|
+
raise ValueError(f"file must be one of {_FILES}, got {file!r}")
|
|
25
|
+
return f"https://raw.githubusercontent.com/ahcm088/antibodyome-atlas/{ref}/metadata/{file}.json"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def fetch(file: str, ref: str = "main") -> pd.DataFrame:
|
|
29
|
+
"""Fetch and parse one of the atlas's JSON manifests as a DataFrame.
|
|
30
|
+
|
|
31
|
+
Nested fields (e.g. ``conditions``, ``platforms``, ``source_ids``) come
|
|
32
|
+
back as object-dtype columns holding Python lists/dicts.
|
|
33
|
+
"""
|
|
34
|
+
url = raw_url(file, ref=ref)
|
|
35
|
+
resp = requests.get(url, timeout=30, headers={"User-Agent": _USER_AGENT})
|
|
36
|
+
resp.raise_for_status()
|
|
37
|
+
data = resp.json()
|
|
38
|
+
if not data:
|
|
39
|
+
return pd.DataFrame()
|
|
40
|
+
return pd.DataFrame(data)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Citation helper."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .datasets import get_dataset
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_citation(atlas_id: str, ref: str = "main") -> dict[str, Any]:
|
|
10
|
+
"""Get the citation for a dataset, ready to paste into a manuscript.
|
|
11
|
+
|
|
12
|
+
Returns a dict with ``atlas_id``, ``dataset_link``, ``citation``,
|
|
13
|
+
``doi``, ``pubmed_link``, ``publisher_link``. Publication fields are
|
|
14
|
+
``None`` if the record has no associated publication.
|
|
15
|
+
"""
|
|
16
|
+
record = get_dataset(atlas_id, ref=ref)
|
|
17
|
+
pub = record.get("publication") or {}
|
|
18
|
+
return {
|
|
19
|
+
"atlas_id": record["atlas_id"],
|
|
20
|
+
"dataset_link": record["dataset_link"],
|
|
21
|
+
"citation": pub.get("citation"),
|
|
22
|
+
"doi": pub.get("doi"),
|
|
23
|
+
"pubmed_link": pub.get("pubmed_link"),
|
|
24
|
+
"publisher_link": pub.get("publisher_link"),
|
|
25
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""List and resolve atlas records."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from ._source import fetch
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def list_datasets(ref: str = "main") -> pd.DataFrame:
|
|
12
|
+
"""List all datasets/papers in the atlas.
|
|
13
|
+
|
|
14
|
+
Columns match ``schema/dataset.schema.json`` in the atlas repo
|
|
15
|
+
(``atlas_id``, ``record_type``, ``title``, ``organism``, ``conditions``,
|
|
16
|
+
``total_sample_n``, ``platforms``, ``dataset_link``,
|
|
17
|
+
``curated_availability``, etc.). List/dict-valued fields come back as
|
|
18
|
+
Python objects in object-dtype columns.
|
|
19
|
+
"""
|
|
20
|
+
return fetch("datasets", ref=ref)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def list_publications(ref: str = "main") -> pd.DataFrame:
|
|
24
|
+
"""List all publications referenced by atlas datasets."""
|
|
25
|
+
return fetch("publications", ref=ref)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def list_platforms(ref: str = "main") -> pd.DataFrame:
|
|
29
|
+
"""List all assay platforms referenced by atlas datasets.
|
|
30
|
+
|
|
31
|
+
Per-study protein/feature counts live on the dataset record
|
|
32
|
+
(``list_datasets()["platforms"]``), not here -- see ``schema/README.md``
|
|
33
|
+
in the atlas repo for why.
|
|
34
|
+
"""
|
|
35
|
+
return fetch("platforms", ref=ref)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def list_link_status(ref: str = "main") -> pd.DataFrame:
|
|
39
|
+
"""List the link-reachability check history.
|
|
40
|
+
|
|
41
|
+
One row per automated check, appended over time by the atlas's
|
|
42
|
+
scheduled link checker. ``reachable`` is the raw HTTP signal;
|
|
43
|
+
``likely_bot_blocked`` flags 403/429 responses from publisher anti-bot
|
|
44
|
+
defenses, which are not necessarily dead links.
|
|
45
|
+
"""
|
|
46
|
+
return fetch("link_status", ref=ref)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_dataset(atlas_id: str, ref: str = "main") -> dict[str, Any]:
|
|
50
|
+
"""Get a single dataset record, with its publication and platforms resolved.
|
|
51
|
+
|
|
52
|
+
Returns a dict with the dataset's fields plus two resolved keys:
|
|
53
|
+
``publication`` (a dict, or ``None`` if the record has no associated
|
|
54
|
+
publication) and ``platforms_detail`` (a list combining each
|
|
55
|
+
``platforms[].platform_id`` from the dataset with the matching row from
|
|
56
|
+
``list_platforms()``, keeping ``n_proteins_reported``).
|
|
57
|
+
"""
|
|
58
|
+
ds = list_datasets(ref=ref)
|
|
59
|
+
match = ds[ds["atlas_id"] == atlas_id]
|
|
60
|
+
if match.empty:
|
|
61
|
+
raise ValueError(f"No dataset found with atlas_id: {atlas_id}")
|
|
62
|
+
record = match.iloc[0].to_dict()
|
|
63
|
+
|
|
64
|
+
pub_id = record.get("publication_id")
|
|
65
|
+
if pub_id:
|
|
66
|
+
pubs = list_publications(ref=ref)
|
|
67
|
+
pub_match = pubs[pubs["publication_id"] == pub_id]
|
|
68
|
+
record["publication"] = pub_match.iloc[0].to_dict() if not pub_match.empty else None
|
|
69
|
+
else:
|
|
70
|
+
record["publication"] = None
|
|
71
|
+
|
|
72
|
+
platforms = record.get("platforms") or []
|
|
73
|
+
detail = []
|
|
74
|
+
if platforms:
|
|
75
|
+
all_platforms = list_platforms(ref=ref)
|
|
76
|
+
for p in platforms:
|
|
77
|
+
merged = dict(p)
|
|
78
|
+
prow = all_platforms[all_platforms["platform_id"] == p["platform_id"]]
|
|
79
|
+
if not prow.empty:
|
|
80
|
+
merged.update({k: v for k, v in prow.iloc[0].to_dict().items() if k != "platform_id"})
|
|
81
|
+
detail.append(merged)
|
|
82
|
+
record["platforms_detail"] = detail
|
|
83
|
+
|
|
84
|
+
return record
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Download a dataset's data file."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import warnings
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from urllib.parse import urlsplit
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from .datasets import get_dataset
|
|
11
|
+
|
|
12
|
+
_USER_AGENT = "aabatlas-python/0.1 (+https://github.com/ahcm088/antibodyome-atlas)"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def download(atlas_id: str, destdir: str = ".", destfile: str | None = None, ref: str = "main") -> Path:
|
|
16
|
+
"""Download whatever is at the record's ``dataset_link``.
|
|
17
|
+
|
|
18
|
+
For records with ``record_type == "DATASET"`` this is usually a
|
|
19
|
+
repository landing page (e.g. a GEO accession page) rather than a
|
|
20
|
+
direct file: check ``curated_availability`` first, and note that some
|
|
21
|
+
repositories require navigating from that page to the actual
|
|
22
|
+
supplementary files by hand.
|
|
23
|
+
|
|
24
|
+
Returns the local file path.
|
|
25
|
+
"""
|
|
26
|
+
record = get_dataset(atlas_id, ref=ref)
|
|
27
|
+
|
|
28
|
+
status = (record.get("curated_availability") or {}).get("data_status")
|
|
29
|
+
if status in ("unavailable", "upon_request"):
|
|
30
|
+
warnings.warn(
|
|
31
|
+
f"curated_availability.data_status for {atlas_id} is {status!r} -- "
|
|
32
|
+
"the data itself may not be directly downloadable. Proceeding to fetch dataset_link anyway."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
url = record["dataset_link"]
|
|
36
|
+
if destfile is None:
|
|
37
|
+
destfile = Path(urlsplit(url).path).name or f"{atlas_id}.html"
|
|
38
|
+
|
|
39
|
+
path = Path(destdir) / destfile
|
|
40
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
|
|
42
|
+
resp = requests.get(url, timeout=60, headers={"User-Agent": _USER_AGENT}, stream=True)
|
|
43
|
+
resp.raise_for_status()
|
|
44
|
+
with open(path, "wb") as f:
|
|
45
|
+
for chunk in resp.iter_content(chunk_size=8192):
|
|
46
|
+
f.write(chunk)
|
|
47
|
+
|
|
48
|
+
return path
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
from aabatlas._source import raw_url
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def atlas_or_skip():
|
|
9
|
+
try:
|
|
10
|
+
resp = requests.get(raw_url("datasets"), timeout=10)
|
|
11
|
+
ok = resp.status_code == 200
|
|
12
|
+
except requests.RequestException:
|
|
13
|
+
ok = False
|
|
14
|
+
if not ok:
|
|
15
|
+
pytest.skip("metadata/datasets.json not reachable at ref 'main' (repo not pushed yet, or offline)")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import aabatlas
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_raw_url_builds_the_expected_url():
|
|
7
|
+
assert aabatlas.raw_url("datasets", ref="v1.0.0") == (
|
|
8
|
+
"https://raw.githubusercontent.com/ahcm088/antibodyome-atlas/v1.0.0/metadata/datasets.json"
|
|
9
|
+
)
|
|
10
|
+
with pytest.raises(ValueError):
|
|
11
|
+
aabatlas.raw_url("nope")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_list_datasets_returns_expected_columns(atlas_or_skip):
|
|
15
|
+
ds = aabatlas.list_datasets()
|
|
16
|
+
assert len(ds) > 0
|
|
17
|
+
for col in ("atlas_id", "record_type", "title", "dataset_link"):
|
|
18
|
+
assert col in ds.columns
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_get_dataset_resolves_publication_and_platforms(atlas_or_skip):
|
|
22
|
+
ds = aabatlas.list_datasets()
|
|
23
|
+
target = ds[ds["publication_id"].notna()]["atlas_id"].iloc[0]
|
|
24
|
+
record = aabatlas.get_dataset(target)
|
|
25
|
+
assert record["atlas_id"] == target
|
|
26
|
+
assert record["publication"] is not None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_get_dataset_raises_on_unknown_atlas_id(atlas_or_skip):
|
|
30
|
+
with pytest.raises(ValueError, match="No dataset found"):
|
|
31
|
+
aabatlas.get_dataset("AAB-999999")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_citation_returns_expected_keys(atlas_or_skip):
|
|
35
|
+
ds = aabatlas.list_datasets()
|
|
36
|
+
target = ds[ds["publication_id"].notna()]["atlas_id"].iloc[0]
|
|
37
|
+
cite = aabatlas.get_citation(target)
|
|
38
|
+
for key in ("atlas_id", "citation", "doi"):
|
|
39
|
+
assert key in cite
|