idlib 0.0.1.dev23__py2.py3-none-any.whl → 0.0.1.dev24__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.
- idlib/__init__.py +1 -1
- idlib/cache.py +16 -3
- idlib/from_oq.py +16 -0
- idlib/streams.py +22 -3
- idlib/systems/doi.py +23 -8
- idlib/systems/rrid.py +25 -3
- {idlib-0.0.1.dev23.dist-info → idlib-0.0.1.dev24.dist-info}/METADATA +4 -4
- {idlib-0.0.1.dev23.dist-info → idlib-0.0.1.dev24.dist-info}/RECORD +11 -11
- {idlib-0.0.1.dev23.dist-info → idlib-0.0.1.dev24.dist-info}/WHEEL +1 -1
- {idlib-0.0.1.dev23.dist-info → idlib-0.0.1.dev24.dist-info}/licenses/LICENSE +0 -0
- {idlib-0.0.1.dev23.dist-info → idlib-0.0.1.dev24.dist-info}/top_level.txt +0 -0
idlib/__init__.py
CHANGED
idlib/cache.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import pickle
|
|
2
3
|
import hashlib
|
|
3
4
|
import inspect
|
|
4
5
|
from pathlib import Path
|
|
@@ -66,6 +67,10 @@ def cache(folder, ser='json', clear_cache=False, create=False, return_path=False
|
|
|
66
67
|
serialize = json.dump
|
|
67
68
|
deserialize = json.load
|
|
68
69
|
mode = 't'
|
|
70
|
+
elif ser == 'pickle':
|
|
71
|
+
serialize = pickle.dump
|
|
72
|
+
deserialize = pickle.load
|
|
73
|
+
mode = 'b'
|
|
69
74
|
else:
|
|
70
75
|
raise TypeError('Bad serialization format.')
|
|
71
76
|
|
|
@@ -77,9 +82,11 @@ def cache(folder, ser='json', clear_cache=False, create=False, return_path=False
|
|
|
77
82
|
if not create:
|
|
78
83
|
raise FileNotFoundError(f'Cache base folder does not exist! {folder}')
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
# TOCTOU race condition is hit idlib is imported by multi-process workers
|
|
86
|
+
folder.mkdir(parents=True, exist_ok=True)
|
|
81
87
|
|
|
82
88
|
if clear_cache:
|
|
89
|
+
import shutil
|
|
83
90
|
log.debug(f'clearing cache for {folder}')
|
|
84
91
|
shutil.rmtree(folder)
|
|
85
92
|
folder.mkdir()
|
|
@@ -100,8 +107,14 @@ def cache(folder, ser='json', clear_cache=False, create=False, return_path=False
|
|
|
100
107
|
else:
|
|
101
108
|
output = function(*args, **kwargs)
|
|
102
109
|
if output is not None:
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
try:
|
|
111
|
+
with open(filepath, write_mode) as f:
|
|
112
|
+
serialize(output, f)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
filepath.unlink()
|
|
115
|
+
# TODO remove serialization on failure so we
|
|
116
|
+
# don't think a real cache exists
|
|
117
|
+
raise e
|
|
105
118
|
|
|
106
119
|
if isinstance(output, dict) and COOLDOWN in output:
|
|
107
120
|
# a hack to put a dummy variable in the cache
|
idlib/from_oq.py
CHANGED
|
@@ -432,6 +432,10 @@ class Pio(formats.Rdf, idlib.Stream):
|
|
|
432
432
|
if data:
|
|
433
433
|
doi = data['doi']
|
|
434
434
|
if doi:
|
|
435
|
+
if not doi.startswith('http'):
|
|
436
|
+
# why is there no scheme? who knows!?
|
|
437
|
+
doi = 'https://' + doi
|
|
438
|
+
|
|
435
439
|
return idlib.Doi(doi)
|
|
436
440
|
|
|
437
441
|
@property
|
|
@@ -758,6 +762,11 @@ class Pio(formats.Rdf, idlib.Stream):
|
|
|
758
762
|
# and pio json mean there is an extra layer that needs
|
|
759
763
|
# interpretation ... i.e. we definitely got to the remote
|
|
760
764
|
raise NotImplementedError(msg)
|
|
765
|
+
elif sc == 1266:
|
|
766
|
+
msg = 'rate limit exceeded'
|
|
767
|
+
if fail_ok: return
|
|
768
|
+
path.unlink() # hopefully works next time?
|
|
769
|
+
raise exc.AccessLimitError(msg)
|
|
761
770
|
else:
|
|
762
771
|
msg = f'unhandled pio status code {sc}\n' + message
|
|
763
772
|
raise NotImplementedError(msg)
|
|
@@ -816,8 +825,10 @@ class Pio(formats.Rdf, idlib.Stream):
|
|
|
816
825
|
# for how we got there, even if we toss the crazy slugs
|
|
817
826
|
self._progenitors = {} # FIXME yes this blasts progens every time
|
|
818
827
|
uh = self.uri_human
|
|
828
|
+
_sigh = uh._progenitors.pop('id-converted-from') # avoid infinite recursion
|
|
819
829
|
uai = uh.uri_api_int
|
|
820
830
|
d4 = uai.data4(fail_ok=fail_ok)
|
|
831
|
+
uh._progenitors['id-converted-from'] = _sigh
|
|
821
832
|
self._progenitors['id-converted-to'] = uai
|
|
822
833
|
if 'path' in uai._progenitors:
|
|
823
834
|
self._progenitors['path'] = uai._progenitors['path']
|
|
@@ -833,6 +844,8 @@ class Pio(formats.Rdf, idlib.Stream):
|
|
|
833
844
|
except Exception as e0:
|
|
834
845
|
try:
|
|
835
846
|
return self.data1(fail_ok=fail_ok)
|
|
847
|
+
except exc.IdDoesNotExistError as ene1:
|
|
848
|
+
raise ene1
|
|
836
849
|
except Exception as e1:
|
|
837
850
|
# FIXME error type ...
|
|
838
851
|
raise exc.InbetweenError() from e1
|
|
@@ -840,6 +853,9 @@ class Pio(formats.Rdf, idlib.Stream):
|
|
|
840
853
|
return self.data4(fail_ok=fail_ok)
|
|
841
854
|
except (AttributeError, NotImplementedError) as e:
|
|
842
855
|
raise e
|
|
856
|
+
except exc.IdDoesNotExistError as e:
|
|
857
|
+
# don't wait for pioids that don't exist
|
|
858
|
+
raise e
|
|
843
859
|
except Exception as e:
|
|
844
860
|
wait_until = time() + self._wait_time
|
|
845
861
|
self._data_in_error_sigh = wait_until, e
|
idlib/streams.py
CHANGED
|
@@ -440,7 +440,12 @@ class HelpTestStreams:
|
|
|
440
440
|
HelpTestStreams._copy = copy
|
|
441
441
|
import pickle
|
|
442
442
|
HelpTestStreams._pickle = pickle
|
|
443
|
-
|
|
443
|
+
try:
|
|
444
|
+
from joblib import Parallel, delayed
|
|
445
|
+
except Exception as e:
|
|
446
|
+
log.exception(e)
|
|
447
|
+
from pyontutils.asyncd import Async as Parallel, deferred as delayed
|
|
448
|
+
|
|
444
449
|
HelpTestStreams._Parallel = Parallel
|
|
445
450
|
HelpTestStreams._delayed = delayed
|
|
446
451
|
|
|
@@ -464,7 +469,11 @@ class HelpTestStreams:
|
|
|
464
469
|
print(d.identifier.prefix)
|
|
465
470
|
print(d.identifier.suffix)
|
|
466
471
|
if d.identifier.prefix is None or d.identifier.suffix is None:
|
|
467
|
-
|
|
472
|
+
if hasattr(d.identifier, 'iri') and hasattr(d.identifier, 'valid') and d.identifier.valid:
|
|
473
|
+
# doi case
|
|
474
|
+
pass
|
|
475
|
+
else:
|
|
476
|
+
bads.append(d.identifier.__dict__)
|
|
468
477
|
|
|
469
478
|
try:
|
|
470
479
|
d.identifier_bound_metadata
|
|
@@ -501,9 +510,18 @@ class HelpTestStreams:
|
|
|
501
510
|
|
|
502
511
|
def test_malformed(self):
|
|
503
512
|
bads = []
|
|
504
|
-
|
|
513
|
+
vbads = []
|
|
514
|
+
pre_garbage = 'oops '
|
|
515
|
+
post_garbage = ' oops'
|
|
516
|
+
bad_ids = (
|
|
517
|
+
list(self.ids_bad) +
|
|
518
|
+
[pre_garbage + i for i in self.ids] +
|
|
519
|
+
[i + post_garbage for i in self.ids])
|
|
520
|
+
for i in bad_ids:
|
|
505
521
|
try:
|
|
506
522
|
d = self.stream(i)
|
|
523
|
+
d.identifier.validate()
|
|
524
|
+
vbads.append(d)
|
|
507
525
|
d.data()
|
|
508
526
|
bads.append(d)
|
|
509
527
|
except Exception as e:
|
|
@@ -511,6 +529,7 @@ class HelpTestStreams:
|
|
|
511
529
|
pass
|
|
512
530
|
|
|
513
531
|
assert not bads, bads
|
|
532
|
+
assert not vbads, vbads
|
|
514
533
|
|
|
515
534
|
def test_hash_eq_id(self):
|
|
516
535
|
hrm = self.ids[0]
|
idlib/systems/doi.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from urllib.parse import unquote, quote
|
|
1
3
|
import ontquery as oq # temp implementation detail
|
|
2
4
|
import idlib
|
|
3
5
|
from idlib import formats
|
|
@@ -26,8 +28,11 @@ class DoiId(oq.OntId, idlib.Identifier, idlib.Stream): # also _technically_ a s
|
|
|
26
28
|
_namespaces = _DoiPrefixes
|
|
27
29
|
_local_conventions = _namespaces
|
|
28
30
|
_id_class = str # eventually we have to drop down to something
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
# https://www.crossref.org/blog/dois-and-matching-regular-expressions/
|
|
32
|
+
# but we have cases that don't follow in our set ... so we may need a variant regex
|
|
33
|
+
# so we can warn if we see one
|
|
34
|
+
local_regex = '^10\\.[0-9]{4,9}/[-._;()<>/:a-zA-Z0-9]+$'
|
|
35
|
+
canonical_regex = '^https://doi.org/10\\.[0-9]{4,9}/[-._;()<>/:a-zA-Z0-9]+$'
|
|
31
36
|
|
|
32
37
|
def __new__(cls, doi_in_various_states_of_mangling=None, iri=None):
|
|
33
38
|
if doi_in_various_states_of_mangling is None and iri is not None:
|
|
@@ -59,22 +64,29 @@ class DoiId(oq.OntId, idlib.Identifier, idlib.Stream): # also _technically_ a s
|
|
|
59
64
|
|
|
60
65
|
@staticmethod
|
|
61
66
|
def normalize(doi):
|
|
62
|
-
doi = doi.replace(' ', '')
|
|
63
|
-
if 'http'
|
|
67
|
+
doi = doi.strip().replace(' :', ':').replace(': ', ':')
|
|
68
|
+
if doi.startswith('http') or doi.startswith('doi.org'):
|
|
64
69
|
doi = '10.' + doi.split('.org/10.', 1)[-1]
|
|
70
|
+
# space is left in quote to ensure we produce an error because there should be no spaces
|
|
71
|
+
doi = quote(unquote(doi), safe='-._;()/: ')
|
|
65
72
|
elif doi.startswith('doi:'):
|
|
66
|
-
doi = doi.strip('doi:')
|
|
73
|
+
doi = doi.strip('doi:').strip()
|
|
67
74
|
elif doi.startswith('DOI:'):
|
|
68
|
-
doi = doi.strip('DOI:')
|
|
75
|
+
doi = doi.strip('DOI:').strip()
|
|
76
|
+
|
|
69
77
|
return doi
|
|
70
78
|
|
|
71
79
|
@property
|
|
72
80
|
def valid(self):
|
|
73
|
-
|
|
81
|
+
if self.curie is None:
|
|
82
|
+
# we may have one of the pathalogical cases
|
|
83
|
+
return re.match(self.canonical_regex, unquote(self.iri))
|
|
84
|
+
else:
|
|
85
|
+
return self.suffix is not None and self.suffix.startswith('10.')
|
|
74
86
|
|
|
75
87
|
def validate(self):
|
|
76
88
|
if not self.valid:
|
|
77
|
-
raise exc.MalformedIdentifierError(f'{self._unnormalized} does not appear '
|
|
89
|
+
raise exc.MalformedIdentifierError(f'{self._unnormalized!r} does not appear '
|
|
78
90
|
f'to be of type {self.__class__}')
|
|
79
91
|
|
|
80
92
|
|
|
@@ -97,6 +109,9 @@ class Doi(formats.Rdf, idlib.Stream): # FIXME that 'has canonical representaito
|
|
|
97
109
|
def __init__(self, doi_in_various_states_of_mangling=None, iri=None):
|
|
98
110
|
self._identifier = self._id_class(doi_in_various_states_of_mangling, iri)
|
|
99
111
|
|
|
112
|
+
def __repr__(self):
|
|
113
|
+
return f'<idlib.{self.__class__.__name__}({self._identifier.asStr()!r})>'
|
|
114
|
+
|
|
100
115
|
def __gt__(self, other):
|
|
101
116
|
if isinstance(other, idlib.Stream):
|
|
102
117
|
return self.identifier > other.identifier
|
idlib/systems/rrid.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from time import sleep
|
|
2
3
|
import idlib
|
|
3
4
|
from idlib import formats
|
|
4
5
|
from idlib import streams
|
|
@@ -11,12 +12,12 @@ from idlib.config import auth
|
|
|
11
12
|
|
|
12
13
|
class RridId(idlib.Identifier):
|
|
13
14
|
|
|
14
|
-
canonical_regex = 'RRID:([A-Za-z]+)_([A-Za-z0-9_:-]+)'
|
|
15
|
+
canonical_regex = '^RRID:([A-Za-z]+)_([A-Za-z0-9_:-]+)$'
|
|
15
16
|
# NOTE: the canonical regex fails to capture a couple
|
|
16
17
|
# of legacy cases e.g. RRID:WB-STRAIN_ and RRID:MGI:
|
|
17
18
|
# yes I understand why MGI doesn't want RRID:MGI_MGI:
|
|
18
19
|
# but what other identifier namespaces do they use?
|
|
19
|
-
_variant_regex = 'RRID:([A-Z]+):([A-Za-z0-9_:-]+)' # legacy
|
|
20
|
+
_variant_regex = '^RRID:([A-Z]+):([A-Za-z0-9_:-]+)$' # legacy
|
|
20
21
|
_local_conventions = conv.Identity
|
|
21
22
|
|
|
22
23
|
def __init__(self, rrid):
|
|
@@ -101,10 +102,31 @@ class Rrid(formats.Rdf, idlib.HelperNoData, idlib.Stream):
|
|
|
101
102
|
elif self._COOLDOWN and self._resp_metadata.status_code == 404:
|
|
102
103
|
msg = f'RRID failure: {self._resp_metadata.status_code} {self.asUri()}'
|
|
103
104
|
return {COOLDOWN: msg,}
|
|
105
|
+
elif self._resp_metadata.status_code == 429:
|
|
106
|
+
headers = self._resp_metadata.headers
|
|
107
|
+
if 'Retry-After' in headers:
|
|
108
|
+
try:
|
|
109
|
+
wait = int(headers['Retry-After'])
|
|
110
|
+
except ValueError as ve:
|
|
111
|
+
try:
|
|
112
|
+
self._resp_metadata.raise_for_status()
|
|
113
|
+
except Exception as e:
|
|
114
|
+
raise exc.ResolutionError(identifier) from e
|
|
115
|
+
|
|
116
|
+
if wait > 20:
|
|
117
|
+
try:
|
|
118
|
+
self._resp_metadata.raise_for_status()
|
|
119
|
+
except Exception as e:
|
|
120
|
+
raise exc.ResolutionError(identifier) from e
|
|
121
|
+
|
|
122
|
+
log.debug(f'waiting {wait}s for {identifier}')
|
|
123
|
+
sleep(wait)
|
|
124
|
+
return self._metadata(identifier)
|
|
125
|
+
|
|
104
126
|
else:
|
|
105
127
|
try:
|
|
106
128
|
self._resp_metadata.raise_for_status()
|
|
107
|
-
except
|
|
129
|
+
except Exception as e:
|
|
108
130
|
raise exc.ResolutionError(identifier) from e
|
|
109
131
|
|
|
110
132
|
@cache_result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: idlib
|
|
3
|
-
Version: 0.0.1.
|
|
3
|
+
Version: 0.0.1.dev24
|
|
4
4
|
Summary: A library for working with identifiers of all kinds.
|
|
5
5
|
Home-page: https://github.com/tgbugs/idlib
|
|
6
6
|
Author: Tom Gillespie
|
|
@@ -8,7 +8,6 @@ Author-email: tgbugs@gmail.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Keywords: python persistent identifiers
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.7
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.8
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -16,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
19
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
20
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
21
|
Classifier: Operating System :: POSIX :: Linux
|
|
@@ -30,12 +30,12 @@ Provides-Extra: test
|
|
|
30
30
|
Requires-Dist: pytest; extra == "test"
|
|
31
31
|
Requires-Dist: joblib>=1.1.0; extra == "test"
|
|
32
32
|
Requires-Dist: beautifulsoup4[html5lib]; extra == "test"
|
|
33
|
-
Requires-Dist: pyontutils>=0.1.
|
|
33
|
+
Requires-Dist: pyontutils>=0.1.40; extra == "test"
|
|
34
34
|
Requires-Dist: google-auth-oauthlib; extra == "test"
|
|
35
35
|
Provides-Extra: org
|
|
36
36
|
Requires-Dist: beautifulsoup4[html5lib]; extra == "org"
|
|
37
37
|
Provides-Extra: rdf
|
|
38
|
-
Requires-Dist: pyontutils>=0.1.
|
|
38
|
+
Requires-Dist: pyontutils>=0.1.40; extra == "rdf"
|
|
39
39
|
Provides-Extra: oauth
|
|
40
40
|
Requires-Dist: google-auth-oauthlib; extra == "oauth"
|
|
41
41
|
Dynamic: author
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
idlib/__init__.py,sha256=
|
|
1
|
+
idlib/__init__.py,sha256=nM5sqe3xTkzp2ETq97yYQUeeoJ3sHfNb_CtVrzJ7moA,1696
|
|
2
2
|
idlib/auth-config.py,sha256=tYM2aYCYJFG5NB4Af1dSn6YxhafttOp7W7aSc-QbVV8,460
|
|
3
|
-
idlib/cache.py,sha256=
|
|
3
|
+
idlib/cache.py,sha256=UN3ufibDtPHgdMqKEXqVvVhfUTod08Vs_xsG12D5kns,4396
|
|
4
4
|
idlib/config.py,sha256=Gli2tZlbKxBos8sXDoDK1g9mngfDw1ZWpBt_7MDZH-g,76
|
|
5
5
|
idlib/core.py,sha256=KVhWN6yQfIGA5rG_ydNVC25oMa88lYJwQtAjzzhqziQ,4569
|
|
6
6
|
idlib/edit.py,sha256=s3yRtvNelQUA8fziu_igZeoFsW4xCK_kgfNVv3TS0iE,3635
|
|
7
7
|
idlib/exceptions.py,sha256=QC3Jq98iwezcqB7SmDr-UEOqdNCnvEXVkKB0eJLIwZs,4714
|
|
8
|
-
idlib/from_oq.py,sha256=
|
|
8
|
+
idlib/from_oq.py,sha256=AVxs7zq8GlAmHOJAu8M3Wb3R5byTc5D4X7U47PzRldM,96351
|
|
9
9
|
idlib/identifiers.py,sha256=s39bAS-fCQrlwAbMtaa7tjSnqKq4YPlfSbfJ6ju2o7I,3861
|
|
10
|
-
idlib/streams.py,sha256=
|
|
10
|
+
idlib/streams.py,sha256=spUVSCyR0gugdZxi8orhTAkUKCAT-kq7J5dyBxl5_uo,27477
|
|
11
11
|
idlib/utils.py,sha256=q2hcz0Qtbya1UpPnlGisougg9EuDZkcAKXJQIN4OFQs,5306
|
|
12
12
|
idlib/apis/__init__.py,sha256=q2-iSMUDPlYbjqGWa1mtbe2G95N7wbjWHGj30BUdVDM,88
|
|
13
13
|
idlib/apis/protocols_io.py,sha256=PKcoSbO9AqTfBYKLWJQyO3vHjug9qEL826s7jY4LWWg,4026
|
|
@@ -19,17 +19,17 @@ idlib/formats/__init__.py,sha256=yS6l0mbDwa2xjyxhgVzlqIf0LPqJmuhNVg8rfKSsh7M,528
|
|
|
19
19
|
idlib/formats/rdf.py,sha256=yIKHPaPn-SUuUMkR4VD7KffVgQD8oNaZNxcqDBilxtg,466
|
|
20
20
|
idlib/systems/__init__.py,sha256=3lWSK2DyzYX0d61DJo-gGytc-HoiOlNJl5so4s7Grrg,203
|
|
21
21
|
idlib/systems/ark.py,sha256=i9JqmuTWsJABrLHR0-_FX_PBbbpeFa7X4CO65QhyOD8,111
|
|
22
|
-
idlib/systems/doi.py,sha256=
|
|
22
|
+
idlib/systems/doi.py,sha256=5Ut8u6m4X_RWJv6yGOTM1MktrJlWnORPfYdmeMT9m_Y,13858
|
|
23
23
|
idlib/systems/handle.py,sha256=Gg97IuysdAdCX9j6EhuNfIddb1GDq0CmwW1SmuLkpgM,95
|
|
24
24
|
idlib/systems/isni.py,sha256=TgiSTlDcSBLRro3gg_YfQJQkfaJ3saw0Au1OMhE23wU,89
|
|
25
25
|
idlib/systems/orcid.py,sha256=aTVu_Q6fnaQvqmd6jeXdst6yKRTO-BEUMs7_4fdQK5E,7886
|
|
26
26
|
idlib/systems/pmid.py,sha256=Na-4_n7qmJ3VAbG0RUwnNTg7o4Z8OkuL_Hluq_A3IO0,181
|
|
27
27
|
idlib/systems/ror.py,sha256=3pZ1aLg7NUh-mHQm-qu-hqy5WrJZprtj5lWIWRpP2-M,8894
|
|
28
|
-
idlib/systems/rrid.py,sha256=
|
|
28
|
+
idlib/systems/rrid.py,sha256=BtQzrS90sAGKvnoH5CQK0URxTEw1A0hwNaEngxuGLFs,9136
|
|
29
29
|
idlib/systems/urn.py,sha256=p222KjHgfF6y9srCm7kFWuWA9NK4lI-wEQUtSeuBqYk,113
|
|
30
30
|
idlib/systems/web.py,sha256=vrSbQYWnxhe9pSgZcOqwLM3V6XQDLwv1QqWlhWWxbL0,1291
|
|
31
|
-
idlib-0.0.1.
|
|
32
|
-
idlib-0.0.1.
|
|
33
|
-
idlib-0.0.1.
|
|
34
|
-
idlib-0.0.1.
|
|
35
|
-
idlib-0.0.1.
|
|
31
|
+
idlib-0.0.1.dev24.dist-info/licenses/LICENSE,sha256=nEuJBsoHfpXGgf6ZyFGUhQJqxFWwhSYF-45pRAqTSb4,1080
|
|
32
|
+
idlib-0.0.1.dev24.dist-info/METADATA,sha256=CW7UYjKLSBcisjzs4NZ-SkT-yIXKIxryIhuOO3D-mn8,2330
|
|
33
|
+
idlib-0.0.1.dev24.dist-info/WHEEL,sha256=4YBfCYNH4wlLpv3pzq1hbEuIlXA4WJabKLFurZ7eTL0,109
|
|
34
|
+
idlib-0.0.1.dev24.dist-info/top_level.txt,sha256=xIk87gJPbeCKih9BVMP8PlEFdpcsGplenz0VQhx5sP8,6
|
|
35
|
+
idlib-0.0.1.dev24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|