biolmai 0.1.4__py2.py3-none-any.whl → 0.1.7__py2.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.
Potentially problematic release.
This version of biolmai might be problematic. Click here for more details.
- biolmai/__init__.py +3 -11
- biolmai/api.py +163 -247
- biolmai/asynch.py +90 -53
- biolmai/auth.py +75 -29
- biolmai/biolmai.py +1 -149
- biolmai/cli.py +30 -22
- biolmai/cls.py +96 -0
- biolmai/const.py +13 -11
- biolmai/payloads.py +28 -3
- biolmai/validate.py +55 -28
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/METADATA +1 -1
- biolmai-0.1.7.dist-info/RECORD +18 -0
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/WHEEL +1 -1
- biolmai-0.1.4.dist-info/RECORD +0 -18
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/AUTHORS.rst +0 -0
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/LICENSE +0 -0
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/entry_points.txt +0 -0
- {biolmai-0.1.4.dist-info → biolmai-0.1.7.dist-info}/top_level.txt +0 -0
biolmai/cls.py
CHANGED
|
@@ -1 +1,97 @@
|
|
|
1
1
|
"""API inference classes."""
|
|
2
|
+
from biolmai.api import APIEndpoint, GenerateAction, PredictAction, TransformAction
|
|
3
|
+
from biolmai.validate import ExtendedAAPlusExtra, SingleOccurrenceOf, UnambiguousAA
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ESMFoldSingleChain(APIEndpoint):
|
|
7
|
+
slug = "esmfold-singlechain"
|
|
8
|
+
action_classes = (PredictAction,)
|
|
9
|
+
seq_classes = (UnambiguousAA(),)
|
|
10
|
+
batch_size = 2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ESMFoldMultiChain(APIEndpoint):
|
|
14
|
+
slug = "esmfold-multichain"
|
|
15
|
+
action_classes = (PredictAction,)
|
|
16
|
+
seq_classes = (ExtendedAAPlusExtra(extra=[":"]),)
|
|
17
|
+
batch_size = 2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ESM2Embeddings(APIEndpoint):
|
|
21
|
+
"""Example.
|
|
22
|
+
|
|
23
|
+
.. highlight:: python
|
|
24
|
+
.. code-block:: python
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
"instances": [{
|
|
28
|
+
"data": {"text": "MSILVTRPSPAGEELVSRLRTLGQVAWHFPLIEFSPGQQLPQ"}
|
|
29
|
+
}]
|
|
30
|
+
}
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
slug = "esm2_t33_650M_UR50D"
|
|
34
|
+
action_classes = (TransformAction,)
|
|
35
|
+
seq_classes = (UnambiguousAA(),)
|
|
36
|
+
batch_size = 1
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ESM1v1(APIEndpoint):
|
|
40
|
+
"""Example.
|
|
41
|
+
|
|
42
|
+
.. highlight:: python
|
|
43
|
+
.. code-block:: python
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
"instances": [{
|
|
47
|
+
"data": {"text": "QERLEUTGR<mask>SLGYNIVAT"}
|
|
48
|
+
}]
|
|
49
|
+
}
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
slug = "esm1v_t33_650M_UR90S_1"
|
|
53
|
+
action_classes = (PredictAction,)
|
|
54
|
+
seq_classes = (SingleOccurrenceOf("<mask>"), ExtendedAAPlusExtra(extra=["<mask>"]))
|
|
55
|
+
batch_size = 5
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ESM1v2(APIEndpoint):
|
|
59
|
+
slug = "esm1v_t33_650M_UR90S_2"
|
|
60
|
+
action_classes = (PredictAction,)
|
|
61
|
+
seq_classes = (SingleOccurrenceOf("<mask>"), ExtendedAAPlusExtra(extra=["<mask>"]))
|
|
62
|
+
batch_size = 5
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ESM1v3(APIEndpoint):
|
|
66
|
+
slug = "esm1v_t33_650M_UR90S_3"
|
|
67
|
+
action_classes = (PredictAction,)
|
|
68
|
+
seq_classes = (SingleOccurrenceOf("<mask>"), ExtendedAAPlusExtra(extra=["<mask>"]))
|
|
69
|
+
batch_size = 5
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ESM1v4(APIEndpoint):
|
|
73
|
+
slug = "esm1v_t33_650M_UR90S_4"
|
|
74
|
+
action_classes = (PredictAction,)
|
|
75
|
+
seq_classes = (SingleOccurrenceOf("<mask>"), ExtendedAAPlusExtra(extra=["<mask>"]))
|
|
76
|
+
batch_size = 5
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ESM1v5(APIEndpoint):
|
|
80
|
+
slug = "esm1v_t33_650M_UR90S_5"
|
|
81
|
+
action_classes = (PredictAction,)
|
|
82
|
+
seq_classes = (SingleOccurrenceOf("<mask>"), ExtendedAAPlusExtra(extra=["<mask>"]))
|
|
83
|
+
batch_size = 5
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ESMIF1(APIEndpoint):
|
|
87
|
+
slug = "esmif1"
|
|
88
|
+
action_classes = (GenerateAction,)
|
|
89
|
+
seq_classes = ()
|
|
90
|
+
batch_size = 2
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class Progen2(APIEndpoint):
|
|
94
|
+
slug = "progen2"
|
|
95
|
+
action_classes = (GenerateAction,)
|
|
96
|
+
seq_classes = ()
|
|
97
|
+
batch_size = 1
|
biolmai/const.py
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import multiprocessing
|
|
2
|
+
import os
|
|
3
3
|
|
|
4
4
|
cpu_count = multiprocessing.cpu_count()
|
|
5
5
|
max_threads = cpu_count * 4
|
|
6
6
|
|
|
7
|
-
if os.environ.get(
|
|
7
|
+
if os.environ.get("BIOLMAI_LOCAL", False):
|
|
8
8
|
# For local development and tests only
|
|
9
|
-
BASE_DOMAIN =
|
|
9
|
+
BASE_DOMAIN = "http://localhost:8000"
|
|
10
10
|
else:
|
|
11
|
-
BASE_DOMAIN =
|
|
11
|
+
BASE_DOMAIN = "https://biolm.ai"
|
|
12
12
|
|
|
13
|
-
USER_BIOLM_DIR = os.path.join(os.path.expanduser(
|
|
14
|
-
ACCESS_TOK_PATH = os.path.join(USER_BIOLM_DIR,
|
|
15
|
-
GEN_TOKEN_URL = f
|
|
16
|
-
MULTIPROCESS_THREADS = os.environ.get(
|
|
13
|
+
USER_BIOLM_DIR = os.path.join(os.path.expanduser("~"), ".biolmai")
|
|
14
|
+
ACCESS_TOK_PATH = os.path.join(USER_BIOLM_DIR, "credentials")
|
|
15
|
+
GEN_TOKEN_URL = f"{BASE_DOMAIN}/ui/accounts/user-api-tokens/"
|
|
16
|
+
MULTIPROCESS_THREADS = os.environ.get("BIOLMAI_THREADS", 1)
|
|
17
17
|
if isinstance(MULTIPROCESS_THREADS, str) and not MULTIPROCESS_THREADS:
|
|
18
18
|
MULTIPROCESS_THREADS = 1
|
|
19
19
|
if int(MULTIPROCESS_THREADS) > max_threads or int(MULTIPROCESS_THREADS) > 128:
|
|
20
|
-
err =
|
|
21
|
-
|
|
20
|
+
err = (
|
|
21
|
+
f"Maximum threads allowed is 4x number of CPU cores ("
|
|
22
|
+
f"{max_threads}) or 128, whichever is lower."
|
|
23
|
+
)
|
|
22
24
|
err += " Please update environment variable BIOLMAI_THREADS."
|
|
23
25
|
raise ValueError(err)
|
|
24
26
|
elif int(MULTIPROCESS_THREADS) <= 0:
|
|
25
27
|
err = "Environment variable BIOLMAI_THREADS must be a positive integer."
|
|
26
28
|
raise ValueError(err)
|
|
27
|
-
BASE_API_URL = f
|
|
29
|
+
BASE_API_URL = f"{BASE_DOMAIN}/api/v1"
|
biolmai/payloads.py
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
def INST_DAT_TXT(batch, include_batch_size=False):
|
|
2
2
|
d = {"instances": []}
|
|
3
|
-
for
|
|
3
|
+
for _, row in batch.iterrows():
|
|
4
4
|
inst = {"data": {"text": row.text}}
|
|
5
|
-
d[
|
|
5
|
+
d["instances"].append(inst)
|
|
6
6
|
if include_batch_size is True:
|
|
7
|
-
d[
|
|
7
|
+
d["batch_size"] = len(d["instances"])
|
|
8
8
|
return d
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def predict_resp_many_in_one_to_many_singles(
|
|
12
|
+
resp_json, status_code, batch_id, local_err, batch_size
|
|
13
|
+
):
|
|
14
|
+
expected_root_key = "predictions"
|
|
15
|
+
to_ret = []
|
|
16
|
+
if not local_err and status_code and status_code == 200:
|
|
17
|
+
list_of_individual_seq_results = resp_json[expected_root_key]
|
|
18
|
+
elif local_err:
|
|
19
|
+
list_of_individual_seq_results = [{"error": resp_json}]
|
|
20
|
+
elif status_code and status_code != 200 and isinstance(resp_json, dict):
|
|
21
|
+
list_of_individual_seq_results = [resp_json] * batch_size
|
|
22
|
+
else:
|
|
23
|
+
raise ValueError("Unexpected response in parser")
|
|
24
|
+
for idx, item in enumerate(list_of_individual_seq_results):
|
|
25
|
+
d = {"status_code": status_code, "batch_id": batch_id, "batch_item": idx}
|
|
26
|
+
if not status_code or status_code != 200:
|
|
27
|
+
d.update(item) # Put all resp keys at root there
|
|
28
|
+
else:
|
|
29
|
+
# We just append one item, mimicking a single seq in POST req/resp
|
|
30
|
+
d[expected_root_key] = []
|
|
31
|
+
d[expected_root_key].append(item)
|
|
32
|
+
to_ret.append(d)
|
|
33
|
+
return to_ret
|
biolmai/validate.py
CHANGED
|
@@ -1,28 +1,47 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
|
-
UNAMBIGUOUS_AA = (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
UNAMBIGUOUS_AA = (
|
|
4
|
+
"A",
|
|
5
|
+
"C",
|
|
6
|
+
"D",
|
|
7
|
+
"E",
|
|
8
|
+
"F",
|
|
9
|
+
"G",
|
|
10
|
+
"H",
|
|
11
|
+
"I",
|
|
12
|
+
"K",
|
|
13
|
+
"L",
|
|
14
|
+
"M",
|
|
15
|
+
"N",
|
|
16
|
+
"P",
|
|
17
|
+
"Q",
|
|
18
|
+
"R",
|
|
19
|
+
"S",
|
|
20
|
+
"T",
|
|
21
|
+
"V",
|
|
22
|
+
"W",
|
|
23
|
+
"Y",
|
|
24
|
+
)
|
|
25
|
+
AAs = "".join(UNAMBIGUOUS_AA)
|
|
7
26
|
# Let's use extended list for ESM-1v
|
|
8
|
-
AAs_EXTENDED =
|
|
27
|
+
AAs_EXTENDED = "ACDEFGHIKLMNPQRSTVWYBXZJUO"
|
|
9
28
|
|
|
10
29
|
|
|
11
|
-
UNAMBIGUOUS_DNA = (
|
|
12
|
-
AMBIGUOUS_DNA = (
|
|
30
|
+
UNAMBIGUOUS_DNA = ("A", "C", "T", "G")
|
|
31
|
+
AMBIGUOUS_DNA = ("A", "C", "T", "G", "X", "N", "U")
|
|
13
32
|
|
|
14
33
|
|
|
15
34
|
regexes = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
35
|
+
"empty_or_unambiguous_aa_validator": re.compile(f"^[{AAs}]*$"),
|
|
36
|
+
"empty_or_unambiguous_dna_validator": re.compile(r"^[ACGT]*$"),
|
|
37
|
+
"extended_aa_validator": re.compile(f"^[{AAs_EXTENDED}]+$"),
|
|
38
|
+
"unambiguous_aa_validator": re.compile(f"^[{AAs}]+$"),
|
|
39
|
+
"unambiguous_dna_validator": re.compile(r"^[ACGT]+$"),
|
|
21
40
|
}
|
|
22
41
|
|
|
23
42
|
|
|
24
43
|
def empty_or_unambiguous_aa_validator(txt):
|
|
25
|
-
r = regexes[
|
|
44
|
+
r = regexes["empty_or_unambiguous_aa_validator"]
|
|
26
45
|
if not bool(r.match(txt)):
|
|
27
46
|
err = f"Residues can only be represented with '{AAs}' characters"
|
|
28
47
|
raise AssertionError(err)
|
|
@@ -30,36 +49,40 @@ def empty_or_unambiguous_aa_validator(txt):
|
|
|
30
49
|
|
|
31
50
|
|
|
32
51
|
def empty_or_unambiguous_dna_validator(txt):
|
|
33
|
-
r = regexes[
|
|
52
|
+
r = regexes["empty_or_unambiguous_dna_validator"]
|
|
34
53
|
if not bool(r.match(txt)):
|
|
35
|
-
err =
|
|
54
|
+
err = "Nucleotides can only be represented with 'ACTG' characters"
|
|
36
55
|
raise AssertionError(err)
|
|
37
56
|
return txt
|
|
38
57
|
|
|
39
58
|
|
|
40
59
|
def extended_aa_validator(txt):
|
|
41
|
-
r = regexes[
|
|
60
|
+
r = regexes["extended_aa_validator"]
|
|
42
61
|
if not bool(r.match(txt)):
|
|
43
|
-
err =
|
|
44
|
-
|
|
62
|
+
err = (
|
|
63
|
+
f"Extended residues can only be represented with "
|
|
64
|
+
f"'{AAs_EXTENDED}' characters"
|
|
65
|
+
)
|
|
45
66
|
raise AssertionError(err)
|
|
46
67
|
return txt
|
|
47
68
|
|
|
48
69
|
|
|
49
70
|
def unambiguous_aa_validator(txt):
|
|
50
|
-
r = regexes[
|
|
71
|
+
r = regexes["unambiguous_aa_validator"]
|
|
51
72
|
if not bool(r.match(txt)):
|
|
52
|
-
err =
|
|
53
|
-
|
|
73
|
+
err = (
|
|
74
|
+
f"Unambiguous residues can only be represented with '{AAs}' " f"characters"
|
|
75
|
+
)
|
|
54
76
|
raise AssertionError(err)
|
|
55
77
|
return txt
|
|
56
78
|
|
|
57
79
|
|
|
58
80
|
def unambiguous_dna_validator(txt):
|
|
59
|
-
r = regexes[
|
|
81
|
+
r = regexes["unambiguous_dna_validator"]
|
|
60
82
|
if not bool(r.match(txt)):
|
|
61
|
-
err =
|
|
62
|
-
|
|
83
|
+
err = (
|
|
84
|
+
"Unambiguous nucleotides can only be represented with 'ACTG' " "characters"
|
|
85
|
+
)
|
|
63
86
|
raise AssertionError(err)
|
|
64
87
|
return txt
|
|
65
88
|
|
|
@@ -70,7 +93,9 @@ class UnambiguousAA:
|
|
|
70
93
|
|
|
71
94
|
|
|
72
95
|
class UnambiguousAAPlusExtra:
|
|
73
|
-
def __init__(self, extra=
|
|
96
|
+
def __init__(self, extra=None):
|
|
97
|
+
if extra is None:
|
|
98
|
+
extra = []
|
|
74
99
|
self.extra = extra
|
|
75
100
|
assert len(extra) > 0
|
|
76
101
|
assert isinstance(extra, list)
|
|
@@ -78,12 +103,14 @@ class UnambiguousAAPlusExtra:
|
|
|
78
103
|
def __call__(self, value):
|
|
79
104
|
txt_clean = value
|
|
80
105
|
for ex in self.extra:
|
|
81
|
-
txt_clean = value.replace(ex,
|
|
106
|
+
txt_clean = value.replace(ex, "")
|
|
82
107
|
_ = unambiguous_aa_validator(txt_clean)
|
|
83
108
|
|
|
84
109
|
|
|
85
110
|
class ExtendedAAPlusExtra:
|
|
86
|
-
def __init__(self, extra=
|
|
111
|
+
def __init__(self, extra=None):
|
|
112
|
+
if extra is None:
|
|
113
|
+
extra = []
|
|
87
114
|
self.extra = extra
|
|
88
115
|
assert len(extra) > 0
|
|
89
116
|
assert isinstance(extra, list)
|
|
@@ -91,7 +118,7 @@ class ExtendedAAPlusExtra:
|
|
|
91
118
|
def __call__(self, value):
|
|
92
119
|
txt_clean = value
|
|
93
120
|
for ex in self.extra:
|
|
94
|
-
txt_clean = value.replace(ex,
|
|
121
|
+
txt_clean = value.replace(ex, "")
|
|
95
122
|
_ = extended_aa_validator(txt_clean)
|
|
96
123
|
|
|
97
124
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
biolmai/__init__.py,sha256=lJ7PiA_IyjKhz3dI8nrnqy8S_wqAHtEM3iN3v3eArr0,136
|
|
2
|
+
biolmai/api.py,sha256=3DcXeTFwXdn2KpHrGPxFGN6bvzdFjK6_4KUZuaRe64w,10974
|
|
3
|
+
biolmai/asynch.py,sha256=ZLCiNdGDR2XvijM6jFB2IFl3bG7ROp4PxKbo1rI5s7A,8698
|
|
4
|
+
biolmai/auth.py,sha256=flI9KAD90qdXyLDnpJTrc9voKsiK0uWtD2ehsPBn8r4,6329
|
|
5
|
+
biolmai/biolmai.py,sha256=xwjAvuw6AtmQdkRf_usSGUZ-k2oU-fjl82_WAgfSvVE,74
|
|
6
|
+
biolmai/cli.py,sha256=bdb4q8QlN73A6Ttz0e-dBIwoct7PYqy5WSc52jCMIyU,1967
|
|
7
|
+
biolmai/cls.py,sha256=yacZIwDyDq3sgU3FSc-l8uld83lkwSTh4wiS-vGNT4I,2425
|
|
8
|
+
biolmai/const.py,sha256=kbpmBEm-bw7lhGIJcMFeq1pfsIYeRk01_JwBufjupXc,1111
|
|
9
|
+
biolmai/ltc.py,sha256=al7HZc5tLyUR5fmpIb95hOz5ctudVsc0xzjd_c2Ew3M,49
|
|
10
|
+
biolmai/payloads.py,sha256=WmFN9JUojbrdvd_By8WWURS6Gm5Bh1fPYK0UjLDCbzU,1356
|
|
11
|
+
biolmai/validate.py,sha256=QdPDuZodHn85p1Y7KGkxCDMuRcXBOzAB9lkNZpigw9g,3311
|
|
12
|
+
biolmai-0.1.7.dist-info/AUTHORS.rst,sha256=TB_ACuFPgVmxn1NspYwksTdT6jdZeShcxfafmi-XWKQ,158
|
|
13
|
+
biolmai-0.1.7.dist-info/LICENSE,sha256=8yt0SdP38I7a3g0zWqZjNe0VSDQhJA4bWLQSqqKtAVg,583
|
|
14
|
+
biolmai-0.1.7.dist-info/METADATA,sha256=S2JBm8gzzRm_Xsb0aY3LozcW9TSocbqFLZd8BsA7gQw,1929
|
|
15
|
+
biolmai-0.1.7.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
|
16
|
+
biolmai-0.1.7.dist-info/entry_points.txt,sha256=ylQnDpCYrxF1F9z_T7NRQcYMWYF5ia_KsTUuboxjEAM,44
|
|
17
|
+
biolmai-0.1.7.dist-info/top_level.txt,sha256=jyQO45JN3g_jbdI8WqMnb0aEIzf4h1MrmPAZkKgfnwY,8
|
|
18
|
+
biolmai-0.1.7.dist-info/RECORD,,
|
biolmai-0.1.4.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
biolmai/__init__.py,sha256=fbDI9cxEz865hVVZpWg5XWv546aL98bt9s9Xe1r_v74,340
|
|
2
|
-
biolmai/api.py,sha256=3XEJ_AIBqe0FBGmEtD85w_uVZs1D8v2nfviC0KKlUQY,13513
|
|
3
|
-
biolmai/asynch.py,sha256=R6p_i-1KK7xGmw1EPUCUYRiwg2tyl-D2JkaNUvUYL3w,7455
|
|
4
|
-
biolmai/auth.py,sha256=Z1lCrN4xJjf5dP7tMxQ0O7cQ7BomwhTdjp4c2NwQuIg,4863
|
|
5
|
-
biolmai/biolmai.py,sha256=CjaV-T1n5Kle8prUSEsIvSYcAA5CJ2XDU2mWsJYDhz8,5336
|
|
6
|
-
biolmai/cli.py,sha256=rpet-mToHlSRIqRgSXGUbqjgPEk-c0nU_ZIalJ3dtjw,1936
|
|
7
|
-
biolmai/cls.py,sha256=Hh_ggmCfDZGPSzYfCfXcFhvoOJVgpuc1rgwHdr7KGFY,29
|
|
8
|
-
biolmai/const.py,sha256=CyZve7qZ8cnX9T4NvNxw2Xpi8QKPX7B_lfXxt8se1tc,1099
|
|
9
|
-
biolmai/ltc.py,sha256=al7HZc5tLyUR5fmpIb95hOz5ctudVsc0xzjd_c2Ew3M,49
|
|
10
|
-
biolmai/payloads.py,sha256=Si0EHKVNYGOAMAsiC4hEez8YZve88cYPu2KwBfaIN18,289
|
|
11
|
-
biolmai/validate.py,sha256=lU-qT11xgB83q76-knKNygDMLAqRdLlmP9mLh6wqNNw,3130
|
|
12
|
-
biolmai-0.1.4.dist-info/AUTHORS.rst,sha256=TB_ACuFPgVmxn1NspYwksTdT6jdZeShcxfafmi-XWKQ,158
|
|
13
|
-
biolmai-0.1.4.dist-info/LICENSE,sha256=8yt0SdP38I7a3g0zWqZjNe0VSDQhJA4bWLQSqqKtAVg,583
|
|
14
|
-
biolmai-0.1.4.dist-info/METADATA,sha256=xX62sswY4h8rheJlCZCmD_fmVmiKf1yAqdwZ5qU_g0c,1929
|
|
15
|
-
biolmai-0.1.4.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110
|
|
16
|
-
biolmai-0.1.4.dist-info/entry_points.txt,sha256=ylQnDpCYrxF1F9z_T7NRQcYMWYF5ia_KsTUuboxjEAM,44
|
|
17
|
-
biolmai-0.1.4.dist-info/top_level.txt,sha256=jyQO45JN3g_jbdI8WqMnb0aEIzf4h1MrmPAZkKgfnwY,8
|
|
18
|
-
biolmai-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|