deriva 1.7.9__tar.gz → 1.7.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. {deriva-1.7.9/deriva.egg-info → deriva-1.7.11}/PKG-INFO +2 -3
  2. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/__init__.py +1 -1
  3. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/datapath.py +57 -8
  4. deriva-1.7.11/deriva/core/utils/credenza_auth_utils.py +299 -0
  5. {deriva-1.7.9 → deriva-1.7.11/deriva.egg-info}/PKG-INFO +2 -3
  6. {deriva-1.7.9 → deriva-1.7.11}/deriva.egg-info/SOURCES.txt +2 -64
  7. {deriva-1.7.9 → deriva-1.7.11}/deriva.egg-info/entry_points.txt +1 -0
  8. {deriva-1.7.9 → deriva-1.7.11}/deriva.egg-info/requires.txt +1 -1
  9. deriva-1.7.11/pyproject.toml +3 -0
  10. {deriva-1.7.9 → deriva-1.7.11}/setup.py +3 -3
  11. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/test_datapath.py +37 -3
  12. deriva-1.7.9/.gitignore +0 -95
  13. deriva-1.7.9/CHANGELOG.md +0 -18
  14. deriva-1.7.9/deriva/seo/README.md +0 -56
  15. deriva-1.7.9/deriva/transfer/download/tests/test1.json +0 -46
  16. deriva-1.7.9/deriva/transfer/download/tests/test10.json +0 -33
  17. deriva-1.7.9/deriva/transfer/download/tests/test11.json +0 -24
  18. deriva-1.7.9/deriva/transfer/download/tests/test12.json +0 -46
  19. deriva-1.7.9/deriva/transfer/download/tests/test13.json +0 -39
  20. deriva-1.7.9/deriva/transfer/download/tests/test14.json +0 -46
  21. deriva-1.7.9/deriva/transfer/download/tests/test15.json +0 -53
  22. deriva-1.7.9/deriva/transfer/download/tests/test16.json +0 -37
  23. deriva-1.7.9/deriva/transfer/download/tests/test19.json +0 -215
  24. deriva-1.7.9/deriva/transfer/download/tests/test2.json +0 -35
  25. deriva-1.7.9/deriva/transfer/download/tests/test20.json +0 -212
  26. deriva-1.7.9/deriva/transfer/download/tests/test3.json +0 -42
  27. deriva-1.7.9/deriva/transfer/download/tests/test4.json +0 -21
  28. deriva-1.7.9/deriva/transfer/download/tests/test5.json +0 -28
  29. deriva-1.7.9/deriva/transfer/download/tests/test6.json +0 -31
  30. deriva-1.7.9/deriva/transfer/download/tests/test7.json +0 -46
  31. deriva-1.7.9/deriva/transfer/download/tests/test8.json +0 -93
  32. deriva-1.7.9/deriva/transfer/download/tests/test9.json +0 -72
  33. deriva-1.7.9/docs/BUILD.md +0 -44
  34. deriva-1.7.9/docs/Makefile +0 -20
  35. deriva-1.7.9/docs/README.md +0 -416
  36. deriva-1.7.9/docs/_static/README.txt +0 -1
  37. deriva-1.7.9/docs/api/deriva.config.rst +0 -46
  38. deriva-1.7.9/docs/api/deriva.core.rst +0 -127
  39. deriva-1.7.9/docs/api/deriva.core.utils.rst +0 -54
  40. deriva-1.7.9/docs/api/deriva.rst +0 -20
  41. deriva-1.7.9/docs/api/deriva.seo.rst +0 -15
  42. deriva-1.7.9/docs/api/deriva.transfer.backup.rst +0 -30
  43. deriva-1.7.9/docs/api/deriva.transfer.download.processors.postprocess.rst +0 -38
  44. deriva-1.7.9/docs/api/deriva.transfer.download.processors.query.rst +0 -39
  45. deriva-1.7.9/docs/api/deriva.transfer.download.processors.rst +0 -31
  46. deriva-1.7.9/docs/api/deriva.transfer.download.processors.transform.rst +0 -10
  47. deriva-1.7.9/docs/api/deriva.transfer.download.rst +0 -37
  48. deriva-1.7.9/docs/api/deriva.transfer.restore.rst +0 -29
  49. deriva-1.7.9/docs/api/deriva.transfer.rst +0 -20
  50. deriva-1.7.9/docs/api/deriva.transfer.upload.rst +0 -29
  51. deriva-1.7.9/docs/cli/commands.md +0 -10
  52. deriva-1.7.9/docs/cli/deriva-acl-config.md +0 -290
  53. deriva-1.7.9/docs/cli/deriva-annotation-config.md +0 -226
  54. deriva-1.7.9/docs/cli/deriva-annotation-validate.md +0 -212
  55. deriva-1.7.9/docs/cli/deriva-backup-cli.md +0 -121
  56. deriva-1.7.9/docs/cli/deriva-download-cli.md +0 -410
  57. deriva-1.7.9/docs/cli/deriva-hatrac-cli.md +0 -141
  58. deriva-1.7.9/docs/cli/deriva-restore-cli.md +0 -169
  59. deriva-1.7.9/docs/cli/deriva-sitemap-cli.md +0 -48
  60. deriva-1.7.9/docs/conf.py +0 -189
  61. deriva-1.7.9/docs/derivapy-catalog-snapshot.ipynb +0 -332
  62. deriva-1.7.9/docs/derivapy-catalog.ipynb +0 -164
  63. deriva-1.7.9/docs/derivapy-datapath-example-1.ipynb +0 -293
  64. deriva-1.7.9/docs/derivapy-datapath-example-2.ipynb +0 -619
  65. deriva-1.7.9/docs/derivapy-datapath-example-3.ipynb +0 -583
  66. deriva-1.7.9/docs/derivapy-datapath-example-4.ipynb +0 -2573
  67. deriva-1.7.9/docs/derivapy-datapath-update.ipynb +0 -385
  68. deriva-1.7.9/docs/get-started.ipynb +0 -117
  69. deriva-1.7.9/docs/index.rst +0 -27
  70. deriva-1.7.9/docs/install.md +0 -19
  71. deriva-1.7.9/docs/make.bat +0 -36
  72. deriva-1.7.9/docs/project-tutorial.md +0 -666
  73. deriva-1.7.9/docs/using-r.md +0 -99
  74. deriva-1.7.9/requirements_dev.txt +0 -8
  75. deriva-1.7.9/tests/deriva/core/mmo/__init__.py +0 -0
  76. {deriva-1.7.9 → deriva-1.7.11}/LICENSE +0 -0
  77. {deriva-1.7.9 → deriva-1.7.11}/README.md +0 -0
  78. {deriva-1.7.9 → deriva-1.7.11}/deriva/__init__.py +0 -0
  79. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/__init__.py +0 -0
  80. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/acl_config.py +0 -0
  81. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/annotation_config.py +0 -0
  82. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/annotation_validate.py +0 -0
  83. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/base_config.py +0 -0
  84. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/dump_catalog_annotations.py +0 -0
  85. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/examples/group_owner_policy.json +0 -0
  86. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/examples/self_serve_policy.json +0 -0
  87. {deriva-1.7.9 → deriva-1.7.11}/deriva/config/rollback_annotation.py +0 -0
  88. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/annotation.py +0 -0
  89. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/base_cli.py +0 -0
  90. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/catalog_cli.py +0 -0
  91. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/deriva_binding.py +0 -0
  92. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/deriva_server.py +0 -0
  93. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/ermrest_catalog.py +0 -0
  94. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/ermrest_model.py +0 -0
  95. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/hatrac_cli.py +0 -0
  96. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/hatrac_store.py +0 -0
  97. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/mmo.py +0 -0
  98. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/polling_ermrest_catalog.py +0 -0
  99. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/app_links.schema.json +0 -0
  100. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/asset.schema.json +0 -0
  101. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/bulk_upload.schema.json +0 -0
  102. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/chaise_config.schema.json +0 -0
  103. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/citation.schema.json +0 -0
  104. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/column_display.schema.json +0 -0
  105. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/display.schema.json +0 -0
  106. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/export.schema.json +0 -0
  107. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/export_2019.schema.json +0 -0
  108. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/foreign_key.schema.json +0 -0
  109. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/generated.schema.json +0 -0
  110. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/immutable.schema.json +0 -0
  111. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/indexing_preferences.schema.json +0 -0
  112. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/key_display.schema.json +0 -0
  113. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/non_deletable.schema.json +0 -0
  114. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/required.schema.json +0 -0
  115. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/source_definitions.schema.json +0 -0
  116. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/table_alternatives.schema.json +0 -0
  117. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/table_display.schema.json +0 -0
  118. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/visible_columns.schema.json +0 -0
  119. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/schemas/visible_foreign_keys.schema.json +0 -0
  120. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/tests/__init__.py +0 -0
  121. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/__init__.py +0 -0
  122. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/core_utils.py +0 -0
  123. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/globus_auth_utils.py +0 -0
  124. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/hash_utils.py +0 -0
  125. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/mime_utils.py +0 -0
  126. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/version_utils.py +0 -0
  127. {deriva-1.7.9 → deriva-1.7.11}/deriva/core/utils/webauthn_utils.py +0 -0
  128. {deriva-1.7.9 → deriva-1.7.11}/deriva/seo/__init__.py +0 -0
  129. {deriva-1.7.9 → deriva-1.7.11}/deriva/seo/sitemap_builder.py +0 -0
  130. {deriva-1.7.9 → deriva-1.7.11}/deriva/seo/sitemap_cli.py +0 -0
  131. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/__init__.py +0 -0
  132. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/backup/__init__.py +0 -0
  133. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/backup/__main__.py +0 -0
  134. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/backup/deriva_backup.py +0 -0
  135. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/backup/deriva_backup_cli.py +0 -0
  136. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/__init__.py +0 -0
  137. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/__main__.py +0 -0
  138. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/deriva_download.py +0 -0
  139. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/deriva_download_cli.py +0 -0
  140. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/deriva_export.py +0 -0
  141. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/__init__.py +0 -0
  142. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/base_processor.py +0 -0
  143. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/postprocess/__init__.py +0 -0
  144. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/postprocess/identifier_post_processor.py +0 -0
  145. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/postprocess/transfer_post_processor.py +0 -0
  146. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/postprocess/url_post_processor.py +0 -0
  147. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/query/__init__.py +0 -0
  148. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/query/bag_fetch_query_processor.py +0 -0
  149. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/query/base_query_processor.py +0 -0
  150. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/query/file_download_query_processor.py +0 -0
  151. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/__init__.py +0 -0
  152. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/base_transform_processor.py +0 -0
  153. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/column_transform_processor.py +0 -0
  154. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/fasta_transform_processor.py +0 -0
  155. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/format_transform_processor.py +0 -0
  156. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/geo_transform_processor.py +0 -0
  157. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/processors/transform/string_transform_processor.py +0 -0
  158. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/download/tests/__init__.py +0 -0
  159. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/restore/__init__.py +0 -0
  160. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/restore/__main__.py +0 -0
  161. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/restore/deriva_restore.py +0 -0
  162. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/restore/deriva_restore_cli.py +0 -0
  163. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/__init__.py +0 -0
  164. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/__main__.py +0 -0
  165. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/deriva_upload.py +0 -0
  166. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/deriva_upload_cli.py +0 -0
  167. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/__init__.py +0 -0
  168. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/archive_processor.py +0 -0
  169. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/base_processor.py +0 -0
  170. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/logging_processor.py +0 -0
  171. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/metadata_update_processor.py +0 -0
  172. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/processors/rename_processor.py +0 -0
  173. {deriva-1.7.9 → deriva-1.7.11}/deriva/transfer/upload/tests/__init__.py +0 -0
  174. {deriva-1.7.9 → deriva-1.7.11}/deriva/utils/__init__.py +0 -0
  175. {deriva-1.7.9 → deriva-1.7.11}/deriva.egg-info/dependency_links.txt +0 -0
  176. {deriva-1.7.9 → deriva-1.7.11}/deriva.egg-info/top_level.txt +0 -0
  177. {deriva-1.7.9 → deriva-1.7.11}/setup.cfg +0 -0
  178. {deriva-1.7.9/tests → deriva-1.7.11/tests/deriva}/__init__.py +0 -0
  179. {deriva-1.7.9/tests/deriva → deriva-1.7.11/tests/deriva/core}/__init__.py +0 -0
  180. {deriva-1.7.9/tests/deriva/core → deriva-1.7.11/tests/deriva/core/mmo}/__init__.py +0 -0
  181. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/base.py +0 -0
  182. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/test_mmo_drop.py +0 -0
  183. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/test_mmo_find.py +0 -0
  184. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/test_mmo_prune.py +0 -0
  185. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/test_mmo_rename.py +0 -0
  186. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/mmo/test_mmo_replace.py +0 -0
  187. {deriva-1.7.9 → deriva-1.7.11}/tests/deriva/core/test_ermrest_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deriva
3
- Version: 1.7.9
3
+ Version: 1.7.11
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
@@ -15,7 +15,6 @@ Classifier: Operating System :: POSIX
15
15
  Classifier: Operating System :: MacOS :: MacOS X
16
16
  Classifier: Operating System :: Microsoft :: Windows
17
17
  Classifier: Programming Language :: Python
18
- Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
@@ -28,7 +27,7 @@ Requires-Dist: requests
28
27
  Requires-Dist: pika
29
28
  Requires-Dist: urllib3<3,>=1.26.20
30
29
  Requires-Dist: portalocker>=1.2.1
31
- Requires-Dist: bdbag>=1.7.5
30
+ Requires-Dist: bdbag>=1.8.0
32
31
  Requires-Dist: globus_sdk<4,>=3
33
32
  Requires-Dist: fair-research-login>=0.3.1
34
33
  Requires-Dist: fair-identifiers-client>=0.5.1
@@ -1,4 +1,4 @@
1
- __version__ = "1.7.9"
1
+ __version__ = "1.7.11"
2
2
 
3
3
  from deriva.core.utils.core_utils import *
4
4
  from deriva.core.base_cli import BaseCLI, KeyValuePairArgs
@@ -11,7 +11,8 @@ from requests import HTTPError
11
11
  import warnings
12
12
  from . import DEFAULT_HEADERS, ermrest_model as _erm
13
13
 
14
- __all__ = ['DataPathException', 'Min', 'Max', 'Sum', 'Avg', 'Cnt', 'CntD', 'Array', 'ArrayD', 'Bin']
14
+ __all__ = ['DataPathException', 'Min', 'Max', 'Sum', 'Avg', 'Cnt', 'CntD', 'Array', 'ArrayD', 'Bin', 'All', 'Any',
15
+ 'simple_denormalization', 'simple_denormalization_with_whole_entities']
15
16
 
16
17
  logger = logging.getLogger(__name__)
17
18
  """Logger for this module"""
@@ -1265,6 +1266,19 @@ class _ColumnWrapper (object):
1265
1266
 
1266
1267
  __eq__ = eq
1267
1268
 
1269
+ def ne(self, other):
1270
+ """Returns a 'not equal' comparison predicate.
1271
+
1272
+ :param other: `None` or any other literal value.
1273
+ :return: a filter predicate object
1274
+ """
1275
+ if other is None:
1276
+ return _ComparisonPredicate(self, "::null::", '').negate()
1277
+ else:
1278
+ return _ComparisonPredicate(self, "=", other).negate()
1279
+
1280
+ __ne__ = ne
1281
+
1268
1282
  def lt(self, other):
1269
1283
  """Returns a 'less than' comparison predicate.
1270
1284
 
@@ -1311,8 +1325,6 @@ class _ColumnWrapper (object):
1311
1325
  :param other: a _string_ literal value.
1312
1326
  :return: a filter predicate object
1313
1327
  """
1314
- if not isinstance(other, str):
1315
- logger.warning("'regexp' method comparison only supports string literals.")
1316
1328
  return _ComparisonPredicate(self, "::regexp::", other)
1317
1329
 
1318
1330
  def ciregexp(self, other):
@@ -1321,8 +1333,6 @@ class _ColumnWrapper (object):
1321
1333
  :param other: a _string_ literal value.
1322
1334
  :return: a filter predicate object
1323
1335
  """
1324
- if not isinstance(other, str):
1325
- logger.warning("'ciregexp' method comparison only supports string literals.")
1326
1336
  return _ComparisonPredicate(self, "::ciregexp::", other)
1327
1337
 
1328
1338
  def ts(self, other):
@@ -1331,8 +1341,6 @@ class _ColumnWrapper (object):
1331
1341
  :param other: a _string_ literal value.
1332
1342
  :return: a filter predicate object
1333
1343
  """
1334
- if not isinstance(other, str):
1335
- logger.warning("'ts' method comparison only supports string literals.")
1336
1344
  return _ComparisonPredicate(self, "::ts::", other)
1337
1345
 
1338
1346
  def alias(self, name):
@@ -1395,6 +1403,16 @@ class _ColumnAlias (object):
1395
1403
 
1396
1404
  __eq__ = eq
1397
1405
 
1406
+ def ne(self, other):
1407
+ """Returns a 'not equal' comparison predicate.
1408
+
1409
+ :param other: `None` or any other literal value.
1410
+ :return: a filter predicate object
1411
+ """
1412
+ return self._base_column.ne(other)
1413
+
1414
+ __ne__ = ne
1415
+
1398
1416
  def lt(self, other):
1399
1417
  """Returns a 'less than' comparison predicate.
1400
1418
 
@@ -1713,7 +1731,7 @@ class _ComparisonPredicate (_Predicate):
1713
1731
  assert isinstance(lop, _ColumnWrapper)
1714
1732
  assert isinstance(rop, _ColumnWrapper) or isinstance(rop, int) or \
1715
1733
  isinstance(rop, float) or isinstance(rop, str) or \
1716
- isinstance(rop, date)
1734
+ isinstance(rop, date) or isinstance(rop, _Quantifier)
1717
1735
  assert isinstance(op, str)
1718
1736
  self._lop = lop
1719
1737
  self._op = op
@@ -1739,6 +1757,9 @@ class _ComparisonPredicate (_Predicate):
1739
1757
  if isinstance(self._rop, _ColumnWrapper):
1740
1758
  # The only valid circumstance for a _ColumnWrapper rop is in a link 'on' predicate for simple key/fkey joins
1741
1759
  return "(%s)=(%s)" % (self._lop._instancename, self._rop._fqname)
1760
+ elif isinstance(self._rop, _Quantifier):
1761
+ # Quantifiers can be trusted to properly urlquote their literals
1762
+ return "%s%s%s" % (self._lop._instancename, self._op, str(self._rop))
1742
1763
  else:
1743
1764
  # All other comparisons are serialized per the usual form
1744
1765
  return "%s%s%s" % (self._lop._instancename, self._op, urlquote(str(self._rop)))
@@ -1810,6 +1831,34 @@ class _NegationPredicate (_Predicate):
1810
1831
  return "!(%s)" % self._child
1811
1832
 
1812
1833
 
1834
+ class _Quantifier (object):
1835
+ """Base class of quantifiers."""
1836
+ def __init__(self, quantifier_name, *args):
1837
+ """Initializes the quantifier object.
1838
+
1839
+ :param quantifier_name: name of the quantifier per ERMrest specification.
1840
+ :param args: arguments of the quantifier per ERMrest specification.
1841
+ """
1842
+ super(_Quantifier, self).__init__()
1843
+ self._quantifier_name = quantifier_name
1844
+ self._args = args
1845
+
1846
+ def __str__(self):
1847
+ return "%s(%s)" % (self._quantifier_name, ','.join([urlquote(str(arg)) for arg in self._args]))
1848
+
1849
+
1850
+ class All (_Quantifier):
1851
+ """Universal quantifier."""
1852
+ def __init__(self, *args):
1853
+ super(All, self).__init__('all', *args)
1854
+
1855
+
1856
+ class Any (_Quantifier):
1857
+ """Existential quantifier."""
1858
+ def __init__(self, *args):
1859
+ super(Any, self).__init__('any', *args)
1860
+
1861
+
1813
1862
  class AggregateFunction (object):
1814
1863
  """Base class of all aggregate functions."""
1815
1864
  def __init__(self, fn_name, arg):
@@ -0,0 +1,299 @@
1
+ import sys
2
+ import json
3
+ import logging
4
+ import traceback
5
+ from pprint import pprint
6
+ from requests.exceptions import HTTPError, ConnectionError
7
+ from bdbag.fetch.auth import keychain as bdbkc
8
+ from deriva.core import DEFAULT_CREDENTIAL_FILE, read_credential, write_credential, format_exception, BaseCLI, \
9
+ get_new_requests_session, urlparse, urljoin
10
+ from deriva.core.utils import eprint
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def host_to_url(host, path="/", protocol="https"):
16
+ if not host:
17
+ return None
18
+ upr = urlparse(host)
19
+ if upr.scheme and upr.netloc:
20
+ url = urljoin(host, path)
21
+ else:
22
+ url = "%s://%s%s" % (protocol, host, path if not host.endswith("/") else "")
23
+ return url.lower()
24
+
25
+ class UsageException(ValueError):
26
+ """Usage exception.
27
+ """
28
+ def __init__(self, message):
29
+ """Initializes the exception.
30
+ """
31
+ super(UsageException, self).__init__(message)
32
+
33
+ class CredenzaAuthUtilCLI(BaseCLI):
34
+ """CredenzaAuthUtil Command-line Interface.
35
+ """
36
+ def __init__(self, *args, **kwargs):
37
+ super(CredenzaAuthUtilCLI, self).__init__(*args, **kwargs)
38
+ self.remove_options(['--token', '--oauth2-token'])
39
+ self.parser.add_argument("--pretty", "-p", action="store_true",
40
+ help="Pretty-print all result output.")
41
+ self.credentials = None
42
+
43
+ # init subparsers and corresponding functions
44
+ self.subparsers = self.parser.add_subparsers(title='sub-commands', dest='subcmd')
45
+ self.login_init()
46
+ self.logout_init()
47
+ self.get_session_init()
48
+ self.put_session_init()
49
+
50
+ @staticmethod
51
+ def update_bdbag_keychain(token=None, host=None, keychain_file=None, allow_redirects=False, delete=False):
52
+ if (token is None) or (host is None):
53
+ return
54
+ keychain_file = keychain_file or bdbkc.DEFAULT_KEYCHAIN_FILE
55
+ entry = {
56
+ "uri": host_to_url(host),
57
+ "auth_type": "bearer-token",
58
+ "auth_params": {
59
+ "token": token,
60
+ "allow_redirects_with_token": True if allow_redirects else False
61
+ }
62
+ }
63
+ bdbkc.update_keychain(entry, keychain_file=keychain_file, delete=delete)
64
+
65
+ def load_credential(self, host, credential_file=None):
66
+ if not self.credentials:
67
+ self.credentials = read_credential(credential_file or DEFAULT_CREDENTIAL_FILE, create_default=True)
68
+ credential = self.credentials.get(host, self.credentials.get(host.lower()))
69
+ if not credential:
70
+ return None
71
+ return credential.get("bearer-token")
72
+
73
+ def save_credential(self, host, credential_file=None, credential=None):
74
+ if not self.credentials:
75
+ self.credentials = read_credential(credential_file or DEFAULT_CREDENTIAL_FILE, create_default=True)
76
+
77
+ if credential is not None:
78
+ self.credentials[host] = {"bearer-token": credential}
79
+ else:
80
+ self.credentials.pop(host, None)
81
+
82
+ write_credential(credential_file or DEFAULT_CREDENTIAL_FILE, self.credentials)
83
+
84
+ def get_session(self, args, check_only=False):
85
+ credential = self.load_credential(args.host, args.credential_file)
86
+ if not credential:
87
+ return None if check_only else "Credential not found. Login required."
88
+
89
+ url = host_to_url(args.host, "/authn/session")
90
+ session = get_new_requests_session(url)
91
+ session.headers.update({"Authorization": f"Bearer {credential}"})
92
+ response = session.get(url)
93
+
94
+ if response.status_code == 200:
95
+ return response.json()
96
+ elif response.status_code == 404:
97
+ return None if check_only else f"No valid session found for host '{args.host}'."
98
+ else:
99
+ response.raise_for_status()
100
+ return None
101
+
102
+ def put_session(self, args):
103
+ credential = self.load_credential(args.host, args.credential_file)
104
+ if not credential:
105
+ return "Credential not found. Login required."
106
+
107
+ path = "/authn/session"
108
+ if args.refresh_upstream:
109
+ path += "?refresh_upstream=true"
110
+ url = host_to_url(args.host, path)
111
+ session = get_new_requests_session(url)
112
+ session.headers.update({"Authorization": f"Bearer {credential}"})
113
+ response = session.put(url)
114
+
115
+ if response.status_code == 200:
116
+ return response.json()
117
+ elif response.status_code == 404:
118
+ return f"No valid session found for host '{args.host}'."
119
+ else:
120
+ response.raise_for_status()
121
+ return None
122
+
123
+ def login(self, args):
124
+
125
+ if not sys.stdin.isatty():
126
+ raise RuntimeError("Interactive TTY required for device login.")
127
+
128
+ if not args.force:
129
+ resp = self.get_session(args, check_only=True)
130
+ if resp:
131
+ return f"You are already logged in to host '{args.host}'"
132
+
133
+ path = "/authn/device/start"
134
+ if args.refresh:
135
+ path += "?refresh=true"
136
+ url = host_to_url(args.host, path)
137
+ session = get_new_requests_session(url)
138
+ response = session.post(url)
139
+ response.raise_for_status()
140
+ body = response.json()
141
+ verification_url = body["verification_uri"]
142
+
143
+ login_prompt = f"""
144
+
145
+ Device login initiated to {args.host}.
146
+
147
+ 1. Please visit {verification_url} in a browser to complete authentication.
148
+ 2. After that, return here and enter "y" or "yes" at the prompt below to proceed.
149
+
150
+ """
151
+ sys.stdout.write(login_prompt)
152
+ sys.stdout.flush()
153
+ try:
154
+ while True:
155
+ sys.stdout.write("\nProceed? (y/N): ")
156
+ sys.stdout.flush()
157
+ response = sys.stdin.readline()
158
+
159
+ ans = response.strip().lower()
160
+ if ans in {"y", "yes"}:
161
+ break
162
+ elif ans in {"n", "no", ""}: # default is No on empty/enter
163
+ return f"Login cancelled for '{args.host}'."
164
+ except KeyboardInterrupt:
165
+ sys.stdout.write("\nCancelled by user (Ctrl-C).\n")
166
+ return f"Login cancelled for '{args.host}'."
167
+
168
+ token_response = session.post(
169
+ f"https://{args.host}/authn/device/token",
170
+ json={"device_code": body["device_code"]}
171
+ )
172
+ token_response.raise_for_status()
173
+ body = token_response.json()
174
+ token = body["access_token"]
175
+ self.save_credential(args.host, args.credential_file, token)
176
+ if not args.no_bdbag_keychain:
177
+ self.update_bdbag_keychain(host=args.host,
178
+ token=token,
179
+ keychain_file=args.bdbag_keychain_file or bdbkc.DEFAULT_KEYCHAIN_FILE)
180
+ token_display = f"Access token: {token}" if args.show_token else ""
181
+ return f"You have been successfully logged in to host '{args.host}'. {token_display}"
182
+
183
+ def logout(self, args):
184
+ credential = self.load_credential(args.host, args.credential_file)
185
+ if not credential:
186
+ return "Credential not found. Not logged in."
187
+
188
+ url = host_to_url(args.host, "/authn/device/logout")
189
+ session = get_new_requests_session(url)
190
+ session.headers.update({"Authorization": f"Bearer {credential}"})
191
+ response = session.post(url)
192
+ response.raise_for_status()
193
+
194
+ self.save_credential(args.host, args.credential_file)
195
+ if not args.no_bdbag_keychain:
196
+ self.update_bdbag_keychain(host=args.host,
197
+ token=credential,
198
+ delete=True,
199
+ keychain_file=args.bdbag_keychain_file or bdbkc.DEFAULT_KEYCHAIN_FILE)
200
+
201
+ return f"You have been successfully logged out of host '{args.host}'."
202
+
203
+ def login_init(self):
204
+ parser = self.subparsers.add_parser('login',
205
+ help="Login with Globus Auth and get OAuth tokens for resource access.")
206
+
207
+ parser.add_argument("--no-bdbag-keychain", action="store_true",
208
+ help="Do not update the bdbag keychain file with result access tokens. Default false.")
209
+ parser.add_argument('--bdbag-keychain-file', metavar='<file>',
210
+ help="Non-default path to a bdbag keychain file.")
211
+ parser.add_argument("--refresh", action="store_true",
212
+ help="Allow the session manager to automatically refresh access tokens on the user's behalf "
213
+ "until either the refresh token expires or the user logs out.")
214
+ parser.add_argument("--force", action="store_true",
215
+ help="Force a login flow even if the current access token is valid.")
216
+ parser.add_argument("--show-token", action="store_true",
217
+ help="Display the token from the authorization response.")
218
+ parser.set_defaults(func=self.login)
219
+
220
+ def logout_init(self):
221
+ parser = self.subparsers.add_parser("logout", help="Logout and revoke all access and refresh tokens.")
222
+ parser.add_argument("--no-bdbag-keychain", action="store_true",
223
+ help="Do not update the bdbag keychain file by removing access tokens on logout. Default false.")
224
+ parser.add_argument('--bdbag-keychain-file', metavar='<file>',
225
+ help="Non-default path to a bdbag keychain file.")
226
+ parser.set_defaults(func=self.logout)
227
+
228
+ def get_session_init(self):
229
+ parser = self.subparsers.add_parser("get-session",
230
+ help="Retrieve information about the currently logged-in user.")
231
+ parser.set_defaults(func=self.get_session)
232
+
233
+ def put_session_init(self):
234
+ parser = self.subparsers.add_parser("put-session",
235
+ help="Extend the current logged-in user's session.")
236
+ parser.add_argument("--refresh-upstream", action="store_true",
237
+ help="Attempt to refresh access tokens, other dependent tokens, and claims from the "
238
+ "upstream identity provider.")
239
+ parser.set_defaults(func=self.put_session)
240
+
241
+ def main(self):
242
+ args = self.parse_cli()
243
+
244
+ def _cmd_error_message(emsg):
245
+ return "{prog} {subcmd}: {msg}".format(
246
+ prog=self.parser.prog, subcmd=args.subcmd, msg=emsg)
247
+
248
+ try:
249
+ if not hasattr(args, 'func'):
250
+ self.parser.print_usage()
251
+ return 2
252
+
253
+ if args.subcmd == "login" or args.subcmd == "logout" or args.subcmd == "session":
254
+ pass
255
+ else:
256
+ pass
257
+
258
+ response = args.func(args)
259
+ if args.pretty:
260
+ if isinstance(response, dict) or isinstance(response, list):
261
+ try:
262
+ print(json.dumps(response, indent=2))
263
+ return 0
264
+ except:
265
+ pprint(response)
266
+ return 0
267
+ elif not isinstance(response, str):
268
+ pprint(response)
269
+ return 0
270
+ print(response)
271
+ return 0
272
+
273
+ except UsageException as e:
274
+ eprint("{prog} {subcmd}: {msg}".format(prog=self.parser.prog, subcmd=args.subcmd, msg=e))
275
+ except ConnectionError as e:
276
+ eprint("{prog}: Connection error occurred".format(prog=self.parser.prog))
277
+ except HTTPError as e:
278
+ if 401 == e.response.status_code:
279
+ msg = 'Authentication required: %s' % format_exception(e)
280
+ elif 403 == e.response.status_code:
281
+ msg = 'Permission denied: %s' % format_exception(e)
282
+ else:
283
+ msg = e
284
+ eprint(_cmd_error_message(msg))
285
+ except RuntimeError as e:
286
+ logging.debug(format_exception(e))
287
+ eprint('An unexpected runtime error occurred')
288
+ except:
289
+ eprint('An unexpected error occurred')
290
+ traceback.print_exc()
291
+ return 1
292
+
293
+ def main():
294
+ desc = "Credenza Auth Utilities"
295
+ info = "For more information see: https://github.com/informatics-isi-edu/deriva-py"
296
+ return CredenzaAuthUtilCLI(desc, info).main()
297
+
298
+ if __name__ == '__main__':
299
+ sys.exit(main())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deriva
3
- Version: 1.7.9
3
+ Version: 1.7.11
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
@@ -15,7 +15,6 @@ Classifier: Operating System :: POSIX
15
15
  Classifier: Operating System :: MacOS :: MacOS X
16
16
  Classifier: Operating System :: Microsoft :: Windows
17
17
  Classifier: Programming Language :: Python
18
- Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
@@ -28,7 +27,7 @@ Requires-Dist: requests
28
27
  Requires-Dist: pika
29
28
  Requires-Dist: urllib3<3,>=1.26.20
30
29
  Requires-Dist: portalocker>=1.2.1
31
- Requires-Dist: bdbag>=1.7.5
30
+ Requires-Dist: bdbag>=1.8.0
32
31
  Requires-Dist: globus_sdk<4,>=3
33
32
  Requires-Dist: fair-research-login>=0.3.1
34
33
  Requires-Dist: fair-identifiers-client>=0.5.1
@@ -1,8 +1,6 @@
1
- .gitignore
2
- CHANGELOG.md
3
1
  LICENSE
4
2
  README.md
5
- requirements_dev.txt
3
+ pyproject.toml
6
4
  setup.cfg
7
5
  setup.py
8
6
  deriva/__init__.py
@@ -58,12 +56,12 @@ deriva/core/schemas/visible_foreign_keys.schema.json
58
56
  deriva/core/tests/__init__.py
59
57
  deriva/core/utils/__init__.py
60
58
  deriva/core/utils/core_utils.py
59
+ deriva/core/utils/credenza_auth_utils.py
61
60
  deriva/core/utils/globus_auth_utils.py
62
61
  deriva/core/utils/hash_utils.py
63
62
  deriva/core/utils/mime_utils.py
64
63
  deriva/core/utils/version_utils.py
65
64
  deriva/core/utils/webauthn_utils.py
66
- deriva/seo/README.md
67
65
  deriva/seo/__init__.py
68
66
  deriva/seo/sitemap_builder.py
69
67
  deriva/seo/sitemap_cli.py
@@ -95,24 +93,6 @@ deriva/transfer/download/processors/transform/format_transform_processor.py
95
93
  deriva/transfer/download/processors/transform/geo_transform_processor.py
96
94
  deriva/transfer/download/processors/transform/string_transform_processor.py
97
95
  deriva/transfer/download/tests/__init__.py
98
- deriva/transfer/download/tests/test1.json
99
- deriva/transfer/download/tests/test10.json
100
- deriva/transfer/download/tests/test11.json
101
- deriva/transfer/download/tests/test12.json
102
- deriva/transfer/download/tests/test13.json
103
- deriva/transfer/download/tests/test14.json
104
- deriva/transfer/download/tests/test15.json
105
- deriva/transfer/download/tests/test16.json
106
- deriva/transfer/download/tests/test19.json
107
- deriva/transfer/download/tests/test2.json
108
- deriva/transfer/download/tests/test20.json
109
- deriva/transfer/download/tests/test3.json
110
- deriva/transfer/download/tests/test4.json
111
- deriva/transfer/download/tests/test5.json
112
- deriva/transfer/download/tests/test6.json
113
- deriva/transfer/download/tests/test7.json
114
- deriva/transfer/download/tests/test8.json
115
- deriva/transfer/download/tests/test9.json
116
96
  deriva/transfer/restore/__init__.py
117
97
  deriva/transfer/restore/__main__.py
118
98
  deriva/transfer/restore/deriva_restore.py
@@ -129,48 +109,6 @@ deriva/transfer/upload/processors/metadata_update_processor.py
129
109
  deriva/transfer/upload/processors/rename_processor.py
130
110
  deriva/transfer/upload/tests/__init__.py
131
111
  deriva/utils/__init__.py
132
- docs/BUILD.md
133
- docs/Makefile
134
- docs/README.md
135
- docs/conf.py
136
- docs/derivapy-catalog-snapshot.ipynb
137
- docs/derivapy-catalog.ipynb
138
- docs/derivapy-datapath-example-1.ipynb
139
- docs/derivapy-datapath-example-2.ipynb
140
- docs/derivapy-datapath-example-3.ipynb
141
- docs/derivapy-datapath-example-4.ipynb
142
- docs/derivapy-datapath-update.ipynb
143
- docs/get-started.ipynb
144
- docs/index.rst
145
- docs/install.md
146
- docs/make.bat
147
- docs/project-tutorial.md
148
- docs/using-r.md
149
- docs/_static/README.txt
150
- docs/api/deriva.config.rst
151
- docs/api/deriva.core.rst
152
- docs/api/deriva.core.utils.rst
153
- docs/api/deriva.rst
154
- docs/api/deriva.seo.rst
155
- docs/api/deriva.transfer.backup.rst
156
- docs/api/deriva.transfer.download.processors.postprocess.rst
157
- docs/api/deriva.transfer.download.processors.query.rst
158
- docs/api/deriva.transfer.download.processors.rst
159
- docs/api/deriva.transfer.download.processors.transform.rst
160
- docs/api/deriva.transfer.download.rst
161
- docs/api/deriva.transfer.restore.rst
162
- docs/api/deriva.transfer.rst
163
- docs/api/deriva.transfer.upload.rst
164
- docs/cli/commands.md
165
- docs/cli/deriva-acl-config.md
166
- docs/cli/deriva-annotation-config.md
167
- docs/cli/deriva-annotation-validate.md
168
- docs/cli/deriva-backup-cli.md
169
- docs/cli/deriva-download-cli.md
170
- docs/cli/deriva-hatrac-cli.md
171
- docs/cli/deriva-restore-cli.md
172
- docs/cli/deriva-sitemap-cli.md
173
- tests/__init__.py
174
112
  tests/deriva/__init__.py
175
113
  tests/deriva/core/__init__.py
176
114
  tests/deriva/core/test_datapath.py
@@ -6,6 +6,7 @@ deriva-annotation-rollback = deriva.config.rollback_annotation:main
6
6
  deriva-annotation-validate = deriva.config.annotation_validate:main
7
7
  deriva-backup-cli = deriva.transfer.backup.__main__:main
8
8
  deriva-catalog-cli = deriva.core.catalog_cli:main
9
+ deriva-credenza-auth-utils = deriva.core.utils.credenza_auth_utils:main
9
10
  deriva-download-cli = deriva.transfer.download.__main__:main
10
11
  deriva-export-cli = deriva.transfer.download.deriva_export:main
11
12
  deriva-globus-auth-utils = deriva.core.utils.globus_auth_utils:main
@@ -3,7 +3,7 @@ requests
3
3
  pika
4
4
  urllib3<3,>=1.26.20
5
5
  portalocker>=1.2.1
6
- bdbag>=1.7.5
6
+ bdbag>=1.8.0
7
7
  globus_sdk<4,>=3
8
8
  fair-research-login>=0.3.1
9
9
  fair-identifiers-client>=0.5.1
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -58,7 +58,8 @@ setup(
58
58
  'deriva-sitemap-cli = deriva.seo.sitemap_cli:main',
59
59
  'deriva-backup-cli = deriva.transfer.backup.__main__:main',
60
60
  'deriva-restore-cli = deriva.transfer.restore.__main__:main',
61
- 'deriva-globus-auth-utils = deriva.core.utils.globus_auth_utils:main'
61
+ 'deriva-globus-auth-utils = deriva.core.utils.globus_auth_utils:main',
62
+ 'deriva-credenza-auth-utils = deriva.core.utils.credenza_auth_utils:main'
62
63
  ]
63
64
  },
64
65
  install_requires=[
@@ -67,7 +68,7 @@ setup(
67
68
  'pika',
68
69
  'urllib3>=1.26.20,<3',
69
70
  'portalocker>=1.2.1',
70
- 'bdbag>=1.7.5',
71
+ 'bdbag>=1.8.0',
71
72
  'globus_sdk>=3,<4',
72
73
  'fair-research-login>=0.3.1',
73
74
  'fair-identifiers-client>=0.5.1',
@@ -82,7 +83,6 @@ setup(
82
83
  'Operating System :: MacOS :: MacOS X',
83
84
  'Operating System :: Microsoft :: Windows',
84
85
  'Programming Language :: Python',
85
- 'Programming Language :: Python :: 3.8',
86
86
  'Programming Language :: Python :: 3.9',
87
87
  'Programming Language :: Python :: 3.10',
88
88
  'Programming Language :: Python :: 3.11',