papyrus-scripts 3.0.0__tar.gz → 3.0.1__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 (46) hide show
  1. {papyrus_scripts-3.0.0/src/papyrus_scripts.egg-info → papyrus_scripts-3.0.1}/PKG-INFO +1 -1
  2. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/__init__.py +1 -1
  3. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/download.py +49 -11
  4. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/preprocess.py +8 -3
  5. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/subsim_search.py +8 -3
  6. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/links.json +1524 -1524
  7. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1/src/papyrus_scripts.egg-info}/PKG-INFO +1 -1
  8. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_download.py +94 -0
  9. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_neuralnet.py +6 -1
  10. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/LICENSE +0 -0
  11. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/README.md +0 -0
  12. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/pyproject.toml +0 -0
  13. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/setup.cfg +0 -0
  14. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/__main__.py +0 -0
  15. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/cli.py +0 -0
  16. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/fingerprint.py +0 -0
  17. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/matchRCSB.py +0 -0
  18. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/modelling.py +0 -0
  19. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/neuralnet.py +0 -0
  20. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/oop.py +0 -0
  21. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/reader.py +0 -0
  22. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/IO.py +0 -0
  23. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/UniprotMatch.py +0 -0
  24. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/__init__.py +0 -0
  25. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/aliases.json +0 -0
  26. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts/utils/mol_reader.py +0 -0
  27. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts.egg-info/SOURCES.txt +0 -0
  28. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts.egg-info/dependency_links.txt +0 -0
  29. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts.egg-info/entry_points.txt +0 -0
  30. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts.egg-info/requires.txt +0 -0
  31. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/src/papyrus_scripts.egg-info/top_level.txt +0 -0
  32. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_cli.py +0 -0
  33. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_fingerprint.py +0 -0
  34. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_io.py +0 -0
  35. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_matchRCSB.py +0 -0
  36. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_modelling.py +0 -0
  37. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_modelling_real_data.py +0 -0
  38. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_mol_reader.py +0 -0
  39. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_oop.py +0 -0
  40. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_oop_unit.py +0 -0
  41. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_preprocess.py +0 -0
  42. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_reader.py +0 -0
  43. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_reader_offline.py +0 -0
  44. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_reader_real_data.py +0 -0
  45. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_subsim_search.py +0 -0
  46. {papyrus_scripts-3.0.0 → papyrus_scripts-3.0.1}/tests/test_uniprot_match.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: papyrus_scripts
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: A collection of scripts to handle the Papyrus bioactivity dataset
5
5
  Author: Brandon J. Bongers, Willem Jespers
6
6
  Author-email: "Olivier J. M. Béquignon" <olivier.bequignon.maintainer@gmail.com>
@@ -35,4 +35,4 @@ from .utils import IO, UniprotMatch
35
35
  from .utils.IO import PapyrusVersion
36
36
  from .utils.mol_reader import MolSupplier
37
37
 
38
- __version__ = '3.0.0'
38
+ __version__ = '3.0.1'
@@ -83,17 +83,29 @@ _SIZE_KEY_BY_FTYPE = {
83
83
  '3D_structures': 'structures_3D',
84
84
  }
85
85
 
86
- def _size_for_ftype(sizes: dict, ftype: str) -> int | None:
86
+ #: data_size.json omits 'prodec' on every 2022.11.x release (.1-.4), even
87
+ #: though the file itself is published. All four share one sha256; row
88
+ #: count independently verified via ``xz -dc <file> | wc -l``.
89
+ _ROW_COUNT_OVERRIDE_BY_SHA256: dict[str, int] = {
90
+ '3211a62f18ccb7ccc13f885374c1462efeb83ab0e98ed62d2645723f7dc9f1a1': 7505,
91
+ }
92
+
93
+
94
+ def _size_for_ftype(sizes: dict, ftype: str, sha256: str | None = None) -> int | None:
87
95
  """Look up *ftype*'s row count in a parsed data_size.json, or ``None`` if absent.
88
96
 
89
97
  Releases up to 2022.11.4 key papyrus++ as ``"papyrus++"``; 2024.09.1+
90
98
  use ``"papyrus_++"`` (``_SIZE_KEY_BY_FTYPE['papyrus++']``) - try both.
99
+
100
+ :param sha256: fallback key into :data:`_ROW_COUNT_OVERRIDE_BY_SHA256`.
91
101
  """
92
102
  key = _SIZE_KEY_BY_FTYPE.get(ftype)
93
103
  if key in sizes:
94
104
  return sizes[key]
95
105
  if ftype == 'papyrus++' and 'papyrus++' in sizes:
96
106
  return sizes['papyrus++']
107
+ if sha256 is not None and sha256 in _ROW_COUNT_OVERRIDE_BY_SHA256:
108
+ return _ROW_COUNT_OVERRIDE_BY_SHA256[sha256]
97
109
  return None
98
110
 
99
111
 
@@ -807,7 +819,11 @@ def download_papyrus(outdir: str | Path | None = None,
807
819
  _update_current_file_description()
808
820
 
809
821
  def _wait_for_converter() -> None:
810
- """Block until the converter process exits, draining progress messages meanwhile."""
822
+ """Block until the converter process exits, draining progress messages meanwhile.
823
+
824
+ Does not close converting_pbar - callers do that via
825
+ _close_converting_pbar, once success/failure is known.
826
+ """
811
827
  # Only ever called once converter_process has been started (see call sites).
812
828
  if converter_process is None: # noqa: B023
813
829
  raise RuntimeError('converter_process not started')
@@ -815,8 +831,27 @@ def download_papyrus(outdir: str | Path | None = None,
815
831
  _drain_progress_queue()
816
832
  converter_process.join(timeout=0.1) # noqa: B023
817
833
  _drain_progress_queue()
818
- if converting_pbar is not None: # noqa: B023
819
- converting_pbar.close() # noqa: B023
834
+
835
+ def _close_converting_pbar(success: bool) -> None:
836
+ """Close converting_pbar, topping it up to 100% first on success.
837
+
838
+ total is a naive line count that can exceed the true row count
839
+ (see convert_xz_to_parquet's docstring), so n often lands just
840
+ under total even on success - tqdm.notebook then marks the bar
841
+ 'danger' (red) as if it had failed. Topping up avoids that;
842
+ skipped on failure, where n < total is a real signal.
843
+ """
844
+ if converting_pbar is None: # noqa: B023
845
+ return
846
+ if (
847
+ success # noqa: B023
848
+ and isinstance(converting_pbar.total, (int, float)) # noqa: B023
849
+ and isinstance(converting_pbar.n, (int, float)) # noqa: B023
850
+ ):
851
+ shortfall = converting_pbar.total - converting_pbar.n # noqa: B023
852
+ if shortfall > 0:
853
+ converting_pbar.update(shortfall) # noqa: B023
854
+ converting_pbar.close() # noqa: B023
820
855
 
821
856
  def _enqueue(item) -> None:
822
857
  """Put *item* on task_queue, staying responsive while backpressured.
@@ -850,15 +885,16 @@ def download_papyrus(outdir: str | Path | None = None,
850
885
  _drain_progress_queue()
851
886
 
852
887
  if not keep_xz:
853
- # ftype per file still needing conversion; used once data_size.json
854
- # is read to compute converting_pbar's total row count.
855
- to_convert_ftypes: list[str] = []
888
+ # (ftype, sha256) per file still needing conversion, for
889
+ # converting_pbar's total - sha256 lets _size_for_ftype fall
890
+ # back to _ROW_COUNT_OVERRIDE_BY_SHA256 if needed.
891
+ to_convert_ftypes: list[tuple[str, str]] = []
856
892
  for ftype in ordered_ftypes:
857
893
  for entry in _iter_entries(version_files[ftype]):
858
894
  fpath = _file_path(papyrus_version_root, ftype, entry['name'])
859
895
  parquet_path = _parquet_sibling(fpath)
860
896
  if parquet_path is not None and not parquet_path.is_file():
861
- to_convert_ftypes.append(ftype)
897
+ to_convert_ftypes.append((ftype, entry['sha256']))
862
898
 
863
899
  task_queue = mp.Queue(maxsize=1)
864
900
  error_queue = mp.Queue()
@@ -972,8 +1008,8 @@ def download_papyrus(outdir: str | Path | None = None,
972
1008
  # unless any is unknown (avoid understating it).
973
1009
  if progress and converting_pbar is not None and to_convert_ftypes:
974
1010
  per_file_rows = [
975
- _size_for_ftype(sizes, ft)
976
- for ft in to_convert_ftypes
1011
+ _size_for_ftype(sizes, ft, sha)
1012
+ for ft, sha in to_convert_ftypes
977
1013
  ]
978
1014
  if all(n is not None for n in per_file_rows):
979
1015
  # reset() syncs the widget's max too, unlike plain `.total =`.
@@ -985,7 +1021,7 @@ def download_papyrus(outdir: str | Path | None = None,
985
1021
  'parquet_path': parquet_path,
986
1022
  'schema_overrides': schemas.get(_SCHEMA_KEY_BY_FTYPE.get(ftype)),
987
1023
  'null_values': _NULL_VALUES_BY_FTYPE.get(ftype),
988
- 'total_rows': _size_for_ftype(sizes, ftype),
1024
+ 'total_rows': _size_for_ftype(sizes, ftype, dhash),
989
1025
  # ftype (e.g. 'papyrus++', '2D_mold2') rather
990
1026
  # than fpath.name: the real filenames (e.g.
991
1027
  # '05.6++_combined_set_without_stereochemistry
@@ -1012,6 +1048,7 @@ def download_papyrus(outdir: str | Path | None = None,
1012
1048
  raise RuntimeError('task_queue not created') from None
1013
1049
  _enqueue(_CONVERSION_DONE)
1014
1050
  _wait_for_converter()
1051
+ _close_converting_pbar(success=False)
1015
1052
  if progress:
1016
1053
  pbar.close()
1017
1054
  raise
@@ -1028,6 +1065,7 @@ def download_papyrus(outdir: str | Path | None = None,
1028
1065
  _enqueue(_CONVERSION_DONE)
1029
1066
  _wait_for_converter()
1030
1067
  error = error_queue.get()
1068
+ _close_converting_pbar(success=error is None)
1031
1069
  if error is not None:
1032
1070
  if progress:
1033
1071
  pbar.close()
@@ -26,7 +26,7 @@ DataOutput = pl.DataFrame | pl.LazyFrame
26
26
  _JoinHow = Literal['inner', 'left', 'right', 'full', 'semi', 'anti', 'cross', 'outer']
27
27
  _ConcatHow = Literal[
28
28
  'vertical', 'vertical_relaxed', 'diagonal', 'diagonal_relaxed',
29
- 'horizontal', 'horizontal_extend', 'align', 'align_full', 'align_inner',
29
+ 'horizontal', 'align', 'align_full', 'align_inner',
30
30
  'align_left', 'align_right',
31
31
  ]
32
32
 
@@ -290,7 +290,9 @@ def process_groups(
290
290
 
291
291
  if has_pchembl:
292
292
  pv = pl.col('pchembl_value')
293
- pv_num = pv.cast(pl.Float64)
293
+ # Raw values can carry padding (e.g. " 6.700") - strip before the
294
+ # strict numeric cast, which otherwise rejects it.
295
+ pv_num = pv.str.strip_chars().cast(pl.Float64)
294
296
  median = pv_num.median()
295
297
  n = pv_num.drop_nulls().len()
296
298
  std = pv_num.std()
@@ -734,7 +736,10 @@ def keep_protein_class(
734
736
  return data.filter(pl.lit(False))
735
737
 
736
738
  # level_frames always share len(protein_data) rows, so this never pads.
737
- split_classes = pl.concat(level_frames, how='horizontal_extend')
739
+ # 'horizontal_extend' only exists in very recent polars releases (absent
740
+ # e.g. on Google Colab's pinned version); 'horizontal' is available
741
+ # everywhere and behaves identically here since heights always match.
742
+ split_classes = pl.concat(level_frames, how='horizontal')
738
743
 
739
744
  # Build the boolean mask over protein rows.
740
745
  mask = pl.Series([False] * len(split_classes))
@@ -38,7 +38,6 @@ try:
38
38
  # first import is unreachable otherwise (the first import raises first).
39
39
  from FPSim2.base import BaseEngine # pragma: no cover
40
40
  from FPSim2.FPSim2 import FPSim2Engine
41
- from FPSim2.FPSim2Cuda import FPSim2CudaEngine # pragma: no cover
42
41
  from FPSim2.io.backends.base import BaseStorageBackend # pragma: no cover
43
42
  from FPSim2.io.backends.pytables import ( # pragma: no cover
44
43
  BATCH_WRITE_SIZE,
@@ -60,10 +59,16 @@ except ImportError:
60
59
 
61
60
  class FPSim2Engine: # type: ignore[no-redef]
62
61
  """Stub for FPSim2.FPSim2.FPSim2Engine when FPSim2 is absent."""
62
+ BATCH_WRITE_SIZE = 32_000 # FPSim2's own default; only used for queue sizing here
63
63
 
64
+ try:
65
+ # FPSim2.FPSim2Cuda unconditionally imports cupy, so this is kept
66
+ # separate from HAS_FPSIM2 above: a missing GPU stack must not disable
67
+ # CPU-only search.
68
+ from FPSim2.FPSim2Cuda import FPSim2CudaEngine # pragma: no cover
69
+ except ImportError:
64
70
  class FPSim2CudaEngine: # type: ignore[no-redef]
65
- """Stub for FPSim2.FPSim2Cuda.FPSim2CudaEngine when FPSim2 is absent."""
66
- BATCH_WRITE_SIZE = 32_000 # FPSim2's own default; only used for queue sizing here
71
+ """Stub for FPSim2.FPSim2Cuda.FPSim2CudaEngine when cupy is absent."""
67
72
 
68
73
  from .fingerprint import Fingerprint, MorganFingerprint, get_fp_from_name
69
74
  from .utils.IO import PapyrusVersion, _prefer_parquet, _set_root_folder, get_num_rows_in_file, locate_file