deriva 1.7.7__py3-none-any.whl → 1.7.9__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.
- deriva/config/acl_config.py +2 -1
- deriva/core/__init__.py +2 -2
- deriva/core/catalog_cli.py +12 -6
- deriva/core/deriva_binding.py +7 -7
- deriva/core/ermrest_catalog.py +20 -6
- deriva/core/ermrest_model.py +1 -1
- deriva/core/utils/core_utils.py +11 -6
- deriva/core/utils/globus_auth_utils.py +41 -4
- deriva/transfer/__init__.py +2 -2
- deriva/transfer/download/deriva_export.py +12 -5
- deriva/transfer/download/processors/query/base_query_processor.py +13 -14
- deriva/transfer/download/processors/query/file_download_query_processor.py +3 -4
- deriva/transfer/upload/deriva_upload.py +26 -16
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info}/METADATA +22 -10
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info}/RECORD +19 -19
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info}/WHEEL +1 -1
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info}/entry_points.txt +0 -0
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info/licenses}/LICENSE +0 -0
- {deriva-1.7.7.dist-info → deriva-1.7.9.dist-info}/top_level.txt +0 -0
deriva/config/acl_config.py
CHANGED
|
@@ -291,7 +291,8 @@ class AclConfig:
|
|
|
291
291
|
elif group.startswith(self.ROBOT_PREFIX_FORMAT.format(server=self.server)):
|
|
292
292
|
self.validate_webauthn_robot(group)
|
|
293
293
|
else:
|
|
294
|
-
|
|
294
|
+
if self.verbose:
|
|
295
|
+
warnings.warn("Can't determine format of group '{g}'".format(g=group))
|
|
295
296
|
|
|
296
297
|
def validate_globus_group(self, group):
|
|
297
298
|
guid = group[len(self.GLOBUS_PREFIX):]
|
deriva/core/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = "1.7.
|
|
1
|
+
__version__ = "1.7.9"
|
|
2
2
|
|
|
3
3
|
from deriva.core.utils.core_utils import *
|
|
4
4
|
from deriva.core.base_cli import BaseCLI, KeyValuePairArgs
|
|
@@ -55,7 +55,7 @@ def get_credential(host,
|
|
|
55
55
|
scope_map = globus_client.hosts_to_scope_map(hosts=[host], match_scope_tag=match_scope_tag,
|
|
56
56
|
force_refresh=force_scope_lookup,
|
|
57
57
|
warn_on_discovery_failure=True if not creds else False)
|
|
58
|
-
tokens = globus_client.is_logged_in(exclude_defaults=True)
|
|
58
|
+
tokens = globus_client.is_logged_in(exclude_defaults=True, hosts_to_scope_map=scope_map)
|
|
59
59
|
if tokens:
|
|
60
60
|
# 1. look for the explicitly requested scope in the token store, if specified
|
|
61
61
|
token = globus_client.find_access_token_for_scope(requested_scope, tokens)
|
deriva/core/catalog_cli.py
CHANGED
|
@@ -6,7 +6,7 @@ import traceback
|
|
|
6
6
|
from pprint import pp
|
|
7
7
|
from requests.exceptions import HTTPError, ConnectionError
|
|
8
8
|
from deriva.core import __version__ as VERSION, BaseCLI, KeyValuePairArgs, DerivaServer, DerivaPathError, \
|
|
9
|
-
get_credential, format_credential, format_exception, DEFAULT_HEADERS
|
|
9
|
+
get_credential, format_credential, format_exception, read_config, DEFAULT_SESSION_CONFIG, DEFAULT_HEADERS
|
|
10
10
|
from deriva.core.ermrest_model import nochange
|
|
11
11
|
from deriva.core.utils import eprint
|
|
12
12
|
|
|
@@ -191,6 +191,11 @@ class DerivaCatalogCLI (BaseCLI):
|
|
|
191
191
|
else:
|
|
192
192
|
return get_credential(host_name)
|
|
193
193
|
|
|
194
|
+
@staticmethod
|
|
195
|
+
def _get_session_config():
|
|
196
|
+
config = read_config()
|
|
197
|
+
return config.get("session", DEFAULT_SESSION_CONFIG)
|
|
198
|
+
|
|
194
199
|
def _post_parser_init(self, args):
|
|
195
200
|
"""Shared initialization for all sub-commands.
|
|
196
201
|
"""
|
|
@@ -202,7 +207,8 @@ class DerivaCatalogCLI (BaseCLI):
|
|
|
202
207
|
credentials=DerivaCatalogCLI._get_credential(
|
|
203
208
|
self.host,
|
|
204
209
|
token=args.token,
|
|
205
|
-
oauth2_token=args.oauth2_token)
|
|
210
|
+
oauth2_token=args.oauth2_token),
|
|
211
|
+
session_config=DerivaCatalogCLI._get_session_config())
|
|
206
212
|
|
|
207
213
|
@staticmethod
|
|
208
214
|
def _decorate_headers(headers, file_format, method="get"):
|
|
@@ -279,10 +285,10 @@ class DerivaCatalogCLI (BaseCLI):
|
|
|
279
285
|
catalog = self.server.connect_ermrest(args.id)
|
|
280
286
|
try:
|
|
281
287
|
if args.output_file:
|
|
282
|
-
catalog.
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
288
|
+
catalog.get_as_file(args.path,
|
|
289
|
+
destfilename=args.output_file,
|
|
290
|
+
headers=headers,
|
|
291
|
+
delete_if_empty=args.auto_delete)
|
|
286
292
|
else:
|
|
287
293
|
pp(catalog.get(args.path, headers=headers).json())
|
|
288
294
|
except HTTPError as e:
|
deriva/core/deriva_binding.py
CHANGED
|
@@ -139,9 +139,10 @@ class DerivaBinding (object):
|
|
|
139
139
|
server
|
|
140
140
|
)
|
|
141
141
|
self._server_uri = self._base_server_uri
|
|
142
|
+
self._auth_uri = self._base_server_uri + "/authn/session"
|
|
142
143
|
|
|
143
|
-
self.session_config = DEFAULT_SESSION_CONFIG if not session_config else session_config
|
|
144
144
|
self._session = None
|
|
145
|
+
self.session_config = DEFAULT_SESSION_CONFIG if not session_config else session_config
|
|
145
146
|
self._get_new_session(self.session_config)
|
|
146
147
|
|
|
147
148
|
self._caching = caching
|
|
@@ -160,9 +161,6 @@ class DerivaBinding (object):
|
|
|
160
161
|
self._close_session()
|
|
161
162
|
self._session = get_new_requests_session(self._server_uri + '/',
|
|
162
163
|
session_config if session_config else self.session_config)
|
|
163
|
-
# allow loopback requests to bypass SSL cert verification
|
|
164
|
-
if "https://localhost" in self._server_uri:
|
|
165
|
-
self._session.verify = False
|
|
166
164
|
|
|
167
165
|
def _pre_get(self, path, headers):
|
|
168
166
|
self.check_path(path)
|
|
@@ -222,19 +220,21 @@ class DerivaBinding (object):
|
|
|
222
220
|
self._session.headers.update({'Authorization': 'Bearer {token}'.format(token=credentials['bearer-token'])})
|
|
223
221
|
elif 'cookie' in credentials:
|
|
224
222
|
cname, cval = credentials['cookie'].split('=', 1)
|
|
225
|
-
|
|
223
|
+
# Fix for cookielib domain rewrite to *.local when no "." in hostname. In this case, don't set the domain.
|
|
224
|
+
# Covers "localhost" and other dev/test scenarios. See "https://github.com/psf/requests/issues/5388"
|
|
225
|
+
self._session.cookies.set(cname, cval, domain="" if "." not in server else server, path='/')
|
|
226
226
|
elif 'username' in credentials and 'password' in credentials:
|
|
227
227
|
self.post_authn_session(credentials)
|
|
228
228
|
|
|
229
229
|
def get_authn_session(self):
|
|
230
230
|
headers = { 'deriva-client-context': self.dcctx.encoded() }
|
|
231
|
-
r = self._session.get(self.
|
|
231
|
+
r = self._session.get(self._auth_uri, headers=headers)
|
|
232
232
|
_response_raise_for_status(r)
|
|
233
233
|
return r
|
|
234
234
|
|
|
235
235
|
def post_authn_session(self, credentials):
|
|
236
236
|
headers = { 'deriva-client-context': self.dcctx.encoded() }
|
|
237
|
-
r = self._session.post(self.
|
|
237
|
+
r = self._session.post(self._auth_uri, data=credentials, headers=headers)
|
|
238
238
|
_response_raise_for_status(r)
|
|
239
239
|
return r
|
|
240
240
|
|
deriva/core/ermrest_catalog.py
CHANGED
|
@@ -481,12 +481,26 @@ class ErmrestCatalog(DerivaBinding):
|
|
|
481
481
|
def getAsFile(self,
|
|
482
482
|
path,
|
|
483
483
|
destfilename,
|
|
484
|
-
headers=DEFAULT_HEADERS,
|
|
485
|
-
callback=None,
|
|
486
|
-
delete_if_empty=False,
|
|
487
|
-
paged=False,
|
|
488
|
-
page_size=DEFAULT_PAGE_SIZE,
|
|
489
|
-
page_sort_columns=frozenset(["RID"])):
|
|
484
|
+
headers = DEFAULT_HEADERS,
|
|
485
|
+
callback = None,
|
|
486
|
+
delete_if_empty = False,
|
|
487
|
+
paged = False,
|
|
488
|
+
page_size = DEFAULT_PAGE_SIZE,
|
|
489
|
+
page_sort_columns = frozenset(["RID"])):
|
|
490
|
+
"""
|
|
491
|
+
Deprecated, call `get_as_file` instead.
|
|
492
|
+
"""
|
|
493
|
+
self.get_as_file(path, destfilename, headers, callback, delete_if_empty, paged, page_size, page_sort_columns)
|
|
494
|
+
|
|
495
|
+
def get_as_file(self,
|
|
496
|
+
path,
|
|
497
|
+
destfilename,
|
|
498
|
+
headers=DEFAULT_HEADERS,
|
|
499
|
+
callback=None,
|
|
500
|
+
delete_if_empty=False,
|
|
501
|
+
paged=False,
|
|
502
|
+
page_size=DEFAULT_PAGE_SIZE,
|
|
503
|
+
page_sort_columns=frozenset(["RID"])):
|
|
490
504
|
"""
|
|
491
505
|
Retrieve catalog data streamed to destination file.
|
|
492
506
|
Caller is responsible to clean up file even on error, when the file may or may not exist.
|
deriva/core/ermrest_model.py
CHANGED
|
@@ -188,7 +188,7 @@ def equivalent(doc1, doc2, method=None):
|
|
|
188
188
|
def canon_cat_acls(d):
|
|
189
189
|
return {
|
|
190
190
|
k: d.get(k, [])
|
|
191
|
-
for k in {'owner', '
|
|
191
|
+
for k in {'owner', 'enumerate', 'write', 'select', 'insert', 'update', 'delete'}
|
|
192
192
|
}
|
|
193
193
|
return equivalent(canon_cat_acls(doc1), canon_cat_acls(doc2), method='acls')
|
|
194
194
|
elif method == 'foreign_key_acls':
|
deriva/core/utils/core_utils.py
CHANGED
|
@@ -48,7 +48,8 @@ DEFAULT_SESSION_CONFIG = {
|
|
|
48
48
|
"allow_retry_on_all_methods": False,
|
|
49
49
|
"cookie_jar": DEFAULT_COOKIE_JAR_FILE,
|
|
50
50
|
"max_request_size": DEFAULT_MAX_REQUEST_SIZE,
|
|
51
|
-
"max_chunk_limit": DEFAULT_MAX_CHUNK_LIMIT
|
|
51
|
+
"max_chunk_limit": DEFAULT_MAX_CHUNK_LIMIT,
|
|
52
|
+
"bypass_cert_verify_host_list": []
|
|
52
53
|
}
|
|
53
54
|
OAUTH2_SCOPES_KEY = "oauth2_scopes"
|
|
54
55
|
DEFAULT_CONFIG = {
|
|
@@ -189,11 +190,15 @@ def get_new_requests_session(url=None, session_config=DEFAULT_SESSION_CONFIG):
|
|
|
189
190
|
not session_config.get("allow_retry_on_all_methods", False) else False,
|
|
190
191
|
raise_on_status=True)
|
|
191
192
|
adapter = TimeoutHTTPAdapter(timeout=session_config.get("timeout", DEFAULT_REQUESTS_TIMEOUT), max_retries=retries)
|
|
193
|
+
session.mount('http://', adapter)
|
|
194
|
+
session.mount('https://', adapter)
|
|
195
|
+
|
|
192
196
|
if url:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
# allow whitelisted hosts to bypass SSL cert verification
|
|
198
|
+
upr = urlparse(url)
|
|
199
|
+
bypass_cert_verify_host_list = session_config.get("bypass_cert_verify_host_list", [])
|
|
200
|
+
if upr.scheme == "https" and upr.hostname in bypass_cert_verify_host_list:
|
|
201
|
+
session.verify = False
|
|
197
202
|
|
|
198
203
|
return session
|
|
199
204
|
|
|
@@ -301,7 +306,7 @@ def get_oauth_scopes_for_host(host,
|
|
|
301
306
|
result = scopes
|
|
302
307
|
break
|
|
303
308
|
if not result or force_refresh:
|
|
304
|
-
session = get_new_requests_session(session_config=DEFAULT_SESSION_CONFIG)
|
|
309
|
+
session = get_new_requests_session(url, session_config=config.get("session", DEFAULT_SESSION_CONFIG))
|
|
305
310
|
try:
|
|
306
311
|
r = session.get(url, headers=DEFAULT_HEADERS)
|
|
307
312
|
r.raise_for_status()
|
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
import logging
|
|
6
6
|
import platform
|
|
7
7
|
import traceback
|
|
8
|
-
import
|
|
8
|
+
import time
|
|
9
9
|
import datetime
|
|
10
10
|
import tzlocal
|
|
11
11
|
import webbrowser
|
|
@@ -15,7 +15,8 @@ from bdbag.fetch.auth import keychain as bdbkc
|
|
|
15
15
|
from deriva.core import __version__ as VERSION, DEFAULT_CONFIG_PATH, DEFAULT_GLOBUS_CREDENTIAL_FILE, urlparse, urljoin,\
|
|
16
16
|
read_config, format_exception, BaseCLI, get_oauth_scopes_for_host, get_new_requests_session
|
|
17
17
|
from deriva.core.utils import eprint
|
|
18
|
-
from globus_sdk import ConfidentialAppAuthClient, AuthClient, AccessTokenAuthorizer,
|
|
18
|
+
from globus_sdk import ConfidentialAppAuthClient, AuthClient, AccessTokenAuthorizer, RefreshTokenAuthorizer, \
|
|
19
|
+
GlobusError, GlobusAPIError, AuthAPIError
|
|
19
20
|
from fair_research_login.client import NativeClient, LoadError, NoSavedTokens, TokensExpired
|
|
20
21
|
|
|
21
22
|
NATIVE_APP_CLIENT_ID = "8ef15ba9-2b4a-469c-a163-7fd910c9d111"
|
|
@@ -586,12 +587,47 @@ class GlobusNativeLogin:
|
|
|
586
587
|
if not scopes:
|
|
587
588
|
return None
|
|
588
589
|
try:
|
|
589
|
-
|
|
590
|
+
tokens = self.client.load_tokens(list(scopes))
|
|
591
|
+
return self.refresh_tokens_preemptively(tokens, time_before_expiry=86400)
|
|
590
592
|
except LoadError as e:
|
|
591
593
|
logging.debug("Unable to load or find tokens for specified scopes [%s]: %s" %
|
|
592
594
|
(scopes, format_exception(e)))
|
|
593
595
|
return None
|
|
594
596
|
|
|
597
|
+
def refresh_tokens_preemptively(self, tokens, time_before_expiry=0):
|
|
598
|
+
needs_refresh = {}
|
|
599
|
+
|
|
600
|
+
for rs, ts in {t: ts for t, ts in tokens.items() if bool(ts['refresh_token'])}.items():
|
|
601
|
+
expiry_threshold = int(time.time()) + time_before_expiry
|
|
602
|
+
if ts['expires_at_seconds'] < expiry_threshold:
|
|
603
|
+
needs_refresh.update({rs:ts})
|
|
604
|
+
|
|
605
|
+
if not needs_refresh:
|
|
606
|
+
return tokens
|
|
607
|
+
|
|
608
|
+
for rs, ts in needs_refresh.items():
|
|
609
|
+
authorizer = RefreshTokenAuthorizer(
|
|
610
|
+
ts['refresh_token'],
|
|
611
|
+
self.client.client,
|
|
612
|
+
access_token=ts['access_token'],
|
|
613
|
+
expires_at=int(time.time()),
|
|
614
|
+
# setting the expires_at to the current time is vicious hack but necessary since the globus_sdk
|
|
615
|
+
# client doesn't allow you to refresh an access token unless it has already expired
|
|
616
|
+
)
|
|
617
|
+
try:
|
|
618
|
+
authorizer.ensure_valid_token()
|
|
619
|
+
ts['access_token'] = authorizer.access_token
|
|
620
|
+
ts['expires_at_seconds'] = authorizer.expires_at
|
|
621
|
+
except AuthAPIError as e:
|
|
622
|
+
if e.message == 'invalid_grant':
|
|
623
|
+
logging.warning('Refresh Token expired for resource server: %s', rs)
|
|
624
|
+
|
|
625
|
+
self.client.save_tokens(needs_refresh)
|
|
626
|
+
result = {rs: ts for rs, ts in tokens.items() if rs not in needs_refresh}
|
|
627
|
+
result.update(needs_refresh)
|
|
628
|
+
|
|
629
|
+
return result
|
|
630
|
+
|
|
595
631
|
def hosts_to_scope_map(self,
|
|
596
632
|
hosts,
|
|
597
633
|
match_scope_tag=None,
|
|
@@ -662,6 +698,7 @@ class GlobusNativeLogin:
|
|
|
662
698
|
access_token = token.get("access_token")
|
|
663
699
|
if (token_scope == scope) and (access_token is not None):
|
|
664
700
|
return access_token
|
|
701
|
+
return None
|
|
665
702
|
|
|
666
703
|
def update_bdbag_keychain(self, token=None, host=None, keychain_file=None, allow_redirects=False, delete=False):
|
|
667
704
|
if (token is None) or (host is None):
|
|
@@ -699,7 +736,7 @@ class GlobusNativeLogin:
|
|
|
699
736
|
prefill_named_grant = self.client.app_name + " with requested scopes [%s] " % ", ".join(scopes)
|
|
700
737
|
tokens = self.client.login(no_local_server=no_local_server,
|
|
701
738
|
no_browser=no_browser,
|
|
702
|
-
requested_scopes=scopes,
|
|
739
|
+
requested_scopes=list(scopes),
|
|
703
740
|
refresh_tokens=refresh_tokens,
|
|
704
741
|
prefill_named_grant=prefill_named_grant,
|
|
705
742
|
query_params=additional_params,
|
deriva/transfer/__init__.py
CHANGED
|
@@ -4,8 +4,8 @@ from deriva.transfer.download.deriva_download import DerivaDownload, GenericDown
|
|
|
4
4
|
from deriva.transfer.download.deriva_download_cli import DerivaDownloadCLI
|
|
5
5
|
from deriva.transfer.download.deriva_export import DerivaExport, DerivaExportCLI
|
|
6
6
|
|
|
7
|
-
from deriva.transfer.upload.deriva_upload import DerivaUpload, GenericUploader,
|
|
8
|
-
DerivaUploadConfigurationError, DerivaUploadCatalogCreateError, DerivaUploadCatalogUpdateError, \
|
|
7
|
+
from deriva.transfer.upload.deriva_upload import DerivaUpload, GenericUploader, UploadState, DerivaUploadError, \
|
|
8
|
+
DerivaUploadError, DerivaUploadConfigurationError, DerivaUploadCatalogCreateError, DerivaUploadCatalogUpdateError, \
|
|
9
9
|
DerivaUploadAuthenticationError
|
|
10
10
|
from deriva.transfer.upload.deriva_upload_cli import DerivaUploadCLI
|
|
11
11
|
|
|
@@ -5,7 +5,6 @@ import traceback
|
|
|
5
5
|
import requests
|
|
6
6
|
import argparse
|
|
7
7
|
import logging
|
|
8
|
-
import certifi
|
|
9
8
|
import datetime
|
|
10
9
|
from collections.abc import Mapping, Iterable
|
|
11
10
|
from requests.exceptions import HTTPError, ConnectionError, Timeout
|
|
@@ -46,6 +45,7 @@ class DerivaExport:
|
|
|
46
45
|
self.timeout = kwargs.get("timeout")
|
|
47
46
|
self.export_type = kwargs.get("export_type", "bdbag")
|
|
48
47
|
self.base_server_uri = "https://" + self.host
|
|
48
|
+
self.auth_service_url = self.base_server_uri + "/authn/session"
|
|
49
49
|
self.service_url = self.base_server_uri + EXPORT_SERVICE_PATH % self.export_type
|
|
50
50
|
self.session_config = DEFAULT_SESSION_CONFIG.copy()
|
|
51
51
|
if isinstance(self.timeout, tuple):
|
|
@@ -78,16 +78,23 @@ class DerivaExport:
|
|
|
78
78
|
raise DerivaDownloadAuthenticationError(
|
|
79
79
|
"The requested service requires authentication and a valid login credential could "
|
|
80
80
|
"not be found (or was not provided) for the specified host.")
|
|
81
|
+
|
|
81
82
|
if 'bearer-token' in self.credential:
|
|
82
83
|
self.session.headers.update(
|
|
83
84
|
{'Authorization': 'Bearer {token}'.format(token=self.credential['bearer-token'])})
|
|
84
85
|
elif 'cookie' in self.credential:
|
|
85
86
|
cname, cval = self.credential['cookie'].split('=', 1)
|
|
86
|
-
self.session.cookies.set(cname, cval, domain=self.host, path='/')
|
|
87
|
+
self.session.cookies.set(cname, cval, domain="" if "." not in self.host else self.host, path='/')
|
|
88
|
+
else:
|
|
89
|
+
try:
|
|
90
|
+
r = self.session.post(self.auth_service_url, data=self.credential)
|
|
91
|
+
r.raise_for_status()
|
|
92
|
+
except HTTPError as e:
|
|
93
|
+
raise DerivaDownloadAuthenticationError(
|
|
94
|
+
"Exception during POST authentication flow: %s" % format_exception(e))
|
|
87
95
|
|
|
88
96
|
def validate_authn_session(self):
|
|
89
|
-
|
|
90
|
-
r = self.session.get(url)
|
|
97
|
+
r = self.session.get(self.auth_service_url)
|
|
91
98
|
if r.status_code == requests.codes.not_found or r.status_code == requests.codes.unauthorized:
|
|
92
99
|
logger.warning("Unable to authenticate. Check for missing or expired credentials.")
|
|
93
100
|
r.raise_for_status()
|
|
@@ -125,7 +132,7 @@ class DerivaExport:
|
|
|
125
132
|
|
|
126
133
|
filename = parse_content_disposition(content_disposition)
|
|
127
134
|
output_path = os.path.abspath(os.path.join(self.output_dir, filename))
|
|
128
|
-
with self.session.get(url, stream=True
|
|
135
|
+
with self.session.get(url, stream=True) as r:
|
|
129
136
|
if r.status_code != 200:
|
|
130
137
|
file_error = "File [%s] transfer failed." % output_path
|
|
131
138
|
url_error = 'HTTP GET Failed for url: %s' % url
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import errno
|
|
3
|
-
import certifi
|
|
4
3
|
import requests
|
|
5
4
|
from deriva.core import urlsplit, get_new_requests_session, stob, make_dirs, format_exception, DEFAULT_SESSION_CONFIG
|
|
6
5
|
from deriva.transfer.download import DerivaDownloadError, DerivaDownloadConfigurationError, \
|
|
@@ -72,13 +71,13 @@ class BaseQueryProcessor(BaseProcessor):
|
|
|
72
71
|
make_dirs(output_dir)
|
|
73
72
|
try:
|
|
74
73
|
if as_file:
|
|
75
|
-
return self.catalog.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
return self.catalog.get_as_file(self.query, self.output_abspath,
|
|
75
|
+
headers=headers,
|
|
76
|
+
callback=self.callback,
|
|
77
|
+
delete_if_empty=True,
|
|
78
|
+
paged=self.paged_query,
|
|
79
|
+
page_size=self.paged_query_size,
|
|
80
|
+
page_sort_columns=self.paged_query_sort_columns)
|
|
82
81
|
else:
|
|
83
82
|
return self.catalog.get(self.query, headers=headers).json()
|
|
84
83
|
except requests.HTTPError as e:
|
|
@@ -143,31 +142,31 @@ class BaseQueryProcessor(BaseProcessor):
|
|
|
143
142
|
|
|
144
143
|
return url
|
|
145
144
|
|
|
146
|
-
def getExternalSession(self,
|
|
147
|
-
sessions = self.sessions
|
|
145
|
+
def getExternalSession(self, url):
|
|
148
146
|
auth_params = self.kwargs.get("auth_params", dict())
|
|
149
147
|
cookies = auth_params.get("cookies")
|
|
150
148
|
auth_url = auth_params.get("auth_url")
|
|
151
149
|
login_params = auth_params.get("login_params")
|
|
152
150
|
session_config = self.kwargs.get("session_config")
|
|
153
151
|
|
|
154
|
-
|
|
152
|
+
host = urlsplit(url).hostname
|
|
153
|
+
session = self.sessions.get(host)
|
|
155
154
|
if session is not None:
|
|
156
155
|
return session
|
|
157
156
|
|
|
158
157
|
if not session_config:
|
|
159
158
|
session_config = DEFAULT_SESSION_CONFIG
|
|
160
|
-
session = get_new_requests_session(session_config=session_config)
|
|
159
|
+
session = get_new_requests_session(url, session_config=session_config)
|
|
161
160
|
|
|
162
161
|
if cookies:
|
|
163
162
|
session.cookies.update(cookies)
|
|
164
163
|
if login_params and auth_url:
|
|
165
|
-
r = session.post(auth_url, data=login_params
|
|
164
|
+
r = session.post(auth_url, data=login_params)
|
|
166
165
|
if r.status_code > 203:
|
|
167
166
|
raise DerivaDownloadError(
|
|
168
167
|
'GetExternalSession Failed with Status Code: %s\n%s\n' % (r.status_code, r.text))
|
|
169
168
|
|
|
170
|
-
sessions[host] = session
|
|
169
|
+
self.sessions[host] = session
|
|
171
170
|
return session
|
|
172
171
|
|
|
173
172
|
def create_default_paths(self):
|
|
@@ -4,7 +4,6 @@ import uuid
|
|
|
4
4
|
import datetime
|
|
5
5
|
import logging
|
|
6
6
|
import requests
|
|
7
|
-
import certifi
|
|
8
7
|
from bdbag import bdbag_ro as ro
|
|
9
8
|
from deriva.core import urlsplit, format_exception, get_transfer_summary, make_dirs, DEFAULT_CHUNK_SIZE
|
|
10
9
|
from deriva.core.utils.mime_utils import parse_content_disposition
|
|
@@ -32,14 +31,13 @@ class FileDownloadQueryProcessor(BaseQueryProcessor):
|
|
|
32
31
|
return self.outputs
|
|
33
32
|
|
|
34
33
|
def getExternalFile(self, url, output_path, headers=None):
|
|
35
|
-
host = urlsplit(url).netloc
|
|
36
34
|
if output_path:
|
|
37
35
|
if not headers:
|
|
38
36
|
headers = self.HEADERS.copy()
|
|
39
37
|
else:
|
|
40
38
|
headers.update(self.HEADERS)
|
|
41
|
-
session = self.getExternalSession(
|
|
42
|
-
with session.get(url, headers=headers, stream=True
|
|
39
|
+
session = self.getExternalSession(url)
|
|
40
|
+
with session.get(url, headers=headers, stream=True) as r:
|
|
43
41
|
if r.status_code != 200:
|
|
44
42
|
file_error = "File [%s] transfer failed." % output_path
|
|
45
43
|
url_error = 'HTTP GET Failed for url: %s' % url
|
|
@@ -59,6 +57,7 @@ class FileDownloadQueryProcessor(BaseQueryProcessor):
|
|
|
59
57
|
length = int(r.headers.get('Content-Length'))
|
|
60
58
|
content_type = r.headers.get("Content-Type")
|
|
61
59
|
return output_path, length, content_type
|
|
60
|
+
return None
|
|
62
61
|
|
|
63
62
|
def downloadFiles(self, input_manifest):
|
|
64
63
|
logging.info("Attempting to download file(s) based on the results of query: %s" % self.query)
|
|
@@ -157,8 +157,12 @@ class DerivaUpload(object):
|
|
|
157
157
|
|
|
158
158
|
# determine identity
|
|
159
159
|
if self.credentials:
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
try:
|
|
161
|
+
attributes = self.catalog.get_authn_session().json()
|
|
162
|
+
self.identity = attributes.get("client", self.identity)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
# not a big deal since the credential token being used could be expired
|
|
165
|
+
logger.debug("Unable to determine user identity from existing credential (may be expired): %s" % e)
|
|
162
166
|
|
|
163
167
|
# init dcctx cid to a default
|
|
164
168
|
self.set_dcctx_cid(self.dcctx_cid)
|
|
@@ -342,7 +346,7 @@ class DerivaUpload(object):
|
|
|
342
346
|
return '%s:%s' % (urlquote(schema_name), urlquote(table_name))
|
|
343
347
|
|
|
344
348
|
@staticmethod
|
|
345
|
-
def interpolateDict(src, dst,
|
|
349
|
+
def interpolateDict(src, dst, allow_none_column_list=[]):
|
|
346
350
|
if not (isinstance(src, dict) and isinstance(dst, dict)):
|
|
347
351
|
raise ValueError("Invalid input parameter type(s): (src = %s, dst = %s), expected (dict, dict)" % (
|
|
348
352
|
type(src).__name__, type(dst).__name__))
|
|
@@ -356,26 +360,27 @@ class DerivaUpload(object):
|
|
|
356
360
|
for k, v in dst.items():
|
|
357
361
|
try:
|
|
358
362
|
value = v.format(**src)
|
|
363
|
+
if k in src:
|
|
364
|
+
v_type = type(src[k])
|
|
365
|
+
value = v_type(value)
|
|
359
366
|
except KeyError:
|
|
360
367
|
value = v
|
|
361
368
|
if value:
|
|
362
369
|
if value.startswith('{') and value.endswith('}'):
|
|
363
370
|
value = None
|
|
364
371
|
dst.update({k: value})
|
|
365
|
-
# remove all None valued entries in the dest, if
|
|
366
|
-
if not
|
|
367
|
-
empty = [k for k, v in dst.items() if v is None]
|
|
368
|
-
for k in empty:
|
|
369
|
-
del dst[k]
|
|
372
|
+
# remove all None valued entries in the dest, if column is not explicitly allowed
|
|
373
|
+
dst = {k: v for k, v in dst.items() if v is not None or k in allow_none_column_list}
|
|
370
374
|
|
|
371
375
|
return dst
|
|
372
376
|
|
|
373
377
|
@staticmethod
|
|
374
|
-
def pruneDict(src, dst,
|
|
378
|
+
def pruneDict(src, dst, allow_none_column_list=[]):
|
|
375
379
|
dst = dst.copy()
|
|
376
380
|
for k in dst.keys():
|
|
377
381
|
value = src.get(k)
|
|
378
|
-
|
|
382
|
+
if value is not None or (value is None and k in allow_none_column_list):
|
|
383
|
+
dst[k] = value
|
|
379
384
|
return dst
|
|
380
385
|
|
|
381
386
|
def getCurrentConfigFilePath(self):
|
|
@@ -712,7 +717,8 @@ class DerivaUpload(object):
|
|
|
712
717
|
self.metadata["URI"] = versioned_uri
|
|
713
718
|
else:
|
|
714
719
|
self.metadata["URI"] = versioned_uri.rsplit(":")[0]
|
|
715
|
-
|
|
720
|
+
safe_overrides = asset_mapping.get("url_encoding_safe_overrides", {}).get("URI", "")
|
|
721
|
+
self.metadata["URI_urlencoded"] = urlquote(self.metadata["URI"], safe=safe_overrides)
|
|
716
722
|
|
|
717
723
|
# 7. Check for an existing record and create a new one if necessary
|
|
718
724
|
if not record:
|
|
@@ -720,7 +726,8 @@ class DerivaUpload(object):
|
|
|
720
726
|
|
|
721
727
|
# 8. Update an existing record, if necessary
|
|
722
728
|
column_map = asset_mapping.get("column_map", {})
|
|
723
|
-
|
|
729
|
+
allow_none_col_list = asset_mapping.get("allow_empty_columns_on_update", [])
|
|
730
|
+
updated_record = self.interpolateDict(self.metadata, column_map, allow_none_col_list)
|
|
724
731
|
if updated_record != record:
|
|
725
732
|
record_update_template = asset_mapping.get("record_update_template")
|
|
726
733
|
require_record_update_template = stob(asset_mapping.get("require_record_update_template", False))
|
|
@@ -778,6 +785,7 @@ class DerivaUpload(object):
|
|
|
778
785
|
"""
|
|
779
786
|
record = None
|
|
780
787
|
column_map = asset_mapping.get("column_map", {})
|
|
788
|
+
allow_none_col_list = asset_mapping.get("allow_empty_columns_on_update", [])
|
|
781
789
|
rqt = asset_mapping['record_query_template']
|
|
782
790
|
try:
|
|
783
791
|
path = rqt.format(**self.metadata)
|
|
@@ -787,14 +795,14 @@ class DerivaUpload(object):
|
|
|
787
795
|
if result:
|
|
788
796
|
record = result[0]
|
|
789
797
|
self._updateFileMetadata(record, no_overwrite=True)
|
|
790
|
-
return self.pruneDict(record, column_map), record
|
|
798
|
+
return self.pruneDict(record, column_map, allow_none_col_list), record
|
|
791
799
|
else:
|
|
792
800
|
row = self.interpolateDict(self.metadata, column_map)
|
|
793
801
|
result = self._catalogRecordCreate(self.metadata['target_table'], row)
|
|
794
802
|
if result:
|
|
795
803
|
record = result[0]
|
|
796
804
|
self._updateFileMetadata(record)
|
|
797
|
-
return self.interpolateDict(self.metadata, column_map,
|
|
805
|
+
return self.interpolateDict(self.metadata, column_map, allow_none_column_list=allow_none_col_list), record
|
|
798
806
|
|
|
799
807
|
def _urlEncodeMetadata(self, safe_overrides=None):
|
|
800
808
|
urlencoded = dict()
|
|
@@ -886,12 +894,14 @@ class DerivaUpload(object):
|
|
|
886
894
|
def _getFileHatracMetadata(self, asset_mapping):
|
|
887
895
|
try:
|
|
888
896
|
hatrac_templates = asset_mapping["hatrac_templates"]
|
|
897
|
+
# convert None values to empty strings for URI and content-disposition template replacement
|
|
898
|
+
metadata = {k: ('' if v is None else v) for k, v in self.metadata.items()}
|
|
889
899
|
# URI is required
|
|
890
|
-
self.metadata["URI"] = hatrac_templates["hatrac_uri"].format(**
|
|
900
|
+
self.metadata["URI"] = hatrac_templates["hatrac_uri"].format(**metadata)
|
|
891
901
|
# overridden content-disposition is optional
|
|
892
902
|
content_disposition = hatrac_templates.get("content-disposition")
|
|
893
903
|
if content_disposition:
|
|
894
|
-
filename = content_disposition.format(**
|
|
904
|
+
filename = content_disposition.format(**metadata)
|
|
895
905
|
else:
|
|
896
906
|
filename = urlparse(self.metadata["URI"]).path.rsplit("/", 1)[-1]
|
|
897
907
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: deriva
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.9
|
|
4
4
|
Summary: Python APIs and CLIs (Command-Line Interfaces) for the DERIVA platform.
|
|
5
5
|
Home-page: https://github.com/informatics-isi-edu/deriva-py
|
|
6
6
|
Author: USC Information Sciences Institute, Informatics Systems Research Division
|
|
@@ -25,14 +25,26 @@ Description-Content-Type: text/markdown
|
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: packaging
|
|
27
27
|
Requires-Dist: requests
|
|
28
|
-
Requires-Dist: certifi
|
|
29
28
|
Requires-Dist: pika
|
|
30
|
-
Requires-Dist: urllib3
|
|
31
|
-
Requires-Dist: portalocker
|
|
32
|
-
Requires-Dist: bdbag
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist: fair-research-login
|
|
35
|
-
Requires-Dist: fair-identifiers-client
|
|
36
|
-
Requires-Dist: jsonschema
|
|
29
|
+
Requires-Dist: urllib3<3,>=1.26.20
|
|
30
|
+
Requires-Dist: portalocker>=1.2.1
|
|
31
|
+
Requires-Dist: bdbag>=1.7.5
|
|
32
|
+
Requires-Dist: globus_sdk<4,>=3
|
|
33
|
+
Requires-Dist: fair-research-login>=0.3.1
|
|
34
|
+
Requires-Dist: fair-identifiers-client>=0.5.1
|
|
35
|
+
Requires-Dist: jsonschema>=3.1
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: author-email
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: license
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: maintainer
|
|
45
|
+
Dynamic: maintainer-email
|
|
46
|
+
Dynamic: requires-dist
|
|
47
|
+
Dynamic: requires-python
|
|
48
|
+
Dynamic: summary
|
|
37
49
|
|
|
38
50
|
For further information, visit the project [homepage](https://github.com/informatics-isi-edu/deriva-py).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
deriva/__init__.py,sha256=h-QyvMVzDNpT3jyVskcSbUVFXxGCRxieFPrvTveZG9k,64
|
|
2
2
|
deriva/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
deriva/config/acl_config.py,sha256=
|
|
3
|
+
deriva/config/acl_config.py,sha256=JK6OKJ9OEaloY2vFZzD9leA3p4yeAtc9QEVhTYEipc0,23979
|
|
4
4
|
deriva/config/annotation_config.py,sha256=sWcJnRfS5vcb85IdUOd420cmFHRyb4br5OxLCOssbec,11714
|
|
5
5
|
deriva/config/annotation_validate.py,sha256=ZN0jq6As49hfsAmWONUxAStqFG9TeYzvCmRU9TQ-zD8,5228
|
|
6
6
|
deriva/config/base_config.py,sha256=Y5sFotuAWWyo-LZvzbzVY2ZDaC-zhwbMXusgBF1OJYM,20724
|
|
@@ -8,15 +8,15 @@ deriva/config/dump_catalog_annotations.py,sha256=QzaWDLfWIAQ0eWVV11zeceWgwDBOYIe
|
|
|
8
8
|
deriva/config/rollback_annotation.py,sha256=vqrIcen-KZX8LDpu2OVNivzIHpQoQgWkZAChZJctvtk,3015
|
|
9
9
|
deriva/config/examples/group_owner_policy.json,sha256=8v3GWM1F_BWnYD9x_f6Eo4kBDvyy8g7mRqujfoEKLNc,2408
|
|
10
10
|
deriva/config/examples/self_serve_policy.json,sha256=pW-cqWz4rJNNXwY4eVZFkQ8gKCHclC9yDa22ylfcDqY,1676
|
|
11
|
-
deriva/core/__init__.py,sha256=
|
|
11
|
+
deriva/core/__init__.py,sha256=NKiBln9VluAuOX25MSfa-xDpYY86NwJY1civQ_Kg5QY,4975
|
|
12
12
|
deriva/core/annotation.py,sha256=PkAkPkxX1brQsb8_drR1Qj5QjQA5mjkpXhkq9NuZ1g8,13432
|
|
13
13
|
deriva/core/base_cli.py,sha256=78Ilf3_f2xREQb3IIj6q0jwWAiXSObZszG0JURs36lA,2902
|
|
14
|
-
deriva/core/catalog_cli.py,sha256
|
|
14
|
+
deriva/core/catalog_cli.py,sha256=CwfTf7C81SpU1J_aPsWiIbPOBAyekkIh384KUivq5H8,23550
|
|
15
15
|
deriva/core/datapath.py,sha256=w8LvPAd_DuknKxHc_YS6NUHhTY6XpCSkfa0m_xQUdZE,89068
|
|
16
|
-
deriva/core/deriva_binding.py,sha256=
|
|
16
|
+
deriva/core/deriva_binding.py,sha256=6yGXIbnayDtb9LU-JVK43zk02-aQwshrKiaLi1pru-8,13086
|
|
17
17
|
deriva/core/deriva_server.py,sha256=nsW3gwg1sIaHl3BTf-nL41AkSj3dEpcEBlatvjvN8CQ,200
|
|
18
|
-
deriva/core/ermrest_catalog.py,sha256=
|
|
19
|
-
deriva/core/ermrest_model.py,sha256=
|
|
18
|
+
deriva/core/ermrest_catalog.py,sha256=2mShQgo35DIQ-0UOEqu2VgCDTE3sUrQSWVDm1jW_tQ8,55547
|
|
19
|
+
deriva/core/ermrest_model.py,sha256=oydtO6IU54ihjWQXcq0nfCyqAFJSW2FI9Z_0FjU7Uk0,124936
|
|
20
20
|
deriva/core/hatrac_cli.py,sha256=l9QmneLRHSMiG_z9S83ea0QGVhTS3Wq1KGPEKEDpecM,14522
|
|
21
21
|
deriva/core/hatrac_store.py,sha256=NcVuO4h4hswbEAct8tTKZ1pNtXBn74Nn9TelKN_jr8Q,22323
|
|
22
22
|
deriva/core/mmo.py,sha256=dcB8akgsqbYMi22ClbVpOKVL6so8FjSDjSb6gP4_jFo,17852
|
|
@@ -44,8 +44,8 @@ deriva/core/schemas/visible_columns.schema.json,sha256=-JKqvhfKT-5btKBtzKn3p6EgY
|
|
|
44
44
|
deriva/core/schemas/visible_foreign_keys.schema.json,sha256=K-oa2qzj5EbmJCEyN6mN3vubblHENFxxbZEeQfFV_QQ,3364
|
|
45
45
|
deriva/core/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
46
|
deriva/core/utils/__init__.py,sha256=XSbGaWe44hebxYvoh5huFzZkMY6TSKPOCRSjUOvaY70,124
|
|
47
|
-
deriva/core/utils/core_utils.py,sha256=
|
|
48
|
-
deriva/core/utils/globus_auth_utils.py,sha256=
|
|
47
|
+
deriva/core/utils/core_utils.py,sha256=bMPVBG0W5-OAPcY7rXYlIfPAofmN1We6h1uyzXYnR9s,19821
|
|
48
|
+
deriva/core/utils/globus_auth_utils.py,sha256=x5Dh4PlAMIKTm4b8nKUeuCMSFn7NMgj_NqtmnS_FM0I,57366
|
|
49
49
|
deriva/core/utils/hash_utils.py,sha256=JqUYVB3jXusCQYX9fkKmweUKBC0WQi8ZI2N8m-uKygQ,2299
|
|
50
50
|
deriva/core/utils/mime_utils.py,sha256=ZT7pMjY2kQWBsgsGC3jY6kjfygdsIyiYW3BKNw_pPyg,1128
|
|
51
51
|
deriva/core/utils/version_utils.py,sha256=HWNUQAZrPXu0oGjhG6gMNm3kWtfa3nR50vfH2uQxBA0,2954
|
|
@@ -53,7 +53,7 @@ deriva/core/utils/webauthn_utils.py,sha256=rD0HQZAjUKp4NfqHQG1FhH3x7uKog2et7w7LB
|
|
|
53
53
|
deriva/seo/__init__.py,sha256=dYn48A7blbeYf40b4T3KVofrQK4u5K5MfxXWfIGloig,54
|
|
54
54
|
deriva/seo/sitemap_builder.py,sha256=Ht_AbodEERDofIoCcd4kPlrl1pVW670WN5dT4cc05LQ,13948
|
|
55
55
|
deriva/seo/sitemap_cli.py,sha256=miCqRfpSj5Dx5BfJGSd8Pi2e4OOQjotDzP_JubukhCM,2654
|
|
56
|
-
deriva/transfer/__init__.py,sha256=
|
|
56
|
+
deriva/transfer/__init__.py,sha256=VRxmElD5SIOGzrB1biUU8bP3_iXPMvJuau-9alU5oy0,1266
|
|
57
57
|
deriva/transfer/backup/__init__.py,sha256=vxsZiDLMTJQPybXT89G-07GsUoLhnItTCbLdXcDSyeA,465
|
|
58
58
|
deriva/transfer/backup/__main__.py,sha256=dT12--8C6sKGEtMhsYuy013ebXKpVnBJfhcQNlVtv6Y,361
|
|
59
59
|
deriva/transfer/backup/deriva_backup.py,sha256=IO9Tmzx6jHfUCkP-41nSsAeOFLn9T-0HwQcpRLpM_zs,5228
|
|
@@ -62,7 +62,7 @@ deriva/transfer/download/__init__.py,sha256=Pr7Zud4AFsIWwopTxeC_pupslgCG_lzycO9w
|
|
|
62
62
|
deriva/transfer/download/__main__.py,sha256=YUg7AZ07t_xaOgtfJnU_l1nkEHCCPR8sU5X-l1An6SY,363
|
|
63
63
|
deriva/transfer/download/deriva_download.py,sha256=ulFrHHEDj3oJA2pAo7MGvGyDF9rA3l8yCUoK3FMvHEk,17100
|
|
64
64
|
deriva/transfer/download/deriva_download_cli.py,sha256=wN8tyQDv1AIE_aDqjECbmkoEWN050vlEdJyteYbdgSs,3940
|
|
65
|
-
deriva/transfer/download/deriva_export.py,sha256=
|
|
65
|
+
deriva/transfer/download/deriva_export.py,sha256=zvFVUUmtQfx8cDa35YiQXjZzjWXW0tpNolDwEC9q0JU,13449
|
|
66
66
|
deriva/transfer/download/processors/__init__.py,sha256=evLp36tZn-Z_AMshdfV3JJO8w1es5owsnRN0IFJUwIo,4507
|
|
67
67
|
deriva/transfer/download/processors/base_processor.py,sha256=R6IIHSa_euv4X2Dyhd8fvQAiVYDGJTWMQtPoukHQn-Q,3837
|
|
68
68
|
deriva/transfer/download/processors/postprocess/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -71,8 +71,8 @@ deriva/transfer/download/processors/postprocess/transfer_post_processor.py,sha25
|
|
|
71
71
|
deriva/transfer/download/processors/postprocess/url_post_processor.py,sha256=s68iIYqQSZHtbv4y-fCG8pjhApAeMEG6hYcKx2Pvf5Y,2745
|
|
72
72
|
deriva/transfer/download/processors/query/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
73
|
deriva/transfer/download/processors/query/bag_fetch_query_processor.py,sha256=tiQtfuy01YgOFFD5b_sP7TGjMnt0Jqcg2gp1KNWqeLE,5645
|
|
74
|
-
deriva/transfer/download/processors/query/base_query_processor.py,sha256=
|
|
75
|
-
deriva/transfer/download/processors/query/file_download_query_processor.py,sha256=
|
|
74
|
+
deriva/transfer/download/processors/query/base_query_processor.py,sha256=LlABWacU_hCySg1dhBJnWeauay0JSGW_f2103D3nU8Y,10459
|
|
75
|
+
deriva/transfer/download/processors/query/file_download_query_processor.py,sha256=_oxaf0r6kxxS8UMc_D96YDeGGumlUICbNAzzbU5PTvw,7201
|
|
76
76
|
deriva/transfer/download/processors/transform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
deriva/transfer/download/processors/transform/base_transform_processor.py,sha256=Ddw5gsNpDANeuLvUaF4utp8psaxOtAzlgXtOg8gb-Pc,4109
|
|
78
78
|
deriva/transfer/download/processors/transform/column_transform_processor.py,sha256=X98XSwpGrw0xhSlQ4i7_EPMvqU0Zz5aZp9Dam2AgYRU,2627
|
|
@@ -87,7 +87,7 @@ deriva/transfer/restore/deriva_restore.py,sha256=s0h7cXit2USSdjrIfrj0dr7BJ0rrHHM
|
|
|
87
87
|
deriva/transfer/restore/deriva_restore_cli.py,sha256=2ViZ1Lyl5ndXPKeJFCHHGnwzkg3DfHhTuRa_bN7eJm8,5603
|
|
88
88
|
deriva/transfer/upload/__init__.py,sha256=4mlc_iUX-v7SpXzlCZmhxQtSiW5JeDGb2FX7bb1E6tY,304
|
|
89
89
|
deriva/transfer/upload/__main__.py,sha256=hqnXtGpRqPthwpO6uvrnf_TQm7McheeyOt960hStSMY,340
|
|
90
|
-
deriva/transfer/upload/deriva_upload.py,sha256=
|
|
90
|
+
deriva/transfer/upload/deriva_upload.py,sha256=CFWhvsMl9Ndw6QJYvQoOsErwQuF1wOpgqGju8G0QgTQ,61708
|
|
91
91
|
deriva/transfer/upload/deriva_upload_cli.py,sha256=-Q6xgiYabQziTQcMQdGNDAv-eLxCCHO-BCSo4umbDE4,5082
|
|
92
92
|
deriva/transfer/upload/processors/__init__.py,sha256=sMM5xdJ82UIRdB1lGMKk7ft0BgtjS2oJ0sI4SQSqiIU,2481
|
|
93
93
|
deriva/transfer/upload/processors/archive_processor.py,sha256=ID0lDwDn4vPe5nbxy6m28Ssj_TsZpK4df2xRrM6nJRQ,2015
|
|
@@ -97,6 +97,7 @@ deriva/transfer/upload/processors/metadata_update_processor.py,sha256=Hgu5huZf7Z
|
|
|
97
97
|
deriva/transfer/upload/processors/rename_processor.py,sha256=UQ-JQuQgyYCGT-fU9kHA53kPdQ20kt-2Bb486od7B14,2423
|
|
98
98
|
deriva/transfer/upload/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
99
99
|
deriva/utils/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
100
|
+
deriva-1.7.9.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
100
101
|
tests/deriva/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
101
102
|
tests/deriva/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
103
|
tests/deriva/core/test_datapath.py,sha256=0vUlQ48KYkDW5L7hzwyGAETa_40y0JmZDalk0W0fCq4,38722
|
|
@@ -108,9 +109,8 @@ tests/deriva/core/mmo/test_mmo_find.py,sha256=PcUN76sik68B3XKg0G3wHVpKcPEld_6Rtb
|
|
|
108
109
|
tests/deriva/core/mmo/test_mmo_prune.py,sha256=4pYtYL8g1BgadlewNPVpVA5lT_gV6SPTDYf04ZKzBTA,6851
|
|
109
110
|
tests/deriva/core/mmo/test_mmo_rename.py,sha256=4oSR1G3Od701Ss3AnolI1Z7CbMxKuQF2uSr2_IcoR6s,8512
|
|
110
111
|
tests/deriva/core/mmo/test_mmo_replace.py,sha256=w-66LWyiQ_ajC7Ipmhc4kAKwIloPdQELeUPsvelTdX8,8439
|
|
111
|
-
deriva-1.7.
|
|
112
|
-
deriva-1.7.
|
|
113
|
-
deriva-1.7.
|
|
114
|
-
deriva-1.7.
|
|
115
|
-
deriva-1.7.
|
|
116
|
-
deriva-1.7.7.dist-info/RECORD,,
|
|
112
|
+
deriva-1.7.9.dist-info/METADATA,sha256=QXs8Ca5GdL-Sw7SY41j0tYR5maXv16epbvoIoH6SnNU,1890
|
|
113
|
+
deriva-1.7.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
114
|
+
deriva-1.7.9.dist-info/entry_points.txt,sha256=HmYCHlgbjYQ_aZX_j4_4tApH4tDTbYtS66jKlfytbn8,850
|
|
115
|
+
deriva-1.7.9.dist-info/top_level.txt,sha256=_LHDie5-O53wFlexfrxjewpVkf04oydf3CqX5h75DXE,13
|
|
116
|
+
deriva-1.7.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|