orfdata 0.8.0__tar.gz → 0.9.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.
- {orfdata-0.8.0/orfdata.egg-info → orfdata-0.9.0}/PKG-INFO +1 -1
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/measurements.md +18 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/pfizer-protein.md +5 -2
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/dataset.py +36 -5
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/dataset_cli.py +5 -1
- orfdata-0.9.0/orfdata/version.py +1 -0
- {orfdata-0.8.0 → orfdata-0.9.0/orfdata.egg-info}/PKG-INFO +1 -1
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata.egg-info/SOURCES.txt +1 -0
- orfdata-0.9.0/tests/test_selectors.py +130 -0
- orfdata-0.8.0/orfdata/version.py +0 -1
- {orfdata-0.8.0 → orfdata-0.9.0}/LICENSE +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/MANIFEST.in +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/README.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/deploy.sh +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/copy-yeast.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/design.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/pairing.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/reference.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/source-references.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/species.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/docs/storage.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/lint.sh +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/__init__.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/build.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/catalog.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/cli.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/datasets.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/orf-evidence/AUTHOR-LICENSE.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/orf-evidence/NOTICE.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/orf-evidence/catalog.json.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/orf-evidence/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/uorf-evidence/AUTHOR-LICENSE.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/uorf-evidence/NOTICE.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/uorf-evidence/catalog.json.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/data/uorf-evidence/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/datasets.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/initiation_context.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/measurements.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/model.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/pairing.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/reference.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/reference_mapping.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/sequence.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/sources/__init__.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/sources/copy.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata/sources/pfizer.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata.egg-info/dependency_links.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata.egg-info/entry_points.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata.egg-info/requires.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/orfdata.egg-info/top_level.txt +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/pyproject.toml +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/setup.cfg +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/test.sh +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/conftest.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905474.soft +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905474_KL9_fpkm.txt.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905476.soft +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905476_KL10_fpkm.txt.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905478.soft +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905478_KL11_fpkm.txt.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905479.soft +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/GSM1905479_KL12_fpkm.txt.gz +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/NOTICE.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/expected.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/geo-series.soft +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/methods.pdf +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/paper.xml +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/pmc-metadata.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/qconcat.fasta +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/copy/workbook.xlsx +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/NOTICE.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/dog/expected.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/dog/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/dog/protein.tsv +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/dog/search.fasta +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/human/expected.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/human/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/human/protein.tsv +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/human/search.fasta +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/mouse/expected.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/mouse/manifest.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/mouse/protein.tsv +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/pfizer/mouse/search.fasta +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/README.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/canis_lupus_familiaris.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/context-keys-v0.4.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/homo_sapiens.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/mus_musculus.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/references/saccharomyces_cerevisiae.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/README.md +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/generate.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v1.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v1.sqlite +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v2.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v2.sqlite +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v3.json +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/data/storage/v3.sqlite +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_copy.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_cross_reference_pairing.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_initiation_context.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_measurements.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_pairing.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_pfizer.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_reference_context.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_reference_mapping.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_reference_orf.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_storage.py +0 -0
- {orfdata-0.8.0 → orfdata-0.9.0}/tests/test_uorf_catalog.py +0 -0
|
@@ -51,6 +51,24 @@ For native sources with unreported genomic metadata, use explicit
|
|
|
51
51
|
[source references and mapping views](source-references.md) to retain the original
|
|
52
52
|
observation alongside its mapping to a PyEnsembl target.
|
|
53
53
|
|
|
54
|
+
Choose a native series explicitly when a source supplies several units:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
values = dataset.measurements(quantity="protein_abundance", unit="iBAQ", scale="linear")
|
|
58
|
+
dataset.export_parquet("ibaq.parquet", unit="iBAQ", scale="linear")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`unit`, `scale` and `log_base` also work with `mapped_measurements` and existing
|
|
62
|
+
storage v1-v4 releases. Units are exact and case-sensitive. Selecting
|
|
63
|
+
`scale="log", log_base=2` returns values already on that scale; nothing is transformed.
|
|
64
|
+
An unavailable series returns no observations. Contradictory linear/log requests
|
|
65
|
+
raise an error. Omitting selectors preserves all native series.
|
|
66
|
+
|
|
67
|
+
For example, Pfizer iBAQ and rIBAQ are two series from the same source rows.
|
|
68
|
+
Selecting or exporting both does not create additional donors, spectra or
|
|
69
|
+
independent detections. Source row/sample/assay lineage stays attached to each
|
|
70
|
+
measurement.
|
|
71
|
+
|
|
54
72
|
The CLI uses the same operations:
|
|
55
73
|
|
|
56
74
|
```sh
|
|
@@ -20,7 +20,7 @@ include sex. Channels and technical runs do not count as independent donors.
|
|
|
20
20
|
pip install 'orfdata[data]'
|
|
21
21
|
orfdata datasets list --species dog
|
|
22
22
|
orfdata datasets download pfizer-atlas-dog-protein
|
|
23
|
-
orfdata datasets query pfizer-atlas-dog-protein --quantity protein_abundance
|
|
23
|
+
orfdata datasets query pfizer-atlas-dog-protein --quantity protein_abundance --unit iBAQ --scale linear
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
```python
|
|
@@ -30,10 +30,13 @@ registry = DatasetRegistry()
|
|
|
30
30
|
dataset = registry.open("pfizer-atlas-dog-protein") # After explicit download.
|
|
31
31
|
reference, = dataset.manifest.references
|
|
32
32
|
group = ScopedTarget(reference, "protein_group", "A0A0A0MPB0", "MSV000099744:ProteinGroup")
|
|
33
|
-
for value in dataset.measurements(target=group):
|
|
33
|
+
for value in dataset.measurements(target=group, unit="iBAQ", scale="linear"):
|
|
34
34
|
print(value.sample_id, value.unit, value.value, value.status)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
Omit the unit selector to return both native series. They retain the same source
|
|
38
|
+
row and sample identity; two units do not imply two independent measurements.
|
|
39
|
+
|
|
37
40
|
Every target retains its species and the checksum of the deposited UniProt
|
|
38
41
|
search FASTA. The original genomic assembly and UniProt release are unknown.
|
|
39
42
|
They stay unknown; a future annotation mapping must be explicit and validated.
|
|
@@ -18,6 +18,8 @@ from .measurements import (
|
|
|
18
18
|
MeasurementReference,
|
|
19
19
|
Sample,
|
|
20
20
|
TargetMapping,
|
|
21
|
+
_identifier,
|
|
22
|
+
_number,
|
|
21
23
|
_plain,
|
|
22
24
|
)
|
|
23
25
|
from .pairing import (
|
|
@@ -138,6 +140,19 @@ def _measurement_record(observation):
|
|
|
138
140
|
return result
|
|
139
141
|
|
|
140
142
|
|
|
143
|
+
def _validate_native_selectors(unit=None, scale=None, log_base=None):
|
|
144
|
+
if unit is not None:
|
|
145
|
+
_identifier(unit, "measurement unit selector")
|
|
146
|
+
if scale is not None and scale not in ("linear", "log"):
|
|
147
|
+
raise ValueError("Measurement scale selector must be linear or log")
|
|
148
|
+
if log_base is not None:
|
|
149
|
+
_number(log_base, "logarithm base selector")
|
|
150
|
+
if log_base <= 0 or log_base == 1:
|
|
151
|
+
raise ValueError("Logarithm base selector must be positive and not one")
|
|
152
|
+
if scale == "linear":
|
|
153
|
+
raise ValueError("A linear scale selector cannot have a logarithm base")
|
|
154
|
+
|
|
155
|
+
|
|
141
156
|
class QuantitativeDataset:
|
|
142
157
|
"""A read-only release. Constructing or querying it never downloads data.
|
|
143
158
|
|
|
@@ -405,8 +420,9 @@ class QuantitativeDataset:
|
|
|
405
420
|
raise ValueError("Choose explicit usable mapping statuses")
|
|
406
421
|
if type(require_sequence) is not bool:
|
|
407
422
|
raise TypeError("require_sequence must be a boolean")
|
|
408
|
-
if set(observation_filters) - {"sample_id", "assay_id", "quantity", "status"}:
|
|
423
|
+
if set(observation_filters) - {"sample_id", "assay_id", "quantity", "status", "unit", "scale", "log_base"}:
|
|
409
424
|
raise ValueError("Mapped observation filters cannot override source/target reference identity")
|
|
425
|
+
_validate_native_selectors(**{name: observation_filters.get(name) for name in ("unit", "scale", "log_base")})
|
|
410
426
|
for mapping in self.reference_mappings(target=target):
|
|
411
427
|
if mapping.status not in allowed or (require_sequence and not mapping.sequence_validated):
|
|
412
428
|
continue
|
|
@@ -468,16 +484,19 @@ class QuantitativeDataset:
|
|
|
468
484
|
tuple(by_target[1].get(relation.right.key, ())))
|
|
469
485
|
|
|
470
486
|
def measurements(self, *, target=None, reference=None, sample_id=None,
|
|
471
|
-
assay_id=None, quantity=None, status=None
|
|
487
|
+
assay_id=None, quantity=None, status=None, unit=None, scale=None,
|
|
488
|
+
log_base=None):
|
|
472
489
|
"""Iterate native observations; a target match is exact, never orthology.
|
|
473
490
|
|
|
474
491
|
Unqualified IDs across multiple references are rejected. To browse all
|
|
475
492
|
species together, omit ID filters; each result still carries its scope.
|
|
493
|
+
Native unit/scale/base selectors are exact; no conversion or aggregation.
|
|
476
494
|
"""
|
|
477
495
|
if quantity is not None and quantity not in QUANTITIES:
|
|
478
496
|
raise ValueError("Unknown measurement quantity")
|
|
479
497
|
if status is not None and status not in MEASUREMENT_STATUSES:
|
|
480
498
|
raise ValueError("Unknown measurement status")
|
|
499
|
+
_validate_native_selectors(unit, scale, log_base)
|
|
481
500
|
scope = self._scope(reference)
|
|
482
501
|
if target is not None:
|
|
483
502
|
if not isinstance(target, ScopedTarget):
|
|
@@ -495,11 +514,23 @@ class QuantitativeDataset:
|
|
|
495
514
|
"m.id, m.sample_id, m.assay_id, m.quantity, m.status "
|
|
496
515
|
"FROM measurement m JOIN target t ON m.reference_key=t.reference_key "
|
|
497
516
|
"AND m.target_key=t.key")
|
|
498
|
-
|
|
499
|
-
|
|
517
|
+
conditions = [f"m.{key}=?" for key, _ in selected]
|
|
518
|
+
parameters = [value for _, value in selected]
|
|
519
|
+
# JSON extraction applies to original v1-v3 records and compact v4
|
|
520
|
+
# residual records. SQLite filters before Python reconstructs objects.
|
|
521
|
+
for value, expression in (
|
|
522
|
+
(unit, "json_extract(m.record, '$.unit')"),
|
|
523
|
+
(scale, "coalesce(json_extract(m.record, '$.scale'), 'linear')"),
|
|
524
|
+
(log_base, "json_extract(m.record, '$.log_base')"),
|
|
525
|
+
):
|
|
526
|
+
if value is not None:
|
|
527
|
+
conditions.append(expression + "=?")
|
|
528
|
+
parameters.append(value)
|
|
529
|
+
if conditions:
|
|
530
|
+
query += " WHERE " + " AND ".join(conditions)
|
|
500
531
|
query += " ORDER BY m.reference_key, m.id"
|
|
501
532
|
with closing(self._connect()) as connection:
|
|
502
|
-
for row in connection.execute(query,
|
|
533
|
+
for row in connection.execute(query, parameters):
|
|
503
534
|
values = json.loads(row[0])
|
|
504
535
|
if self._storage_version == 4:
|
|
505
536
|
values = dict(_V4_DEFAULTS, **values)
|
|
@@ -39,6 +39,9 @@ def run(argv=None, prog=None):
|
|
|
39
39
|
subparser.add_argument("--assay-id")
|
|
40
40
|
subparser.add_argument("--quantity")
|
|
41
41
|
subparser.add_argument("--status")
|
|
42
|
+
subparser.add_argument("--unit", help="Exact native unit, e.g. iBAQ, rIBAQ, TPM or counts")
|
|
43
|
+
subparser.add_argument("--scale", choices=("linear", "log"))
|
|
44
|
+
subparser.add_argument("--log-base", type=float, help="Exact native logarithm base; no transformation")
|
|
42
45
|
subparser.add_argument("--target")
|
|
43
46
|
subparser.add_argument("--kind")
|
|
44
47
|
subparser.add_argument("--namespace")
|
|
@@ -111,7 +114,8 @@ def run(argv=None, prog=None):
|
|
|
111
114
|
references = {r.key: r for r in dataset.manifest.references}
|
|
112
115
|
target = ScopedTarget(references[args.reference], args.kind, args.target, args.namespace)
|
|
113
116
|
filters = dict(sample_id=args.sample, assay_id=args.assay_id,
|
|
114
|
-
quantity=args.quantity, status=args.status
|
|
117
|
+
quantity=args.quantity, status=args.status,
|
|
118
|
+
unit=args.unit, scale=args.scale, log_base=args.log_base)
|
|
115
119
|
if args.mapped:
|
|
116
120
|
if target is None:
|
|
117
121
|
parser.error("--mapped requires an exact target and reference")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.0"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Native series selection preserves values, lineage and target resolution."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import replace
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from orfdata import DatasetManifest, DatasetRegistry, Measurement, QuantitativeDataset
|
|
10
|
+
from orfdata.cli import run
|
|
11
|
+
from orfdata.sources.pfizer import import_protein
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(params=("human", "mouse", "dog"))
|
|
15
|
+
def native(request, tmp_path):
|
|
16
|
+
root = Path(__file__).parent / "data/pfizer" / request.param
|
|
17
|
+
manifest = DatasetManifest.from_dict(json.loads((root / "manifest.json").read_text()))
|
|
18
|
+
return import_protein({a.asset_id: root / a.asset_id for a in manifest.sources}, tmp_path / "native.sqlite", manifest)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_native_unit_values_and_source_identity(native):
|
|
22
|
+
original = list(native.measurements(quantity="protein_abundance"))
|
|
23
|
+
assert len(original) == 10
|
|
24
|
+
selected = {}
|
|
25
|
+
for unit in ("iBAQ", "rIBAQ"):
|
|
26
|
+
values = list(native.measurements(quantity="protein_abundance", unit=unit, scale="linear"))
|
|
27
|
+
assert len(values) == 5 and values == [m for m in original if m.unit == unit]
|
|
28
|
+
assert any(m.value == 0 and m.status == "measured" for m in values)
|
|
29
|
+
assert any(m.value is None and m.status == "missing" for m in values)
|
|
30
|
+
selected[unit] = {(m.sample_id, m.assay_id, m.provenance["line"]) for m in values}
|
|
31
|
+
assert selected["iBAQ"] == selected["rIBAQ"] # Same five source rows, two series.
|
|
32
|
+
for unit in ("copies/cell", "ibaq", "iBAQ' OR 1=1 --"):
|
|
33
|
+
assert list(native.measurements(unit=unit)) == []
|
|
34
|
+
assert list(native.measurements(unit="iBAQ", scale="log")) == []
|
|
35
|
+
mapping = next(m for m in native.reference_mappings() if m.targets)
|
|
36
|
+
target = mapping.targets[0]
|
|
37
|
+
assert list(native.mapped_measurements(target, unit="iBAQ")) == []
|
|
38
|
+
views = list(native.mapped_measurements(target, mapping_statuses=["unresolved"], unit="iBAQ", scale="linear"))
|
|
39
|
+
assert views and all(v.measurement.unit == "iBAQ" and v.attribution == "group_membership_context" for v in views)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_cli_native_and_mapped(native, tmp_path, capsys):
|
|
43
|
+
from test_measurements import definition
|
|
44
|
+
|
|
45
|
+
definitions = definition(native)
|
|
46
|
+
path = tmp_path / "registry.json"
|
|
47
|
+
path.write_text(json.dumps(definitions))
|
|
48
|
+
cache = tmp_path / "cache"
|
|
49
|
+
DatasetRegistry(definitions, cache_root=cache).download(native.manifest.dataset_id, show_progress=False)
|
|
50
|
+
prefix = ["datasets", "--registry", str(path), "--cache-root", str(cache), "query", native.manifest.dataset_id]
|
|
51
|
+
run(prefix + ["--unit", "iBAQ", "--scale", "linear"])
|
|
52
|
+
rows = [json.loads(line) for line in capsys.readouterr().out.splitlines()]
|
|
53
|
+
assert len(rows) == 5 and all(r["unit"] == "iBAQ" for r in rows)
|
|
54
|
+
target = next(m.targets[0] for m in native.reference_mappings() if m.targets)
|
|
55
|
+
run(prefix + ["--mapped", "--mapping-status", "unresolved", "--reference", target.reference.key,
|
|
56
|
+
"--target", target.identifier, "--kind", target.kind, "--namespace", target.namespace,
|
|
57
|
+
"--unit", "rIBAQ", "--scale", "linear"])
|
|
58
|
+
rows = [json.loads(line) for line in capsys.readouterr().out.splitlines()]
|
|
59
|
+
assert rows and all(r["measurement"]["unit"] == "rIBAQ" for r in rows)
|
|
60
|
+
run(prefix + ["--unit", "copies/cell"])
|
|
61
|
+
assert capsys.readouterr().out == ""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_parquet_uses_the_same_selection(native, tmp_path):
|
|
65
|
+
parquet = pytest.importorskip("pyarrow.parquet")
|
|
66
|
+
output = tmp_path / "selected.parquet"
|
|
67
|
+
native.export_parquet(output, unit="iBAQ", scale="linear")
|
|
68
|
+
rows = parquet.read_table(output).to_pylist()
|
|
69
|
+
assert len(rows) == 5 and all(r["unit"] == "iBAQ" for r in rows)
|
|
70
|
+
assert [Measurement.from_dict(json.loads(r["measurement_json"])) for r in rows] == list(native.measurements(unit="iBAQ"))
|
|
71
|
+
native.export_parquet(output, unit="unavailable")
|
|
72
|
+
assert parquet.read_table(output).num_rows == 0
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@pytest.mark.parametrize("version", (1, 2, 3))
|
|
76
|
+
def test_legacy_exact_series_filters(version):
|
|
77
|
+
dataset = QuantitativeDataset(Path(__file__).parent / f"data/storage/v{version}.sqlite")
|
|
78
|
+
original = list(dataset.measurements())
|
|
79
|
+
for unit in ("TPM", "iBAQ", "fixture-units"):
|
|
80
|
+
assert list(dataset.measurements(unit=unit, scale="linear")) == [m for m in original if m.unit == unit]
|
|
81
|
+
assert list(dataset.measurements(scale="log")) == []
|
|
82
|
+
assert list(dataset.measurements(log_base=2)) == []
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@pytest.fixture
|
|
86
|
+
def transformed(experiment, tmp_path):
|
|
87
|
+
manifest, samples, assays, values = experiment
|
|
88
|
+
value = values[0]
|
|
89
|
+
observations = [replace(value, measurement_id="linear", value=0),
|
|
90
|
+
replace(value, measurement_id="log2", value=-2, scale="log", log_base=2),
|
|
91
|
+
replace(value, measurement_id="log10", value=-1, scale="log", log_base=10)]
|
|
92
|
+
return QuantitativeDataset.create(tmp_path / "log.sqlite", manifest, samples=samples, assays=assays, measurements=observations)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_log_base_selection_never_transforms(transformed):
|
|
96
|
+
assert [m.value for m in transformed.measurements(unit="TPM", scale="linear")] == [0]
|
|
97
|
+
assert {m.value for m in transformed.measurements(scale="log")} == {-1, -2}
|
|
98
|
+
assert [m.value for m in transformed.measurements(unit="TPM", log_base=2)] == [-2]
|
|
99
|
+
assert [m.value for m in transformed.measurements(scale="log", log_base=10)] == [-1]
|
|
100
|
+
assert list(transformed.measurements(log_base=3)) == []
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_cli_log_base_and_contradictory_selection(transformed, tmp_path, capsys):
|
|
104
|
+
from test_measurements import definition
|
|
105
|
+
|
|
106
|
+
definitions = definition(transformed)
|
|
107
|
+
path = tmp_path / "registry.json"
|
|
108
|
+
path.write_text(json.dumps(definitions))
|
|
109
|
+
cache = tmp_path / "cache"
|
|
110
|
+
DatasetRegistry(definitions, cache_root=cache).download("fixture", show_progress=False)
|
|
111
|
+
prefix = ["datasets", "--registry", str(path), "--cache-root", str(cache), "query", "fixture"]
|
|
112
|
+
run(prefix + ["--unit", "TPM", "--scale", "log", "--log-base", "2"])
|
|
113
|
+
rows = [json.loads(line) for line in capsys.readouterr().out.splitlines()]
|
|
114
|
+
assert len(rows) == 1 and rows[0]["value"] == -2 and rows[0]["log_base"] == 2
|
|
115
|
+
with pytest.raises(SystemExit):
|
|
116
|
+
run(prefix + ["--scale", "linear", "--log-base", "2"])
|
|
117
|
+
assert "cannot have a logarithm base" in capsys.readouterr().err
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.mark.parametrize("filters", [
|
|
121
|
+
{"unit": ""}, {"unit": " "}, {"unit": 1}, {"scale": "log2"}, {"log_base": 0},
|
|
122
|
+
{"log_base": 1}, {"log_base": -2}, {"log_base": True}, {"log_base": float("inf")},
|
|
123
|
+
{"log_base": float("nan")}, {"scale": "linear", "log_base": 2},
|
|
124
|
+
])
|
|
125
|
+
def test_invalid_selectors(transformed, filters):
|
|
126
|
+
with pytest.raises((ValueError, TypeError)):
|
|
127
|
+
list(transformed.measurements(**filters))
|
|
128
|
+
target = next(transformed.measurements()).target
|
|
129
|
+
with pytest.raises((ValueError, TypeError)):
|
|
130
|
+
list(transformed.mapped_measurements(target, **filters))
|
orfdata-0.8.0/orfdata/version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.8.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|