dsi-workflow 1.2.7__tar.gz → 1.2.8__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 (105) hide show
  1. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/PKG-INFO +1 -1
  2. dsi_workflow-1.2.8/dsi/_version.py +1 -0
  3. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/denodo.py +29 -1
  4. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/duckdb.py +4 -5
  5. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/ndp.py +29 -1
  6. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/oceans11.py +29 -1
  7. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/osti.py +29 -1
  8. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/rcsbpdb.py +88 -57
  9. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/sqlite.py +3 -4
  10. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_oceans11.py +15 -13
  11. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_osti.py +54 -41
  12. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/webserver.py +4 -0
  13. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/zenodo.py +29 -0
  14. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/core.py +68 -65
  15. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/dsi.py +72 -49
  16. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/sync.py +29 -29
  17. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/dsi_vcs.py +1 -1
  18. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/plots/plot-commit-diff.py +2 -2
  19. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task2_dsivcs_tests.py +1 -1
  20. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task2_git_tests.py +2 -2
  21. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/vcs_metadata_helper.py +1 -1
  22. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/PKG-INFO +1 -1
  23. dsi_workflow-1.2.7/dsi/_version.py +0 -1
  24. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/README.rst +0 -0
  25. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/__init__.py +0 -0
  26. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/backend.py +0 -0
  27. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/filesystem.py +0 -0
  28. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/gufi.py +0 -0
  29. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/hpss.py +0 -0
  30. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/sqlalchemy.py +0 -0
  31. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_denodo.py +0 -0
  32. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_duckdb.py +0 -0
  33. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_gufi.py +0 -0
  34. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_hpss.py +0 -0
  35. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_ndp.py +0 -0
  36. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_rcsbpdb.py +0 -0
  37. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_sqlalchemy.py +0 -0
  38. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_sqlite.py +0 -0
  39. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/backends/tests/test_zenodo.py +0 -0
  40. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/cli.py +0 -0
  41. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/dsi_scout.py +0 -0
  42. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/dsifederated.py +0 -0
  43. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/collection_reader.py +0 -0
  44. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/dashboard.py +0 -0
  45. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/env.py +0 -0
  46. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/file_reader.py +0 -0
  47. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/file_writer.py +0 -0
  48. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/metadata.py +0 -0
  49. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/ml_emulator.py +0 -0
  50. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/plugin.py +0 -0
  51. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/plugin_models.py +0 -0
  52. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/tests/test_collection_reader.py +0 -0
  53. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/tests/test_env.py +0 -0
  54. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/tests/test_file_reader.py +0 -0
  55. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/tests/test_file_writer.py +0 -0
  56. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/plugins/vtk_reader.py +0 -0
  57. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/tests/test_core.py +0 -0
  58. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/tests/test_dsi.py +0 -0
  59. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/__init__.py +0 -0
  60. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/dsi_utils.py +0 -0
  61. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/federated/__init__.py +0 -0
  62. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/federated/catalog_walk.py +0 -0
  63. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/federated/federate_datasets.py +0 -0
  64. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/federated/source_entry.py +0 -0
  65. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/federation_utils.py +0 -0
  66. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/git_utils.py +0 -0
  67. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/hpc_kerberos.py +0 -0
  68. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/hpc_schema_crosswalk.json +0 -0
  69. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/rsync_utils.py +0 -0
  70. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/s3_utils.py +0 -0
  71. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/__init__.py +0 -0
  72. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/__main__.py +0 -0
  73. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/cli.py +0 -0
  74. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/plots/plot-add-commit.py +0 -0
  75. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/__init__.py +0 -0
  76. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/chunking.py +0 -0
  77. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/csv_chunking.py +0 -0
  78. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/db_chunking.py +0 -0
  79. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/json_chunking.py +0 -0
  80. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/npy_chunking.py +0 -0
  81. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/xlsx_chunking.py +0 -0
  82. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/content_chunking/xml_chunking.py +0 -0
  83. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/exceptions.py +0 -0
  84. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/file_store.py +0 -0
  85. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/frame_codec.py +0 -0
  86. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/log_record.py +0 -0
  87. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/merkle.py +0 -0
  88. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/repolog/repository_log.py +0 -0
  89. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task1_dsivcs_tests.py +0 -0
  90. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task1_git_tests.py +0 -0
  91. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task3_dsivcs_tests.py +0 -0
  92. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/task3_git_tests.py +0 -0
  93. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/tests/test_vcs.py +0 -0
  94. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/version_control/vcs_db.py +0 -0
  95. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/web_utils.py +0 -0
  96. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/webserver_crosswalk.json +0 -0
  97. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi/utils/webserver_query.py +0 -0
  98. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/SOURCES.txt +0 -0
  99. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/dependency_links.txt +0 -0
  100. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/entry_points.txt +0 -0
  101. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/requires.txt +0 -0
  102. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/dsi_workflow.egg-info/top_level.txt +0 -0
  103. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/pyproject.toml +0 -0
  104. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/requirements.txt +0 -0
  105. {dsi_workflow-1.2.7 → dsi_workflow-1.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dsi-workflow
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: A Data Science Infrastructure Project
5
5
  Author-email: Jesus Pulido <pulido@lanl.gov>, James Ahrens <ahrens@lanl.gov>, Divya Banesh <dbanesh@lanl.gov>, Hugh Greenberg <hng@lanl.gov>, Pascal Grosset <pascalgrosset@lanl.gov>, Vedant Iyer <iyer@lanl.gov>, Benjamin Sims <bsims@lanl.gov>, Terece Turton <tlturton@lanl.gov>
6
6
  License-Expression: BSD-3-Clause
@@ -0,0 +1 @@
1
+ __version__ = "1.2.8"
@@ -1805,8 +1805,36 @@ class Denodo(Webserver):
1805
1805
 
1806
1806
 
1807
1807
  # ----------------------------------------------------------------------
1808
- # DSI Interface: Find
1808
+ # DSI Interface: Search/Find
1809
1809
  # ----------------------------------------------------------------------
1810
+ def search(self, params, download=False):
1811
+ """
1812
+ Retrieves metadata or data for entries in a specified dataset.
1813
+
1814
+ Parameters
1815
+ ----------
1816
+ `params` : dict
1817
+ Identifies the dataset and, optionally, a specific entry.
1818
+ For example, {"database_id": 1} retrieves metadata for all entries
1819
+ in the dataset, while {"database_id": 1, "entry_id": 1} retrieves
1820
+ data for a specific entry (if supported).
1821
+
1822
+ `download` : bool, optional, default=False
1823
+ If True, downloads specified data to a local directory.
1824
+ If False, returns dataset's entry metadata when no entry is specified,
1825
+ or references to a specified entry's data for separate download.
1826
+
1827
+ Returns
1828
+ -------
1829
+ pandas.DataFrame or list of pandas.DataFrame
1830
+ Metadata for a dataset's entries or data references for a specified entry.
1831
+ Returns a list of DataFrames when the metadata spans multiple tables.
1832
+
1833
+ None
1834
+ If no metadata found or data directly downloaded with (download=True)
1835
+ """
1836
+ raise NotImplementedError
1837
+
1810
1838
  def find(self, query_object, **kwargs):
1811
1839
  """Search table names, column names and cell values."""
1812
1840
  return (
@@ -358,15 +358,14 @@ class DuckDB(Filesystem):
358
358
  self.cur.execute(create_query)
359
359
  units_data = artifacts["dsi_units"]
360
360
  for table_val, col_val, unit_val in zip(units_data["table_name"], units_data["column_name"], units_data["unit"]):
361
- str_query = f"INSERT INTO dsi_units VALUES ('{table_val}', '{col_val}', '{unit_val}')"
362
- unit_result = self.cur.execute(f"""SELECT unit FROM dsi_units
363
- WHERE table_name = '{table_val}' AND column_name = '{col_val}';""").fetchone()
361
+ unit_result = self.cur.execute("""SELECT unit FROM dsi_units WHERE
362
+ table_name = ? AND column_name = ?;""", [table_val, col_val]).fetchone()
364
363
  if unit_result and unit_result[0] != unit_val: #checks if unit for same table and col exists in db and if units match
365
364
  self.cur.execute("ROLLBACK")
366
365
  raise TypeError(f"Cannot ingest different units for the column {col_val} in {table_val}")
367
366
  elif not unit_result:
368
367
  try:
369
- self.cur.execute(str_query)
368
+ self.cur.execute("INSERT INTO dsi_units VALUES (?, ?, ?)", [table_val, col_val, unit_val])
370
369
  except duckdb.Error as e:
371
370
  self.cur.execute("ROLLBACK")
372
371
  self.cur.execute("CHECKPOINT")
@@ -1003,7 +1002,7 @@ class DuckDB(Filesystem):
1003
1002
  AVG("{col_name}"),
1004
1003
  STDDEV_SAMP("{col_name}")
1005
1004
  FROM {table_name}
1006
- WHERE "{col_name}" IS NOT NULL
1005
+ WHERE isfinite("{col_name}")
1007
1006
  """).fetchone()
1008
1007
  else:
1009
1008
  min_val = max_val = avg_val = std_dev = None
@@ -1059,8 +1059,36 @@ class NDP(Webserver):
1059
1059
 
1060
1060
 
1061
1061
  # ----------------------------------------------------------------------
1062
- # Find Methods
1062
+ # Search/Find Methods
1063
1063
  # ----------------------------------------------------------------------
1064
+ def search(self, params, download=False):
1065
+ """
1066
+ Retrieves metadata or data for entries in a specified dataset.
1067
+
1068
+ Parameters
1069
+ ----------
1070
+ `params` : dict
1071
+ Identifies the dataset and, optionally, a specific entry.
1072
+ For example, {"database_id": 1} retrieves metadata for all entries
1073
+ in the dataset, while {"database_id": 1, "entry_id": 1} retrieves
1074
+ data for a specific entry (if supported).
1075
+
1076
+ `download` : bool, optional, default=False
1077
+ If True, downloads specified data to a local directory.
1078
+ If False, returns dataset's entry metadata when no entry is specified,
1079
+ or references to a specified entry's data for separate download.
1080
+
1081
+ Returns
1082
+ -------
1083
+ pandas.DataFrame or list of pandas.DataFrame
1084
+ Metadata for a dataset's entries or data references for a specified entry.
1085
+ Returns a list of DataFrames when the metadata spans multiple tables.
1086
+
1087
+ None
1088
+ If no metadata found or data directly downloaded with (download=True)
1089
+ """
1090
+ raise NotImplementedError
1091
+
1064
1092
  def find(self, query_object, **kwargs):
1065
1093
  """
1066
1094
  Searches for all instances of query_object across all tables.
@@ -794,8 +794,36 @@ class Oceans11(Webserver):
794
794
  return self._cache
795
795
 
796
796
  # ------------------------------------------------------------------
797
- # Find Methods
797
+ # Search/Find Methods
798
798
  # ------------------------------------------------------------------
799
+ def search(self, params, download=False):
800
+ """
801
+ Retrieves metadata or data for entries in a specified dataset.
802
+
803
+ Parameters
804
+ ----------
805
+ `params` : dict
806
+ Identifies the dataset and, optionally, a specific entry.
807
+ For example, {"database_id": 1} retrieves metadata for all entries
808
+ in the dataset, while {"database_id": 1, "entry_id": 1} retrieves
809
+ data for a specific entry (if supported).
810
+
811
+ `download` : bool, optional, default=False
812
+ If True, downloads specified data to a local directory.
813
+ If False, returns dataset's entry metadata when no entry is specified,
814
+ or references to a specified entry's data for separate download.
815
+
816
+ Returns
817
+ -------
818
+ pandas.DataFrame or list of pandas.DataFrame
819
+ Metadata for a dataset's entries or data references for a specified entry.
820
+ Returns a list of DataFrames when the metadata spans multiple tables.
821
+
822
+ None
823
+ If no metadata found or data directly downloaded with (download=True)
824
+ """
825
+ raise NotImplementedError
826
+
799
827
  def find(self, query_object, **kwargs):
800
828
  """Search for a value across table, column, and cell levels."""
801
829
  if not self._loaded:
@@ -713,8 +713,36 @@ class OSTI(Webserver):
713
713
  )
714
714
 
715
715
  # ----------------------------------------------------------------------
716
- # Find Methods
716
+ # Search/Find Methods
717
717
  # ----------------------------------------------------------------------
718
+ def search(self, params, download=False):
719
+ """
720
+ Retrieves metadata or data for entries in a specified dataset.
721
+
722
+ Parameters
723
+ ----------
724
+ `params` : dict
725
+ Identifies the dataset and, optionally, a specific entry.
726
+ For example, {"database_id": 1} retrieves metadata for all entries
727
+ in the dataset, while {"database_id": 1, "entry_id": 1} retrieves
728
+ data for a specific entry (if supported).
729
+
730
+ `download` : bool, optional, default=False
731
+ If True, downloads specified data to a local directory.
732
+ If False, returns dataset's entry metadata when no entry is specified,
733
+ or references to a specified entry's data for separate download.
734
+
735
+ Returns
736
+ -------
737
+ pandas.DataFrame or list of pandas.DataFrame
738
+ Metadata for a dataset's entries or data references for a specified entry.
739
+ Returns a list of DataFrames when the metadata spans multiple tables.
740
+
741
+ None
742
+ If no metadata found or data directly downloaded with (download=True)
743
+ """
744
+ raise NotImplementedError
745
+
718
746
  def find(self, query_object, **kwargs):
719
747
  """
720
748
  Searches for all instances of `query_object` across the table, column, and cell levels.
@@ -3,65 +3,68 @@ RCSBPDB Webserver Backend for DSI
3
3
 
4
4
  Read-only metadata-first backend that retrieves rcsb pdb metadata
5
5
  and exposes it as in-memory DSI tables.
6
- """
7
- # Access modes
8
- # ------------
9
- # 1. Identifier-driven mode
10
- # - DOI input, e.g. "10.2210/pdb1cbs/pdb"
11
- # - PDB ID input, e.g. "1CBS"
12
-
13
- # 2. Query-driven mode, closer to NDP
14
- # - params={"keywords": "hemoglobin", "limit": 5}
15
- # - find_relation({"keywords": "hemoglobin", "limit": 5})
16
- # - find_relation("hemoglobin")
17
-
18
- # DOI behavior
19
- # ------------
20
- # RCSB-style DOI input is supported through identifiers or params.
21
- # Only DOIs of the form 10.2210/pdbXXXX/pdb are converted directly into PDB IDs.
22
- # General publication DOI search is not currently supported.
23
-
24
- # REST flow
25
- # ---------
26
- # RCSB Search API -> PDB IDs -> RCSB Data API -> normalized DSI tables
27
-
28
- # Tables
29
- # ------
30
- # - datasets
31
- # - resources
32
- # - errors
33
-
34
- # Tier mapping
35
- # ------------
36
- # self.tables["datasets"] = Tier 1 datasets
37
- # self.tables["resources"] = Tier 2 normalized resources
38
- # self.tables["errors"] = failed/skipped lookups
39
-
40
- # Current scope
41
- # -------------
42
- # - Metadata-first
43
- # - Read-only
44
- # - REST APIs only
45
- # - Exposes mmCIF download URLs
46
- # - Does not parse raw mmCIF content yet
47
-
48
- # identifiers
49
- # → __init__()
50
- # → _load_initial_data()
51
- # → lookup_identifier()
52
- # → lookup_rcsbpdb()
53
- # → _request()
54
- # → GET https://data.rcsb.org/rest/v1/core/entry/{pdb_id}
55
-
56
- # params
57
- # → __init__()
58
- # → _load_from_params()
59
- # → _search_rcsb()
60
- # → _build_search_query()
61
- # → _post_json()
62
- # → POST https://search.rcsb.org/rcsbsearch/v2/query
63
6
 
64
7
 
8
+ Access modes
9
+ ------------
10
+ 1. Identifier-driven mode
11
+ - DOI input, e.g. "10.2210/pdb1cbs/pdb"
12
+ - PDB ID input, e.g. "1CBS"
13
+
14
+ 2. Query-driven mode, closer to NDP
15
+ - params={"keywords": "hemoglobin", "limit": 5}
16
+ - find_relation({"keywords": "hemoglobin", "limit": 5})
17
+ - find_relation("hemoglobin")
18
+
19
+ DOI behavior
20
+ ------------
21
+ RCSB-style DOI input is supported through identifiers or params.
22
+ Only DOIs of the form 10.2210/pdbXXXX/pdb are converted directly into PDB IDs.
23
+ General publication DOI search is not currently supported.
24
+
25
+ REST flow
26
+ ---------
27
+ RCSB Search API -> PDB IDs -> RCSB Data API -> normalized DSI tables
28
+
29
+ Tables
30
+ ------
31
+ - datasets
32
+ - resources
33
+ - errors
34
+
35
+ Tier mapping
36
+ ------------
37
+ self.tables["datasets"] = Tier 1 datasets
38
+ self.tables["resources"] = Tier 2 normalized resources
39
+ self.tables["errors"] = failed/skipped lookups
40
+
41
+ Current scope
42
+ -------------
43
+ - Metadata-first
44
+ - Read-only
45
+ - REST APIs only
46
+ - Exposes mmCIF download URLs
47
+ - Does not parse raw mmCIF content yet
48
+
49
+ **identifiers**
50
+
51
+ - __init__()
52
+ - _load_initial_data()
53
+ - lookup_identifier()
54
+ - lookup_rcsbpdb()
55
+ - _request()
56
+ - GET https://data.rcsb.org/rest/v1/core/entry/{pdb_id}
57
+
58
+ **params**
59
+
60
+ - __init__()
61
+ - _load_from_params()
62
+ - _search_rcsb()
63
+ - _build_search_query()
64
+ - _post_json()
65
+ - POST https://search.rcsb.org/rcsbsearch/v2/query
66
+ """
67
+
65
68
  from __future__ import annotations
66
69
 
67
70
  import builtins
@@ -1354,6 +1357,34 @@ class RCSBPDB(Webserver):
1354
1357
  self._loaded = True
1355
1358
  return self.tables
1356
1359
 
1360
+ def search(self, params, download=False):
1361
+ """
1362
+ Retrieves metadata or data for entries in a specified dataset.
1363
+
1364
+ Parameters
1365
+ ----------
1366
+ `params` : dict
1367
+ Identifies the dataset and, optionally, a specific entry.
1368
+ For example, {"database_id": 1} retrieves metadata for all entries
1369
+ in the dataset, while {"database_id": 1, "entry_id": 1} retrieves
1370
+ data for a specific entry (if supported).
1371
+
1372
+ `download` : bool, optional, default=False
1373
+ If True, downloads specified data to a local directory.
1374
+ If False, returns dataset's entry metadata when no entry is specified,
1375
+ or references to a specified entry's data for separate download.
1376
+
1377
+ Returns
1378
+ -------
1379
+ pandas.DataFrame or list of pandas.DataFrame
1380
+ Metadata for a dataset's entries or data references for a specified entry.
1381
+ Returns a list of DataFrames when the metadata spans multiple tables.
1382
+
1383
+ None
1384
+ If no metadata found or data directly downloaded with (download=True)
1385
+ """
1386
+ raise NotImplementedError
1387
+
1357
1388
  def find(self, query_object, **kwargs):
1358
1389
  """
1359
1390
  Searches for all instances of query_object across all loaded tables.
@@ -323,15 +323,14 @@ class Sqlite(Filesystem):
323
323
  self.cur.execute(create_query)
324
324
  units_data = artifacts["dsi_units"]
325
325
  for table_val, col_val, unit_val in zip(units_data["table_name"], units_data["column_name"], units_data["unit"]):
326
- str_query = f"INSERT INTO dsi_units VALUES ('{table_val}', '{col_val}', '{unit_val}')"
327
- unit_result = self.cur.execute(f"""SELECT unit FROM dsi_units
328
- WHERE table_name = '{table_val}' AND column_name = '{col_val}';""").fetchone()
326
+ unit_result = self.cur.execute("""SELECT unit FROM dsi_units WHERE
327
+ table_name = ? AND column_name = ?;""", [table_val, col_val]).fetchone()
329
328
  if unit_result and unit_result[0] != unit_val: #checks if unit for same table and col exists in db and if units match
330
329
  self.con.rollback()
331
330
  raise TypeError(f"Cannot ingest different units for the column {col_val} in {table_val}")
332
331
  elif not unit_result:
333
332
  try:
334
- self.cur.execute(str_query)
333
+ self.cur.execute("INSERT INTO dsi_units VALUES (?, ?, ?)", [table_val, col_val, unit_val])
335
334
  except sqlite3.Error as e:
336
335
  self.con.rollback()
337
336
  raise sqlite3.Error(e)
@@ -33,25 +33,27 @@ TEST_OSTI_ID = "3022783"
33
33
  # =============================================================================
34
34
  # Fixtures
35
35
  # =============================================================================
36
-
37
36
  @pytest.fixture(scope="session")
38
37
  def backend(tmp_path_factory):
39
38
  """Create one live Oceans11 backend for the entire test session."""
40
39
  workspace = tmp_path_factory.mktemp("oceans11")
41
40
 
42
- instance = Oceans11(
43
- params=[
44
- {"osti_id": TEST_OSTI_ID, "rows": 1},
45
- {"osti_id": TEST_OSTI_ID, "rows": 1},
46
- ],
47
- workspace=str(workspace),
48
- )
49
-
50
- yield instance
51
-
52
- if instance._loaded:
53
- instance.close()
41
+ try:
42
+ instance = Oceans11(
43
+ params=[
44
+ {"osti_id": TEST_OSTI_ID, "rows": 1},
45
+ {"osti_id": TEST_OSTI_ID, "rows": 1},
46
+ ],
47
+ workspace=str(workspace),
48
+ )
49
+ except ConnectionError as e:
50
+ pytest.skip(f"Oceans11 is unavailable: {e}")
54
51
 
52
+ try:
53
+ yield instance
54
+ finally:
55
+ if instance._loaded:
56
+ instance.close()
55
57
 
56
58
  @pytest.fixture(scope="session")
57
59
  def record(backend):