encode-toolkit 0.3.0b1__py3-none-any.whl
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.
- encode_connector/__init__.py +4 -0
- encode_connector/__main__.py +5 -0
- encode_connector/client/__init__.py +6 -0
- encode_connector/client/auth.py +262 -0
- encode_connector/client/constants.py +348 -0
- encode_connector/client/downloader.py +305 -0
- encode_connector/client/encode_client.py +585 -0
- encode_connector/client/models.py +332 -0
- encode_connector/client/tracker.py +1129 -0
- encode_connector/client/validation.py +188 -0
- encode_connector/server/__init__.py +1 -0
- encode_connector/server/__main__.py +5 -0
- encode_connector/server/main.py +1495 -0
- encode_toolkit-0.3.0b1.dist-info/METADATA +810 -0
- encode_toolkit-0.3.0b1.dist-info/RECORD +18 -0
- encode_toolkit-0.3.0b1.dist-info/WHEEL +4 -0
- encode_toolkit-0.3.0b1.dist-info/entry_points.txt +2 -0
- encode_toolkit-0.3.0b1.dist-info/licenses/LICENSE +144 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""Secure credential management for ENCODE API authentication.
|
|
2
|
+
|
|
3
|
+
Credentials are stored in the OS keyring (macOS Keychain, Linux Secret Service,
|
|
4
|
+
Windows Credential Locker). Falls back to Fernet-encrypted file storage when
|
|
5
|
+
keyring is unavailable.
|
|
6
|
+
|
|
7
|
+
Credentials never appear in logs, error messages, or are sent anywhere
|
|
8
|
+
except the ENCODE API over HTTPS.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import base64
|
|
14
|
+
import hashlib
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _get_machine_key(salt_path: Path | None = None) -> bytes:
|
|
24
|
+
"""Derive a machine-specific encryption key for fallback file storage.
|
|
25
|
+
|
|
26
|
+
Uses PBKDF2 with a random salt stored alongside the credentials file.
|
|
27
|
+
The salt is generated once and reused for subsequent key derivations.
|
|
28
|
+
"""
|
|
29
|
+
if salt_path is None:
|
|
30
|
+
salt_path = Path.home() / ".encode_connector" / ".salt"
|
|
31
|
+
|
|
32
|
+
# Generate or read the salt
|
|
33
|
+
if salt_path.exists():
|
|
34
|
+
salt = salt_path.read_bytes()
|
|
35
|
+
else:
|
|
36
|
+
salt_path.parent.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
salt = os.urandom(32)
|
|
38
|
+
salt_path.write_bytes(salt)
|
|
39
|
+
salt_path.chmod(0o600)
|
|
40
|
+
|
|
41
|
+
# Combine machine-specific values as key material
|
|
42
|
+
import getpass
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
login = getpass.getuser()
|
|
46
|
+
except (KeyError, OSError):
|
|
47
|
+
# getpass.getuser() raises KeyError in containers/CI where the user
|
|
48
|
+
# is not in the password database, or OSError in restricted environments
|
|
49
|
+
login = os.environ.get("USER", os.environ.get("USERNAME", "encode-user"))
|
|
50
|
+
material = f"{platform.node()}-{login}-encode-connector"
|
|
51
|
+
|
|
52
|
+
# Use PBKDF2 with 600,000 iterations (OWASP recommendation)
|
|
53
|
+
dk = hashlib.pbkdf2_hmac("sha256", material.encode(), salt, 600_000, dklen=32)
|
|
54
|
+
return base64.urlsafe_b64encode(dk)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class CredentialManager:
|
|
58
|
+
"""Manages ENCODE API credentials with secure storage.
|
|
59
|
+
|
|
60
|
+
Storage priority:
|
|
61
|
+
1. OS keyring (macOS Keychain, Linux Secret Service, Windows Credential Locker)
|
|
62
|
+
2. Fernet-encrypted file at ~/.encode_connector/credentials.enc
|
|
63
|
+
3. Environment variables (read-only, for initial setup)
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
SERVICE_NAME = "encode-connector"
|
|
67
|
+
_fallback_dir = Path.home() / ".encode_connector"
|
|
68
|
+
_fallback_file = _fallback_dir / "credentials.enc"
|
|
69
|
+
|
|
70
|
+
def __init__(self) -> None:
|
|
71
|
+
self._access_key: str | None = None
|
|
72
|
+
self._secret_key: str | None = None
|
|
73
|
+
self._keyring_available: bool | None = None
|
|
74
|
+
|
|
75
|
+
def _check_keyring(self) -> bool:
|
|
76
|
+
"""Check if OS keyring is available."""
|
|
77
|
+
if self._keyring_available is not None:
|
|
78
|
+
return self._keyring_available
|
|
79
|
+
try:
|
|
80
|
+
import keyring
|
|
81
|
+
from keyring.errors import NoKeyringError
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
# Test keyring access
|
|
85
|
+
keyring.get_password(self.SERVICE_NAME, "__test__")
|
|
86
|
+
self._keyring_available = True
|
|
87
|
+
except NoKeyringError:
|
|
88
|
+
self._keyring_available = False
|
|
89
|
+
except Exception:
|
|
90
|
+
self._keyring_available = False
|
|
91
|
+
except ImportError:
|
|
92
|
+
self._keyring_available = False
|
|
93
|
+
|
|
94
|
+
return self._keyring_available
|
|
95
|
+
|
|
96
|
+
def _read_from_keyring(self) -> tuple[str | None, str | None]:
|
|
97
|
+
"""Read credentials from OS keyring."""
|
|
98
|
+
if not self._check_keyring():
|
|
99
|
+
return None, None
|
|
100
|
+
try:
|
|
101
|
+
import keyring
|
|
102
|
+
|
|
103
|
+
access_key = keyring.get_password(self.SERVICE_NAME, "access_key")
|
|
104
|
+
secret_key = keyring.get_password(self.SERVICE_NAME, "secret_key")
|
|
105
|
+
return access_key, secret_key
|
|
106
|
+
except Exception:
|
|
107
|
+
return None, None
|
|
108
|
+
|
|
109
|
+
def _write_to_keyring(self, access_key: str, secret_key: str) -> bool:
|
|
110
|
+
"""Store credentials in OS keyring. Returns True on success."""
|
|
111
|
+
if not self._check_keyring():
|
|
112
|
+
return False
|
|
113
|
+
try:
|
|
114
|
+
import keyring
|
|
115
|
+
|
|
116
|
+
keyring.set_password(self.SERVICE_NAME, "access_key", access_key)
|
|
117
|
+
keyring.set_password(self.SERVICE_NAME, "secret_key", secret_key)
|
|
118
|
+
logger.info("Credentials stored in OS keyring")
|
|
119
|
+
return True
|
|
120
|
+
except Exception as e:
|
|
121
|
+
logger.warning("Failed to store credentials in keyring: %s", type(e).__name__)
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
def _read_from_encrypted_file(self) -> tuple[str | None, str | None]:
|
|
125
|
+
"""Read credentials from Fernet-encrypted file."""
|
|
126
|
+
if not self._fallback_file.exists():
|
|
127
|
+
return None, None
|
|
128
|
+
try:
|
|
129
|
+
from cryptography.fernet import Fernet
|
|
130
|
+
|
|
131
|
+
key = _get_machine_key()
|
|
132
|
+
f = Fernet(key)
|
|
133
|
+
data = f.decrypt(self._fallback_file.read_bytes()).decode()
|
|
134
|
+
parts = data.split("\n", 1)
|
|
135
|
+
if len(parts) == 2:
|
|
136
|
+
return parts[0], parts[1]
|
|
137
|
+
except Exception:
|
|
138
|
+
logger.warning("Failed to decrypt credential file")
|
|
139
|
+
return None, None
|
|
140
|
+
|
|
141
|
+
def _write_to_encrypted_file(self, access_key: str, secret_key: str) -> bool:
|
|
142
|
+
"""Store credentials in Fernet-encrypted file."""
|
|
143
|
+
try:
|
|
144
|
+
from cryptography.fernet import Fernet
|
|
145
|
+
|
|
146
|
+
self._fallback_dir.mkdir(parents=True, exist_ok=True)
|
|
147
|
+
# Restrict directory permissions
|
|
148
|
+
self._fallback_dir.chmod(0o700)
|
|
149
|
+
|
|
150
|
+
key = _get_machine_key()
|
|
151
|
+
f = Fernet(key)
|
|
152
|
+
data = f"{access_key}\n{secret_key}"
|
|
153
|
+
encrypted = f.encrypt(data.encode())
|
|
154
|
+
self._fallback_file.write_bytes(encrypted)
|
|
155
|
+
# Restrict file permissions
|
|
156
|
+
self._fallback_file.chmod(0o600)
|
|
157
|
+
logger.info("Credentials stored in encrypted file")
|
|
158
|
+
return True
|
|
159
|
+
except Exception as e:
|
|
160
|
+
logger.warning("Failed to write encrypted credential file: %s", type(e).__name__)
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
def _read_from_env(self) -> tuple[str | None, str | None]:
|
|
164
|
+
"""Read credentials from environment variables."""
|
|
165
|
+
access_key = os.environ.get("ENCODE_ACCESS_KEY")
|
|
166
|
+
secret_key = os.environ.get("ENCODE_SECRET_KEY")
|
|
167
|
+
if access_key and secret_key:
|
|
168
|
+
return access_key, secret_key
|
|
169
|
+
return None, None
|
|
170
|
+
|
|
171
|
+
def get_credentials(self) -> tuple[str | None, str | None]:
|
|
172
|
+
"""Get ENCODE API credentials from the most secure available source.
|
|
173
|
+
|
|
174
|
+
Checks in order: cache -> keyring -> encrypted file -> env vars.
|
|
175
|
+
If found in env vars, migrates to keyring/encrypted file for future use.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Tuple of (access_key, secret_key), both None if no credentials found.
|
|
179
|
+
"""
|
|
180
|
+
# Check cache first
|
|
181
|
+
if self._access_key and self._secret_key:
|
|
182
|
+
return self._access_key, self._secret_key
|
|
183
|
+
|
|
184
|
+
# Try keyring
|
|
185
|
+
access_key, secret_key = self._read_from_keyring()
|
|
186
|
+
if access_key and secret_key:
|
|
187
|
+
self._access_key = access_key
|
|
188
|
+
self._secret_key = secret_key
|
|
189
|
+
return access_key, secret_key
|
|
190
|
+
|
|
191
|
+
# Try encrypted file
|
|
192
|
+
access_key, secret_key = self._read_from_encrypted_file()
|
|
193
|
+
if access_key and secret_key:
|
|
194
|
+
self._access_key = access_key
|
|
195
|
+
self._secret_key = secret_key
|
|
196
|
+
return access_key, secret_key
|
|
197
|
+
|
|
198
|
+
# Try env vars (and migrate to secure storage)
|
|
199
|
+
access_key, secret_key = self._read_from_env()
|
|
200
|
+
if access_key and secret_key:
|
|
201
|
+
self._access_key = access_key
|
|
202
|
+
self._secret_key = secret_key
|
|
203
|
+
# Migrate to secure storage
|
|
204
|
+
self.store_credentials(access_key, secret_key)
|
|
205
|
+
return access_key, secret_key
|
|
206
|
+
|
|
207
|
+
return None, None
|
|
208
|
+
|
|
209
|
+
def store_credentials(self, access_key: str, secret_key: str) -> str:
|
|
210
|
+
"""Store credentials in the most secure available storage.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Description of where credentials were stored.
|
|
214
|
+
"""
|
|
215
|
+
self._access_key = access_key
|
|
216
|
+
self._secret_key = secret_key
|
|
217
|
+
|
|
218
|
+
if self._write_to_keyring(access_key, secret_key):
|
|
219
|
+
return "OS keyring (macOS Keychain / Linux Secret Service / Windows Credential Locker)"
|
|
220
|
+
|
|
221
|
+
if self._write_to_encrypted_file(access_key, secret_key):
|
|
222
|
+
return f"Encrypted file ({self._fallback_file})"
|
|
223
|
+
|
|
224
|
+
return "Memory only (credentials will not persist across sessions)"
|
|
225
|
+
|
|
226
|
+
def clear_credentials(self) -> None:
|
|
227
|
+
"""Remove all stored credentials."""
|
|
228
|
+
self._access_key = None
|
|
229
|
+
self._secret_key = None
|
|
230
|
+
|
|
231
|
+
# Clear keyring
|
|
232
|
+
if self._check_keyring():
|
|
233
|
+
try:
|
|
234
|
+
import keyring
|
|
235
|
+
|
|
236
|
+
keyring.delete_password(self.SERVICE_NAME, "access_key")
|
|
237
|
+
keyring.delete_password(self.SERVICE_NAME, "secret_key")
|
|
238
|
+
except Exception:
|
|
239
|
+
pass
|
|
240
|
+
|
|
241
|
+
# Clear encrypted file
|
|
242
|
+
if self._fallback_file.exists():
|
|
243
|
+
self._fallback_file.unlink()
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def has_credentials(self) -> bool:
|
|
247
|
+
"""Check if credentials are available without revealing them."""
|
|
248
|
+
access_key, secret_key = self.get_credentials()
|
|
249
|
+
return bool(access_key and secret_key)
|
|
250
|
+
|
|
251
|
+
def get_auth_header(self) -> dict[str, str] | None:
|
|
252
|
+
"""Get HTTP Basic auth header for ENCODE API.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
Dict with Authorization header, or None if no credentials.
|
|
256
|
+
"""
|
|
257
|
+
access_key, secret_key = self.get_credentials()
|
|
258
|
+
if not access_key or not secret_key:
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
token = base64.b64encode(f"{access_key}:{secret_key}".encode()).decode()
|
|
262
|
+
return {"Authorization": f"Basic {token}"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""ENCODE API constants, endpoints, and known filter values."""
|
|
2
|
+
|
|
3
|
+
BASE_URL = "https://www.encodeproject.org"
|
|
4
|
+
SEARCH_ENDPOINT = "/search/"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Rate limiting
|
|
8
|
+
MAX_REQUESTS_PER_SECOND = 10
|
|
9
|
+
DOWNLOAD_CONCURRENCY = 3
|
|
10
|
+
|
|
11
|
+
# Request defaults
|
|
12
|
+
DEFAULT_TIMEOUT = 30.0
|
|
13
|
+
DOWNLOAD_TIMEOUT = 300.0
|
|
14
|
+
DEFAULT_LIMIT = 25
|
|
15
|
+
try:
|
|
16
|
+
import importlib.metadata
|
|
17
|
+
|
|
18
|
+
_version = importlib.metadata.version("encode-toolkit")
|
|
19
|
+
except importlib.metadata.PackageNotFoundError:
|
|
20
|
+
_version = "0.3.0"
|
|
21
|
+
USER_AGENT = f"encode-toolkit/{_version} (MCP; +https://github.com/ammawla/encode-toolkit)"
|
|
22
|
+
|
|
23
|
+
# Keyring service name for credential storage
|
|
24
|
+
KEYRING_SERVICE = "encode-connector"
|
|
25
|
+
KEYRING_ACCESS_KEY = "access_key"
|
|
26
|
+
KEYRING_SECRET_KEY = "secret_key"
|
|
27
|
+
|
|
28
|
+
# -------------------------------------------------------------------
|
|
29
|
+
# Known ENCODE filter values (for metadata/autocomplete)
|
|
30
|
+
# -------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
ASSAY_TITLES = [
|
|
33
|
+
"Histone ChIP-seq",
|
|
34
|
+
"TF ChIP-seq",
|
|
35
|
+
"Control ChIP-seq",
|
|
36
|
+
"Mint-ChIP-seq",
|
|
37
|
+
"ATAC-seq",
|
|
38
|
+
"DNase-seq",
|
|
39
|
+
"RNA-seq",
|
|
40
|
+
"total RNA-seq",
|
|
41
|
+
"small RNA-seq",
|
|
42
|
+
"long read RNA-seq",
|
|
43
|
+
"microRNA-seq",
|
|
44
|
+
"polyA plus RNA-seq",
|
|
45
|
+
"polyA minus RNA-seq",
|
|
46
|
+
"single-cell RNA sequencing assay",
|
|
47
|
+
"CAGE",
|
|
48
|
+
"RAMPAGE",
|
|
49
|
+
"RRBS",
|
|
50
|
+
"WGBS",
|
|
51
|
+
"whole-genome shotgun bisulfite sequencing",
|
|
52
|
+
"Hi-C",
|
|
53
|
+
"intact Hi-C",
|
|
54
|
+
"in situ Hi-C",
|
|
55
|
+
"Micro-C",
|
|
56
|
+
"ChIA-PET",
|
|
57
|
+
"HiChIP",
|
|
58
|
+
"PLAC-seq",
|
|
59
|
+
"PRO-seq",
|
|
60
|
+
"GRO-seq",
|
|
61
|
+
"CUT&RUN",
|
|
62
|
+
"CUT&Tag",
|
|
63
|
+
"STARR-seq",
|
|
64
|
+
"MPRA",
|
|
65
|
+
"CRISPR screen",
|
|
66
|
+
"proliferation CRISPR screen",
|
|
67
|
+
"FlowFISH CRISPR screen",
|
|
68
|
+
"eCLIP",
|
|
69
|
+
"iCLIP",
|
|
70
|
+
"shRNA knockdown followed by RNA-seq",
|
|
71
|
+
"siRNA knockdown followed by RNA-seq",
|
|
72
|
+
"CRISPRi followed by RNA-seq",
|
|
73
|
+
"MeDIP-seq",
|
|
74
|
+
"MRE-seq",
|
|
75
|
+
"MNase-seq",
|
|
76
|
+
"5C",
|
|
77
|
+
"BruUV-seq",
|
|
78
|
+
"genetic modification followed by DNase-seq",
|
|
79
|
+
"long read sequencing assay",
|
|
80
|
+
"direct RNA-seq",
|
|
81
|
+
"Parse SPLiT-seq",
|
|
82
|
+
"SHARE-seq",
|
|
83
|
+
"10x multiome",
|
|
84
|
+
"single-nucleus ATAC-seq",
|
|
85
|
+
"single-nucleus RNA-seq",
|
|
86
|
+
"snATAC-seq",
|
|
87
|
+
"Repli-seq",
|
|
88
|
+
"Repli-chip",
|
|
89
|
+
"Switchgear",
|
|
90
|
+
"genotyping HTS",
|
|
91
|
+
"whole genome sequencing assay",
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
ORGANISMS = [
|
|
95
|
+
"Homo sapiens",
|
|
96
|
+
"Mus musculus",
|
|
97
|
+
"Drosophila melanogaster",
|
|
98
|
+
"Caenorhabditis elegans",
|
|
99
|
+
"Saccharomyces cerevisiae",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
BIOSAMPLE_CLASSIFICATIONS = [
|
|
103
|
+
"tissue",
|
|
104
|
+
"cell line",
|
|
105
|
+
"primary cell",
|
|
106
|
+
"in vitro differentiated cells",
|
|
107
|
+
"organoid",
|
|
108
|
+
"whole organisms",
|
|
109
|
+
"single cell",
|
|
110
|
+
"induced pluripotent stem cell line",
|
|
111
|
+
"stem cell",
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
ORGAN_SLIMS = [
|
|
115
|
+
"adrenal gland",
|
|
116
|
+
"arterial blood vessel",
|
|
117
|
+
"bone element",
|
|
118
|
+
"bone marrow",
|
|
119
|
+
"brain",
|
|
120
|
+
"breast",
|
|
121
|
+
"bronchus",
|
|
122
|
+
"connective tissue",
|
|
123
|
+
"embryo",
|
|
124
|
+
"esophagus",
|
|
125
|
+
"extraembryonic component",
|
|
126
|
+
"eye",
|
|
127
|
+
"gonad",
|
|
128
|
+
"heart",
|
|
129
|
+
"intestine",
|
|
130
|
+
"kidney",
|
|
131
|
+
"large intestine",
|
|
132
|
+
"limb",
|
|
133
|
+
"liver",
|
|
134
|
+
"lung",
|
|
135
|
+
"lymph node",
|
|
136
|
+
"lymphoid tissue",
|
|
137
|
+
"mammary gland",
|
|
138
|
+
"mouth",
|
|
139
|
+
"musculature of body",
|
|
140
|
+
"nerve",
|
|
141
|
+
"nose",
|
|
142
|
+
"ovary",
|
|
143
|
+
"pancreas",
|
|
144
|
+
"penis",
|
|
145
|
+
"placenta",
|
|
146
|
+
"prostate gland",
|
|
147
|
+
"skeleton",
|
|
148
|
+
"skin of body",
|
|
149
|
+
"small intestine",
|
|
150
|
+
"spinal cord",
|
|
151
|
+
"spleen",
|
|
152
|
+
"stomach",
|
|
153
|
+
"testis",
|
|
154
|
+
"thymus",
|
|
155
|
+
"thyroid gland",
|
|
156
|
+
"tongue",
|
|
157
|
+
"tonsil",
|
|
158
|
+
"ureter",
|
|
159
|
+
"urinary bladder",
|
|
160
|
+
"uterus",
|
|
161
|
+
"vagina",
|
|
162
|
+
"vasculature",
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
FILE_FORMATS = [
|
|
166
|
+
"fastq",
|
|
167
|
+
"bam",
|
|
168
|
+
"bed",
|
|
169
|
+
"bigWig",
|
|
170
|
+
"bigBed",
|
|
171
|
+
"tsv",
|
|
172
|
+
"csv",
|
|
173
|
+
"tar",
|
|
174
|
+
"hic",
|
|
175
|
+
"tagAlign",
|
|
176
|
+
"bedpe",
|
|
177
|
+
"pairs",
|
|
178
|
+
"fasta",
|
|
179
|
+
"gff",
|
|
180
|
+
"gtf",
|
|
181
|
+
"idat",
|
|
182
|
+
"CEL",
|
|
183
|
+
"rcc",
|
|
184
|
+
"sra",
|
|
185
|
+
"csfasta",
|
|
186
|
+
"csqual",
|
|
187
|
+
"2bit",
|
|
188
|
+
"database",
|
|
189
|
+
"vcf",
|
|
190
|
+
"bigInteract",
|
|
191
|
+
"idx",
|
|
192
|
+
"dat",
|
|
193
|
+
"txt",
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
OUTPUT_TYPES = [
|
|
197
|
+
"reads",
|
|
198
|
+
"alignments",
|
|
199
|
+
"unfiltered alignments",
|
|
200
|
+
"transcriptome alignments",
|
|
201
|
+
"signal",
|
|
202
|
+
"signal of unique reads",
|
|
203
|
+
"signal of all reads",
|
|
204
|
+
"signal p-value",
|
|
205
|
+
"fold change over control",
|
|
206
|
+
"peaks",
|
|
207
|
+
"IDR thresholded peaks",
|
|
208
|
+
"conservative IDR thresholded peaks",
|
|
209
|
+
"optimal IDR thresholded peaks",
|
|
210
|
+
"pseudoreplicated peaks",
|
|
211
|
+
"replicated peaks",
|
|
212
|
+
"stable peaks",
|
|
213
|
+
"hotspots",
|
|
214
|
+
"narrowPeaks",
|
|
215
|
+
"broadPeaks",
|
|
216
|
+
"gappedPeaks",
|
|
217
|
+
"gene quantifications",
|
|
218
|
+
"transcript quantifications",
|
|
219
|
+
"exon quantifications",
|
|
220
|
+
"splice junctions",
|
|
221
|
+
"genome reference",
|
|
222
|
+
"genome index",
|
|
223
|
+
"transcriptome reference",
|
|
224
|
+
"transcriptome index",
|
|
225
|
+
"spike-in sequence",
|
|
226
|
+
"contact matrix",
|
|
227
|
+
"contact domains",
|
|
228
|
+
"topologically associated domains",
|
|
229
|
+
"chromatin interactions",
|
|
230
|
+
"DNA accessibility raw signal",
|
|
231
|
+
"DNA accessibility enrichment signal",
|
|
232
|
+
"methylation state at CpG",
|
|
233
|
+
"methylation state at CHG",
|
|
234
|
+
"methylation state at CHH",
|
|
235
|
+
"enrichment",
|
|
236
|
+
"FDR cut rate",
|
|
237
|
+
"element quantifications",
|
|
238
|
+
"guide quantifications",
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
OUTPUT_CATEGORIES = [
|
|
242
|
+
"raw data",
|
|
243
|
+
"alignment",
|
|
244
|
+
"signal",
|
|
245
|
+
"annotation",
|
|
246
|
+
"quantification",
|
|
247
|
+
"reference",
|
|
248
|
+
"quality metric",
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
FILE_STATUSES = [
|
|
252
|
+
"released",
|
|
253
|
+
"archived",
|
|
254
|
+
"in progress",
|
|
255
|
+
"revoked",
|
|
256
|
+
"deleted",
|
|
257
|
+
"content error",
|
|
258
|
+
"upload failed",
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
EXPERIMENT_STATUSES = [
|
|
262
|
+
"released",
|
|
263
|
+
"archived",
|
|
264
|
+
"revoked",
|
|
265
|
+
"deleted",
|
|
266
|
+
"replaced",
|
|
267
|
+
"in progress",
|
|
268
|
+
"submitted",
|
|
269
|
+
"preliminary",
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
ASSEMBLIES = [
|
|
273
|
+
"GRCh38",
|
|
274
|
+
"hg19",
|
|
275
|
+
"mm10",
|
|
276
|
+
"mm9",
|
|
277
|
+
"GRCm39",
|
|
278
|
+
"dm6",
|
|
279
|
+
"dm3",
|
|
280
|
+
"ce11",
|
|
281
|
+
"ce10",
|
|
282
|
+
]
|
|
283
|
+
|
|
284
|
+
LIFE_STAGES = [
|
|
285
|
+
"embryonic",
|
|
286
|
+
"postnatal",
|
|
287
|
+
"newborn",
|
|
288
|
+
"child",
|
|
289
|
+
"adolescent",
|
|
290
|
+
"adult",
|
|
291
|
+
"unknown",
|
|
292
|
+
]
|
|
293
|
+
|
|
294
|
+
REPLICATION_TYPES = [
|
|
295
|
+
"isogenic",
|
|
296
|
+
"anisogenic",
|
|
297
|
+
"unreplicated",
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
# Map of metadata_type to its values for the get_metadata tool
|
|
301
|
+
METADATA_MAP = {
|
|
302
|
+
"assays": ASSAY_TITLES,
|
|
303
|
+
"organisms": ORGANISMS,
|
|
304
|
+
"organs": ORGAN_SLIMS,
|
|
305
|
+
"biosample_types": BIOSAMPLE_CLASSIFICATIONS,
|
|
306
|
+
"file_formats": FILE_FORMATS,
|
|
307
|
+
"output_types": OUTPUT_TYPES,
|
|
308
|
+
"output_categories": OUTPUT_CATEGORIES,
|
|
309
|
+
"assemblies": ASSEMBLIES,
|
|
310
|
+
"life_stages": LIFE_STAGES,
|
|
311
|
+
"replication_types": REPLICATION_TYPES,
|
|
312
|
+
"statuses": EXPERIMENT_STATUSES,
|
|
313
|
+
"file_statuses": FILE_STATUSES,
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
# ENCODE API parameter name mapping (user-friendly -> API param)
|
|
317
|
+
EXPERIMENT_FILTER_MAP = {
|
|
318
|
+
"assay_title": "assay_title",
|
|
319
|
+
"organism": "replicates.library.biosample.donor.organism.scientific_name",
|
|
320
|
+
"organ": "biosample_ontology.organ_slims",
|
|
321
|
+
"biosample_type": "biosample_ontology.classification",
|
|
322
|
+
"biosample_term_name": "biosample_ontology.term_name",
|
|
323
|
+
"target": "target.label",
|
|
324
|
+
"status": "status",
|
|
325
|
+
"lab": "lab.title",
|
|
326
|
+
"award": "award.project",
|
|
327
|
+
"assembly": "assembly",
|
|
328
|
+
"replication_type": "replication_type",
|
|
329
|
+
"life_stage": "replicates.library.biosample.life_stage",
|
|
330
|
+
"sex": "replicates.library.biosample.sex",
|
|
331
|
+
"perturbed": "replicates.library.biosample.perturbed",
|
|
332
|
+
"treatment": "replicates.library.biosample.treatments.treatment_term_name",
|
|
333
|
+
"genetic_modification": "replicates.library.biosample.applied_modifications.category",
|
|
334
|
+
"date_released": "date_released",
|
|
335
|
+
"searchTerm": "searchTerm",
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
FILE_FILTER_MAP = {
|
|
339
|
+
"file_format": "file_format",
|
|
340
|
+
"file_type": "file_type",
|
|
341
|
+
"output_type": "output_type",
|
|
342
|
+
"output_category": "output_category",
|
|
343
|
+
"assembly": "assembly",
|
|
344
|
+
"status": "status",
|
|
345
|
+
"biological_replicates": "biological_replicates",
|
|
346
|
+
"preferred_default": "preferred_default",
|
|
347
|
+
"dataset": "dataset",
|
|
348
|
+
}
|