synkit 1.6.5__py3-none-win_amd64.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.
- synkit/CRN/Benchmark/__init__.py +53 -0
- synkit/CRN/Benchmark/crosschecks.py +13 -0
- synkit/CRN/Benchmark/kegg.py +12 -0
- synkit/CRN/Benchmark/networks.py +13 -0
- synkit/CRN/Benchmark/scaling.py +13 -0
- synkit/CRN/Benchmark/validate.py +13 -0
- synkit/CRN/Construct/__init__.py +16 -0
- synkit/CRN/Construct/abstract.py +668 -0
- synkit/CRN/Construct/arity.py +36 -0
- synkit/CRN/Construct/builder.py +619 -0
- synkit/CRN/Construct/derivation.py +63 -0
- synkit/CRN/Construct/flattener.py +100 -0
- synkit/CRN/Construct/keys.py +14 -0
- synkit/CRN/Construct/mixtures.py +117 -0
- synkit/CRN/Construct/rdkit_worker.py +69 -0
- synkit/CRN/Construct/smiles.py +99 -0
- synkit/CRN/Construct/state.py +31 -0
- synkit/CRN/Construct/strategy.py +75 -0
- synkit/CRN/Construct/worker.py +42 -0
- synkit/CRN/IO/__init__.py +36 -0
- synkit/CRN/IO/sbml.py +925 -0
- synkit/CRN/Pathway/__init__.py +72 -0
- synkit/CRN/Pathway/_adapter.py +333 -0
- synkit/CRN/Pathway/pathfinder.py +500 -0
- synkit/CRN/Pathway/reachability.py +796 -0
- synkit/CRN/Pathway/realizability.py +1322 -0
- synkit/CRN/Petrinet/__init__.py +93 -0
- synkit/CRN/Petrinet/analyzer.py +486 -0
- synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
- synkit/CRN/Petrinet/net.py +1041 -0
- synkit/CRN/Petrinet/persistence.py +97 -0
- synkit/CRN/Petrinet/semiflows.py +483 -0
- synkit/CRN/Petrinet/siphon_search.py +402 -0
- synkit/CRN/Petrinet/structure.py +286 -0
- synkit/CRN/Props/__init__.py +130 -0
- synkit/CRN/Props/_rank.py +29 -0
- synkit/CRN/Props/deficiency.py +953 -0
- synkit/CRN/Props/dynamics.py +832 -0
- synkit/CRN/Props/helper.py +151 -0
- synkit/CRN/Props/stoich.py +751 -0
- synkit/CRN/Props/thermo.py +584 -0
- synkit/CRN/Query/__init__.py +66 -0
- synkit/CRN/Query/cache.py +41 -0
- synkit/CRN/Query/kegg_api.py +99 -0
- synkit/CRN/Query/kegg_extract.py +714 -0
- synkit/CRN/Query/kegg_impute.py +707 -0
- synkit/CRN/Query/kegg_parse.py +480 -0
- synkit/CRN/Query/to_syncrn.py +290 -0
- synkit/CRN/README.md +234 -0
- synkit/CRN/Structure/__init__.py +12 -0
- synkit/CRN/Structure/_graph_io.py +713 -0
- synkit/CRN/Structure/_matrices.py +88 -0
- synkit/CRN/Structure/_parse.py +544 -0
- synkit/CRN/Structure/reaction.py +237 -0
- synkit/CRN/Structure/rule.py +55 -0
- synkit/CRN/Structure/species.py +46 -0
- synkit/CRN/Structure/syncrn.py +929 -0
- synkit/CRN/Symmetry/__init__.py +20 -0
- synkit/CRN/Symmetry/_common.py +1059 -0
- synkit/CRN/Symmetry/_ir.py +940 -0
- synkit/CRN/Symmetry/automorphism.py +472 -0
- synkit/CRN/Symmetry/canon.py +441 -0
- synkit/CRN/Symmetry/isomorphism.py +412 -0
- synkit/CRN/Symmetry/symmetry.py +61 -0
- synkit/CRN/Symmetry/wl_canon.py +967 -0
- synkit/CRN/Visualize/__init__.py +11 -0
- synkit/CRN/Visualize/labels.py +113 -0
- synkit/CRN/Visualize/layout.py +708 -0
- synkit/CRN/Visualize/palette.py +292 -0
- synkit/CRN/Visualize/validation.py +122 -0
- synkit/CRN/Visualize/vis.py +1152 -0
- synkit/CRN/__init__.py +233 -0
- synkit/CRN/_build.py +50 -0
- synkit/CRN/_native_build.py +175 -0
- synkit/CRN/analysis.py +629 -0
- synkit/CRN/backend.py +74 -0
- synkit/CRN/cpp/CMakeLists.txt +58 -0
- synkit/CRN/cpp/algebra.cpp +46 -0
- synkit/CRN/cpp/closure.cpp +29 -0
- synkit/CRN/cpp/exact.h +55 -0
- synkit/CRN/cpp/pathway.cpp +46 -0
- synkit/CRN/cpp/semiflows.cpp +209 -0
- synkit/CRN/cpp/structural.cpp +240 -0
- synkit/CRN/cpp/symmetry.cpp +45 -0
- synkit/CRN/cpp/write_manifest.cmake +28 -0
- synkit/CRN/kinds.py +137 -0
- synkit/CRN/lib/synkit_crn.dll +0 -0
- synkit/CRN/lib/synkit_crn.json +33 -0
- synkit/CRN/native.py +388 -0
- synkit/CRN/native_analysis.py +459 -0
- synkit/Chem/Cluster/__init__.py +0 -0
- synkit/Chem/Cluster/butina.py +140 -0
- synkit/Chem/Fingerprint/__init__.py +0 -0
- synkit/Chem/Fingerprint/fp_calculator.py +155 -0
- synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
- synkit/Chem/Fingerprint/transformation_fp.py +139 -0
- synkit/Chem/Mapper/README.rst +43 -0
- synkit/Chem/Mapper/__init__.py +255 -0
- synkit/Chem/Mapper/_compat.py +130 -0
- synkit/Chem/Mapper/adapters/__init__.py +1 -0
- synkit/Chem/Mapper/adapters/prediction.py +126 -0
- synkit/Chem/Mapper/adapters/template.py +412 -0
- synkit/Chem/Mapper/chem/__init__.py +52 -0
- synkit/Chem/Mapper/chem/aam.py +673 -0
- synkit/Chem/Mapper/chem/blind.py +160 -0
- synkit/Chem/Mapper/chem/its.py +309 -0
- synkit/Chem/Mapper/chem/smiles.py +564 -0
- synkit/Chem/Mapper/graph/__init__.py +66 -0
- synkit/Chem/Mapper/graph/automorphism.py +395 -0
- synkit/Chem/Mapper/graph/blockcut.py +98 -0
- synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
- synkit/Chem/Mapper/graph/refine.py +176 -0
- synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
- synkit/Chem/Mapper/io/__init__.py +13 -0
- synkit/Chem/Mapper/io/idxmapstr.py +82 -0
- synkit/Chem/Mapper/mapper.py +685 -0
- synkit/Chem/Mapper/reaction_search.py +554 -0
- synkit/Chem/Mapper/reporting/__init__.py +1 -0
- synkit/Chem/Mapper/reporting/alternatives.py +451 -0
- synkit/Chem/Mapper/reporting/analysis.py +681 -0
- synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
- synkit/Chem/Mapper/reporting/spectrum.py +642 -0
- synkit/Chem/Mapper/solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
- synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
- synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
- synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
- synkit/Chem/Mapper/solvers/exact/core.py +183 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
- synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
- synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
- synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
- synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
- synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
- synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
- synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
- synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
- synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
- synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
- synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
- synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
- synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
- synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
- synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
- synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
- synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
- synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
- synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
- synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
- synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
- synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
- synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
- synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
- synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
- synkit/Chem/Mapper/solvers/exact/search.py +55 -0
- synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
- synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
- synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
- synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
- synkit/Chem/Mapper/solvers/native/astar.py +22 -0
- synkit/Chem/Mapper/solvers/native/build.py +385 -0
- synkit/Chem/Mapper/solvers/native/classification.py +641 -0
- synkit/Chem/Mapper/solvers/native/core.py +378 -0
- synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
- synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
- synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
- synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
- synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
- synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
- synkit/Chem/Mapper/solvers/native/mces.py +16 -0
- synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
- synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
- synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
- synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
- synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
- synkit/Chem/Mapper/solvers/native/slap.py +266 -0
- synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
- synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
- synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
- synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
- synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
- synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
- synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
- synkit/Chem/Mapper/validation/__init__.py +1 -0
- synkit/Chem/Mapper/validation/aam_validator.py +442 -0
- synkit/Chem/Mapper/validation/annotations.py +274 -0
- synkit/Chem/Mapper/validation/bonds.py +124 -0
- synkit/Chem/Mapper/validation/cohorts.py +72 -0
- synkit/Chem/Mapper/validation/identifiability.py +150 -0
- synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
- synkit/Chem/Mapper/validation/orbits.py +137 -0
- synkit/Chem/Molecule/__init__.py +0 -0
- synkit/Chem/Molecule/_chirality_loci.py +165 -0
- synkit/Chem/Molecule/_chirality_types.py +231 -0
- synkit/Chem/Molecule/_helical_loci.py +167 -0
- synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
- synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
- synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
- synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
- synkit/Chem/Molecule/atom_features.py +379 -0
- synkit/Chem/Molecule/chirality.py +1041 -0
- synkit/Chem/Molecule/cip_assignment.py +569 -0
- synkit/Chem/Molecule/cip_ranking.py +843 -0
- synkit/Chem/Molecule/coordinate_stereo.py +503 -0
- synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
- synkit/Chem/Molecule/descriptors.py +452 -0
- synkit/Chem/Molecule/formula.py +249 -0
- synkit/Chem/Molecule/global_stereo.py +175 -0
- synkit/Chem/Molecule/graph_annotator.py +300 -0
- synkit/Chem/Molecule/standardize.py +817 -0
- synkit/Chem/Molecule/stereo_evidence.py +179 -0
- synkit/Chem/Molecule/stereo_perception.py +1032 -0
- synkit/Chem/Molecule/valence.py +123 -0
- synkit/Chem/Reaction/Mapper/__init__.py +44 -0
- synkit/Chem/Reaction/__init__.py +20 -0
- synkit/Chem/Reaction/aam_validator.py +5 -0
- synkit/Chem/Reaction/balance_check.py +138 -0
- synkit/Chem/Reaction/canon_rsmi.py +249 -0
- synkit/Chem/Reaction/cleaning.py +58 -0
- synkit/Chem/Reaction/deionize.py +199 -0
- synkit/Chem/Reaction/explicit_h_audit.py +232 -0
- synkit/Chem/Reaction/fix_aam.py +64 -0
- synkit/Chem/Reaction/neutralize.py +207 -0
- synkit/Chem/Reaction/radical_wildcard.py +224 -0
- synkit/Chem/Reaction/standardize.py +203 -0
- synkit/Chem/Reaction/tautomerize.py +205 -0
- synkit/Chem/__init__.py +1 -0
- synkit/Chem/utils.py +315 -0
- synkit/Data/__init__.py +0 -0
- synkit/Data/aldol.json.gz +1 -0
- synkit/Data/gen_partial_aam.py +147 -0
- synkit/Data/paracetamol.json.gz +1 -0
- synkit/Graph/Canon/__init__.py +16 -0
- synkit/Graph/Canon/_native/__init__.py +13 -0
- synkit/Graph/Canon/_native/build.py +93 -0
- synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
- synkit/Graph/Canon/_native/prepare.py +49 -0
- synkit/Graph/Canon/_native/runtime.py +140 -0
- synkit/Graph/Canon/_native/search.py +137 -0
- synkit/Graph/Canon/canon_algs.py +228 -0
- synkit/Graph/Canon/canon_graph.py +531 -0
- synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
- synkit/Graph/Canon/cpp/README.md +123 -0
- synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
- synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
- synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
- synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
- synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
- synkit/Graph/Canon/exact.py +1020 -0
- synkit/Graph/Canon/exact_refinement.py +368 -0
- synkit/Graph/Canon/nauty.py +143 -0
- synkit/Graph/Context/__init__.py +0 -0
- synkit/Graph/Context/hier_context.py +244 -0
- synkit/Graph/Context/radius_expand.py +252 -0
- synkit/Graph/FG/__init__.py +19 -0
- synkit/Graph/FG/api.py +39 -0
- synkit/Graph/FG/audit.py +155 -0
- synkit/Graph/FG/catalog.py +919 -0
- synkit/Graph/FG/detector.py +288 -0
- synkit/Graph/FG/model.py +97 -0
- synkit/Graph/FG/recognizers.py +274 -0
- synkit/Graph/FG/ring_system.py +154 -0
- synkit/Graph/Feature/Descriptors/topology.py +857 -0
- synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
- synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
- synkit/Graph/Feature/__init__.py +5 -0
- synkit/Graph/Feature/graph_descriptors.py +323 -0
- synkit/Graph/Feature/graph_fps.py +96 -0
- synkit/Graph/Feature/graph_signature.py +239 -0
- synkit/Graph/Feature/hash_fps.py +133 -0
- synkit/Graph/Feature/morgan_fps.py +88 -0
- synkit/Graph/Feature/path_fps.py +81 -0
- synkit/Graph/Feature/wl_hash.py +134 -0
- synkit/Graph/Fusion/__init__.py +85 -0
- synkit/Graph/Fusion/candidate.py +559 -0
- synkit/Graph/Fusion/constructor.py +877 -0
- synkit/Graph/Fusion/identity.py +184 -0
- synkit/Graph/Fusion/interface.py +700 -0
- synkit/Graph/Fusion/search.py +241 -0
- synkit/Graph/Hyrogen/__init__.py +6 -0
- synkit/Graph/Hyrogen/_misc.py +591 -0
- synkit/Graph/Hyrogen/hcomplete.py +995 -0
- synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
- synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
- synkit/Graph/Hyrogen/hextend.py +570 -0
- synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
- synkit/Graph/ITS/__init__.py +4 -0
- synkit/Graph/ITS/its_builder.py +120 -0
- synkit/Graph/ITS/its_construction.py +719 -0
- synkit/Graph/ITS/its_decompose.py +572 -0
- synkit/Graph/ITS/its_destruction.py +331 -0
- synkit/Graph/ITS/its_expand.py +1251 -0
- synkit/Graph/ITS/its_relabel.py +187 -0
- synkit/Graph/ITS/its_reverter.py +356 -0
- synkit/Graph/ITS/normalize_aam.py +145 -0
- synkit/Graph/ITS/partial_its.py +238 -0
- synkit/Graph/ITS/rc_extractor.py +656 -0
- synkit/Graph/ITS/stereo.py +74 -0
- synkit/Graph/MTG/__init__.py +107 -0
- synkit/Graph/MTG/gluing.py +451 -0
- synkit/Graph/MTG/history.py +928 -0
- synkit/Graph/MTG/inventory.py +118 -0
- synkit/Graph/MTG/local.py +447 -0
- synkit/Graph/MTG/mcs_matcher.py +246 -0
- synkit/Graph/MTG/mtg.py +611 -0
- synkit/Graph/MTG/mtg_explore.py +74 -0
- synkit/Graph/MTG/observation.py +209 -0
- synkit/Graph/MTG/process.py +577 -0
- synkit/Graph/MTG/queries.py +66 -0
- synkit/Graph/MTG/realization.py +95 -0
- synkit/Graph/MTG/series_parallel.py +107 -0
- synkit/Graph/MTG/utils.py +424 -0
- synkit/Graph/Matcher/__init__.py +10 -0
- synkit/Graph/Matcher/approx_mcs.py +1264 -0
- synkit/Graph/Matcher/auto_est.py +736 -0
- synkit/Graph/Matcher/automorphism.py +314 -0
- synkit/Graph/Matcher/batch_cluster.py +224 -0
- synkit/Graph/Matcher/dedup_matches.py +247 -0
- synkit/Graph/Matcher/graph_cluster.py +191 -0
- synkit/Graph/Matcher/graph_matcher.py +312 -0
- synkit/Graph/Matcher/graph_morphism.py +421 -0
- synkit/Graph/Matcher/mcs_matcher.py +804 -0
- synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
- synkit/Graph/Matcher/orbit.py +284 -0
- synkit/Graph/Matcher/partial_matcher.py +694 -0
- synkit/Graph/Matcher/sing.py +544 -0
- synkit/Graph/Matcher/subgraph_matcher.py +812 -0
- synkit/Graph/Matcher/turbo_iso.py +272 -0
- synkit/Graph/Matcher/wl_sel.py +537 -0
- synkit/Graph/Mech/__init__.py +26 -0
- synkit/Graph/Mech/conversion.py +1466 -0
- synkit/Graph/Mech/conversion_debug.py +237 -0
- synkit/Graph/Mech/electron_accounting.py +200 -0
- synkit/Graph/Mech/lwg_editor.py +406 -0
- synkit/Graph/Mech/lwg_ops.py +313 -0
- synkit/Graph/Morphism/__init__.py +99 -0
- synkit/Graph/Morphism/constraints.py +460 -0
- synkit/Graph/Morphism/llg.py +999 -0
- synkit/Graph/Morphism/morphism.py +349 -0
- synkit/Graph/Morphism/stereo.py +258 -0
- synkit/Graph/Morphism/stereo_morphism.py +383 -0
- synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
- synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
- synkit/Graph/Stereo/__init__.py +376 -0
- synkit/Graph/Stereo/_descriptor_core.py +207 -0
- synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
- synkit/Graph/Stereo/canonical.py +648 -0
- synkit/Graph/Stereo/changes.py +964 -0
- synkit/Graph/Stereo/composition.py +391 -0
- synkit/Graph/Stereo/configured.py +946 -0
- synkit/Graph/Stereo/couplings.py +245 -0
- synkit/Graph/Stereo/descriptors.py +1030 -0
- synkit/Graph/Stereo/enumeration.py +597 -0
- synkit/Graph/Stereo/extended_descriptors.py +406 -0
- synkit/Graph/Stereo/global_configured.py +152 -0
- synkit/Graph/Stereo/global_stereo.py +304 -0
- synkit/Graph/Stereo/identity.py +648 -0
- synkit/Graph/Stereo/interchange.py +496 -0
- synkit/Graph/Stereo/legacy.py +460 -0
- synkit/Graph/Stereo/matching.py +899 -0
- synkit/Graph/Stereo/native.py +154 -0
- synkit/Graph/Stereo/orbits.py +668 -0
- synkit/Graph/Stereo/outcomes.py +99 -0
- synkit/Graph/Stereo/pairwise.py +350 -0
- synkit/Graph/Stereo/rdkit_adapter.py +662 -0
- synkit/Graph/Stereo/rdkit_identity.py +118 -0
- synkit/Graph/Stereo/rdkit_resonance.py +140 -0
- synkit/Graph/Stereo/reaction_interchange.py +266 -0
- synkit/Graph/Stereo/semantics.py +296 -0
- synkit/Graph/Stereo/supports.py +257 -0
- synkit/Graph/Stereo/wire.py +339 -0
- synkit/Graph/Wildcard/__init__.py +0 -0
- synkit/Graph/Wildcard/fuse_graph.py +156 -0
- synkit/Graph/Wildcard/graph_wc.py +303 -0
- synkit/Graph/Wildcard/its_merge.py +857 -0
- synkit/Graph/Wildcard/radwc.py +114 -0
- synkit/Graph/Wildcard/wc_matcher.py +576 -0
- synkit/Graph/Wildcard/wildcard.py +225 -0
- synkit/Graph/__init__.py +17 -0
- synkit/Graph/canon_graph.py +14 -0
- synkit/Graph/syn_graph.py +199 -0
- synkit/Graph/utils.py +324 -0
- synkit/IO/__init__.py +4 -0
- synkit/IO/chem_converter.py +1059 -0
- synkit/IO/combinatorial/__init__.py +8 -0
- synkit/IO/combinatorial/gml_to_graph.py +223 -0
- synkit/IO/combinatorial/graph_to_gml.py +280 -0
- synkit/IO/combinatorial/graph_to_smarts.py +186 -0
- synkit/IO/combinatorial/smarts_expander.py +147 -0
- synkit/IO/combinatorial/smarts_generalizer.py +133 -0
- synkit/IO/combinatorial/smarts_to_graph.py +179 -0
- synkit/IO/conversion.py +42 -0
- synkit/IO/data_io.py +269 -0
- synkit/IO/data_process.py +143 -0
- synkit/IO/debug.py +73 -0
- synkit/IO/gml_to_nx.py +150 -0
- synkit/IO/graph_to_mol.py +199 -0
- synkit/IO/mol_to_graph.py +1105 -0
- synkit/IO/mol_to_graph_chemistry.py +545 -0
- synkit/IO/nx_to_gml.py +209 -0
- synkit/IO/smiles_to_id.py +123 -0
- synkit/Mechanism/__init__.py +151 -0
- synkit/Mechanism/adapters.py +136 -0
- synkit/Mechanism/audit.py +323 -0
- synkit/Mechanism/benchmark.py +638 -0
- synkit/Mechanism/compatibility.py +13 -0
- synkit/Mechanism/drawing.py +85 -0
- synkit/Mechanism/electron_models.py +725 -0
- synkit/Mechanism/equivalence.py +521 -0
- synkit/Mechanism/evidence.py +262 -0
- synkit/Mechanism/interchange.py +141 -0
- synkit/Mechanism/model.py +918 -0
- synkit/Mechanism/neighbor_stereo.py +312 -0
- synkit/Mechanism/radical_data.py +740 -0
- synkit/Mechanism/replay.py +986 -0
- synkit/Mechanism/schema.py +264 -0
- synkit/Mechanism/stereo_state.py +416 -0
- synkit/Mechanism/symbols.py +91 -0
- synkit/Rule/Apply/__init__.py +35 -0
- synkit/Rule/Apply/conditions.py +45 -0
- synkit/Rule/Apply/dpo.py +998 -0
- synkit/Rule/Apply/rule_matcher.py +218 -0
- synkit/Rule/Apply/validation.py +354 -0
- synkit/Rule/Compose/__init__.py +106 -0
- synkit/Rule/Compose/_identity.py +43 -0
- synkit/Rule/Compose/composition.py +976 -0
- synkit/Rule/Compose/laws.py +439 -0
- synkit/Rule/Compose/search.py +771 -0
- synkit/Rule/Compose/synrule.py +170 -0
- synkit/Rule/Modify/__init__.py +0 -0
- synkit/Rule/Modify/implict_rule.py +56 -0
- synkit/Rule/Modify/longest_path.py +92 -0
- synkit/Rule/Modify/molecule_rule.py +115 -0
- synkit/Rule/Modify/prune_templates.py +78 -0
- synkit/Rule/Modify/rule_utils.py +194 -0
- synkit/Rule/Modify/strip_rule.py +97 -0
- synkit/Rule/__init__.py +28 -0
- synkit/Rule/generic_stereo.py +884 -0
- synkit/Rule/stereo_identity.py +271 -0
- synkit/Rule/syn_rule.py +1090 -0
- synkit/Synthesis/MSR/__init__.py +0 -0
- synkit/Synthesis/MSR/path_finder.py +239 -0
- synkit/Synthesis/Metrics/__init__.py +0 -0
- synkit/Synthesis/Metrics/_base.py +52 -0
- synkit/Synthesis/Metrics/_plot.py +129 -0
- synkit/Synthesis/Metrics/_ranking.py +179 -0
- synkit/Synthesis/RBL/__init__.py +80 -0
- synkit/Synthesis/RBL/engine.py +1249 -0
- synkit/Synthesis/RBL/matching.py +652 -0
- synkit/Synthesis/RBL/overlap.py +336 -0
- synkit/Synthesis/RBL/pipeline.py +376 -0
- synkit/Synthesis/RBL/policy.py +139 -0
- synkit/Synthesis/RBL/proof.py +370 -0
- synkit/Synthesis/RBL/reaction.py +506 -0
- synkit/Synthesis/RBL/state.py +169 -0
- synkit/Synthesis/RBL/validation.py +1060 -0
- synkit/Synthesis/Reactor/__init__.py +60 -0
- synkit/Synthesis/Reactor/core/__init__.py +1 -0
- synkit/Synthesis/Reactor/core/engine.py +967 -0
- synkit/Synthesis/Reactor/core/product.py +621 -0
- synkit/Synthesis/Reactor/core/rewrite.py +561 -0
- synkit/Synthesis/Reactor/core/strategy.py +44 -0
- synkit/Synthesis/Reactor/matching/__init__.py +1 -0
- synkit/Synthesis/Reactor/matching/mixin.py +920 -0
- synkit/Synthesis/Reactor/matching/policy.py +345 -0
- synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
- synkit/Synthesis/Reactor/output/__init__.py +1 -0
- synkit/Synthesis/Reactor/output/deduplication.py +703 -0
- synkit/Synthesis/Reactor/output/policy.py +16 -0
- synkit/Synthesis/Reactor/output/serialization.py +485 -0
- synkit/Synthesis/Reactor/output/structural.py +893 -0
- synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
- synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
- synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
- synkit/Synthesis/Reactor/variants/__init__.py +1 -0
- synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
- synkit/Synthesis/Reactor/variants/partial.py +84 -0
- synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
- synkit/Synthesis/Reactor/workflow/batch.py +550 -0
- synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
- synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
- synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
- synkit/Synthesis/__init__.py +0 -0
- synkit/Synthesis/reactor_utils.py +316 -0
- synkit/Utils/__init__.py +0 -0
- synkit/Utils/utils.py +172 -0
- synkit/Vis/__init__.py +91 -0
- synkit/Vis/crn/__init__.py +40 -0
- synkit/Vis/epd/__init__.py +20 -0
- synkit/Vis/epd/arrows.py +425 -0
- synkit/Vis/epd/chem.py +197 -0
- synkit/Vis/epd/constants.py +83 -0
- synkit/Vis/epd/layout.py +283 -0
- synkit/Vis/epd/mapping.py +51 -0
- synkit/Vis/epd/models.py +136 -0
- synkit/Vis/epd/render.py +543 -0
- synkit/Vis/epd/utils.py +108 -0
- synkit/Vis/epd/visualizer.py +811 -0
- synkit/Vis/graph_visualizer.py +375 -0
- synkit/Vis/its/__init__.py +19 -0
- synkit/Vis/its/drawer.py +615 -0
- synkit/Vis/its_drawer.py +35 -0
- synkit/Vis/molecule/__init__.py +31 -0
- synkit/Vis/molecule/drawer.py +563 -0
- synkit/Vis/molecule/reaction.py +285 -0
- synkit/Vis/molecule_drawer.py +33 -0
- synkit/Vis/mtg/__init__.py +17 -0
- synkit/Vis/mtg/drawer.py +769 -0
- synkit/Vis/mtg_drawer.py +34 -0
- synkit/Vis/pdf_writer.py +146 -0
- synkit/Vis/reaction/__init__.py +19 -0
- synkit/Vis/reaction/rule.py +141 -0
- synkit/Vis/reaction/rxn.py +532 -0
- synkit/Vis/reaction_drawer.py +41 -0
- synkit/Vis/space/__init__.py +17 -0
- synkit/Vis/space/chemical.py +80 -0
- synkit/Vis/space/embedding.py +87 -0
- synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
- synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
- synkit/Vis/vis_synedu/rxn_vis.py +377 -0
- synkit/Vis/vis_synedu/vis.py +501 -0
- synkit/Vis/visual_drawer.py +215 -0
- synkit/Vis/visual_model.py +520 -0
- synkit/__init__.py +3 -0
- synkit/_native.py +91 -0
- synkit/examples.py +50 -0
- synkit/version.py +23 -0
- synkit-1.6.5.dist-info/METADATA +156 -0
- synkit-1.6.5.dist-info/RECORD +636 -0
- synkit-1.6.5.dist-info/WHEEL +4 -0
- synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, Optional, Mapping
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from rxnmapper import RXNMapper as _RXNMapper
|
|
10
|
+
except Exception:
|
|
11
|
+
_RXNMapper = None
|
|
12
|
+
|
|
13
|
+
from .kegg_api import KEGGClient
|
|
14
|
+
from .kegg_parse import (
|
|
15
|
+
equation_to_text,
|
|
16
|
+
get_compound_ids_from_equations,
|
|
17
|
+
get_compound_ids_from_text,
|
|
18
|
+
molblock_to_smiles,
|
|
19
|
+
normalize_module_id,
|
|
20
|
+
orient_equation_to_module,
|
|
21
|
+
parse_equation,
|
|
22
|
+
parse_kegg_field_blocks,
|
|
23
|
+
parse_module_reaction_directions,
|
|
24
|
+
reaction_smiles_from_equation,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_RID_PATTERN = re.compile(r"R\d{5}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
ReactionEquationMap = dict[str, Optional[str]]
|
|
31
|
+
CompoundTable = dict[str, dict[str, Any]]
|
|
32
|
+
ReactionSmilesMap = dict[str, str]
|
|
33
|
+
MissingByReaction = dict[str, dict[str, list[str]]]
|
|
34
|
+
JSONDict = dict[str, Any]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(slots=True)
|
|
38
|
+
class KEGGExtractor:
|
|
39
|
+
"""High-level extractor for KEGG pathway and module reaction data.
|
|
40
|
+
|
|
41
|
+
This class orchestrates KEGG entry retrieval, module membership parsing,
|
|
42
|
+
reaction equation collection, compound-table construction, reaction SMILES
|
|
43
|
+
assembly, and optional atom mapping.
|
|
44
|
+
|
|
45
|
+
:param client:
|
|
46
|
+
Optional KEGG REST client. When omitted, a default :class:`KEGGClient`
|
|
47
|
+
instance is created during :meth:`__post_init__`.
|
|
48
|
+
:type client: Optional[KEGGClient]
|
|
49
|
+
:param mapper_cls:
|
|
50
|
+
Optional atom-mapper class used by :meth:`atom_map_reactions`. The
|
|
51
|
+
class must be instantiable without arguments and must provide
|
|
52
|
+
``get_attention_guided_atom_maps``.
|
|
53
|
+
:type mapper_cls: Optional[type[Any]]
|
|
54
|
+
|
|
55
|
+
.. rubric:: Example
|
|
56
|
+
|
|
57
|
+
.. code-block:: python
|
|
58
|
+
|
|
59
|
+
extractor = KEGGExtractor()
|
|
60
|
+
data = extractor.build_module_json(
|
|
61
|
+
"M00001",
|
|
62
|
+
with_compounds=True,
|
|
63
|
+
with_atom_maps=False,
|
|
64
|
+
)
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
client: Optional[KEGGClient] = None
|
|
68
|
+
mapper_cls: Optional[type[Any]] = _RXNMapper
|
|
69
|
+
|
|
70
|
+
def __post_init__(self) -> None:
|
|
71
|
+
if self.client is None:
|
|
72
|
+
self.client = KEGGClient()
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def save_json(data: Mapping[str, Any], save_as: Optional[str]) -> None:
|
|
76
|
+
"""Save JSON data to disk when an output path is provided.
|
|
77
|
+
|
|
78
|
+
:param data:
|
|
79
|
+
JSON-serializable data to write.
|
|
80
|
+
:type data: Mapping[str, Any]
|
|
81
|
+
:param save_as:
|
|
82
|
+
Optional output path.
|
|
83
|
+
:type save_as: Optional[str]
|
|
84
|
+
|
|
85
|
+
:return:
|
|
86
|
+
``None``.
|
|
87
|
+
:rtype: None
|
|
88
|
+
|
|
89
|
+
.. rubric:: Example
|
|
90
|
+
|
|
91
|
+
.. code-block:: python
|
|
92
|
+
|
|
93
|
+
KEGGExtractor._save_json({"x": 1}, "out.json")
|
|
94
|
+
"""
|
|
95
|
+
if save_as:
|
|
96
|
+
with open(save_as, "w", encoding="utf-8") as handle:
|
|
97
|
+
json.dump(data, handle, ensure_ascii=False, indent=2)
|
|
98
|
+
|
|
99
|
+
def get_modules_from_pathway(self, pathway_id: str) -> list[str]:
|
|
100
|
+
"""Extract module IDs from a KEGG pathway entry.
|
|
101
|
+
|
|
102
|
+
:param pathway_id:
|
|
103
|
+
KEGG pathway identifier such as ``"hsa00010"``.
|
|
104
|
+
:type pathway_id: str
|
|
105
|
+
|
|
106
|
+
:return:
|
|
107
|
+
Canonical KEGG module identifiers such as ``["M00001",
|
|
108
|
+
"M00002"]``.
|
|
109
|
+
:rtype: list[str]
|
|
110
|
+
|
|
111
|
+
.. rubric:: Example
|
|
112
|
+
|
|
113
|
+
.. code-block:: python
|
|
114
|
+
|
|
115
|
+
modules = extractor.get_modules_from_pathway("hsa00010")
|
|
116
|
+
"""
|
|
117
|
+
text = self.client.get_text(f"get/{pathway_id}")
|
|
118
|
+
payloads = parse_kegg_field_blocks(text, "MODULE")
|
|
119
|
+
|
|
120
|
+
modules: list[str] = []
|
|
121
|
+
for payload in payloads:
|
|
122
|
+
for token in payload.split():
|
|
123
|
+
normalized = normalize_module_id(token)
|
|
124
|
+
if normalized is not None:
|
|
125
|
+
modules.append(normalized)
|
|
126
|
+
|
|
127
|
+
return modules
|
|
128
|
+
|
|
129
|
+
def get_reaction_ids_from_module(self, module_id: str) -> list[str]:
|
|
130
|
+
"""Collect KEGG reaction IDs from a module entry, preserving module order when
|
|
131
|
+
directional REACTION lines can be parsed.
|
|
132
|
+
|
|
133
|
+
:param module_id:
|
|
134
|
+
KEGG module identifier such as ``"M00001"``.
|
|
135
|
+
:type module_id: str
|
|
136
|
+
|
|
137
|
+
:return:
|
|
138
|
+
Sorted unique KEGG reaction identifiers.
|
|
139
|
+
:rtype: list[str]
|
|
140
|
+
|
|
141
|
+
.. rubric:: Example
|
|
142
|
+
|
|
143
|
+
.. code-block:: python
|
|
144
|
+
|
|
145
|
+
reaction_ids = extractor.get_reaction_ids_from_module("M00001")
|
|
146
|
+
"""
|
|
147
|
+
text = self.client.get_text(f"get/{module_id}")
|
|
148
|
+
directions = parse_module_reaction_directions(text)
|
|
149
|
+
if directions:
|
|
150
|
+
return list(directions.keys())
|
|
151
|
+
|
|
152
|
+
payloads = parse_kegg_field_blocks(text, "REACTION")
|
|
153
|
+
reaction_ids: set[str] = set()
|
|
154
|
+
for payload in payloads:
|
|
155
|
+
reaction_ids.update(_RID_PATTERN.findall(payload))
|
|
156
|
+
|
|
157
|
+
return sorted(reaction_ids)
|
|
158
|
+
|
|
159
|
+
def get_equation_for_reaction(self, reaction_id: str) -> Optional[str]:
|
|
160
|
+
"""Fetch the KEGG equation string for a reaction.
|
|
161
|
+
|
|
162
|
+
:param reaction_id:
|
|
163
|
+
KEGG reaction identifier such as ``"R00200"``.
|
|
164
|
+
:type reaction_id: str
|
|
165
|
+
|
|
166
|
+
:return:
|
|
167
|
+
Equation string when present, otherwise ``None``.
|
|
168
|
+
:rtype: Optional[str]
|
|
169
|
+
|
|
170
|
+
.. rubric:: Example
|
|
171
|
+
|
|
172
|
+
.. code-block:: python
|
|
173
|
+
|
|
174
|
+
equation = extractor.get_equation_for_reaction("R00200")
|
|
175
|
+
"""
|
|
176
|
+
text = self.client.get_text(f"get/rn:{reaction_id}")
|
|
177
|
+
payloads = parse_kegg_field_blocks(text, "EQUATION")
|
|
178
|
+
return payloads[0].strip() if payloads else None
|
|
179
|
+
|
|
180
|
+
def get_module_equations(self, module_id: str) -> ReactionEquationMap:
|
|
181
|
+
"""Build a reaction-to-equation mapping for a KEGG module.
|
|
182
|
+
|
|
183
|
+
:param module_id:
|
|
184
|
+
KEGG module identifier.
|
|
185
|
+
:type module_id: str
|
|
186
|
+
|
|
187
|
+
:return:
|
|
188
|
+
Mapping from reaction identifier to equation string.
|
|
189
|
+
:rtype: dict[str, Optional[str]]
|
|
190
|
+
|
|
191
|
+
.. rubric:: Example
|
|
192
|
+
|
|
193
|
+
.. code-block:: python
|
|
194
|
+
|
|
195
|
+
equations = extractor.get_module_equations("M00001")
|
|
196
|
+
"""
|
|
197
|
+
module_text = self.client.get_text(f"get/{module_id}")
|
|
198
|
+
directions = parse_module_reaction_directions(module_text)
|
|
199
|
+
|
|
200
|
+
reaction_ids = (
|
|
201
|
+
list(directions.keys())
|
|
202
|
+
if directions
|
|
203
|
+
else self.get_reaction_ids_from_module(module_id)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
equations_by_rid: ReactionEquationMap = {}
|
|
207
|
+
|
|
208
|
+
for reaction_id in reaction_ids:
|
|
209
|
+
equation = self.get_equation_for_reaction(reaction_id)
|
|
210
|
+
if equation is None:
|
|
211
|
+
equations_by_rid[reaction_id] = None
|
|
212
|
+
continue
|
|
213
|
+
|
|
214
|
+
if reaction_id not in directions:
|
|
215
|
+
equations_by_rid[reaction_id] = equation
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
left_ids, right_ids, module_arrow = directions[reaction_id]
|
|
219
|
+
parsed = parse_equation(equation)
|
|
220
|
+
oriented = orient_equation_to_module(parsed, left_ids, right_ids)
|
|
221
|
+
equations_by_rid[reaction_id] = equation_to_text(
|
|
222
|
+
oriented, arrow=module_arrow
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return equations_by_rid
|
|
226
|
+
|
|
227
|
+
def get_pathway_equations(
|
|
228
|
+
self,
|
|
229
|
+
pathway_id: str,
|
|
230
|
+
) -> dict[str, ReactionEquationMap]:
|
|
231
|
+
"""Build nested module/reaction equation mappings for a pathway.
|
|
232
|
+
|
|
233
|
+
:param pathway_id:
|
|
234
|
+
KEGG pathway identifier.
|
|
235
|
+
:type pathway_id: str
|
|
236
|
+
|
|
237
|
+
:return:
|
|
238
|
+
Mapping of the form ``{module_id: {reaction_id: equation}}``.
|
|
239
|
+
:rtype: dict[str, dict[str, Optional[str]]]
|
|
240
|
+
|
|
241
|
+
.. rubric:: Example
|
|
242
|
+
|
|
243
|
+
.. code-block:: python
|
|
244
|
+
|
|
245
|
+
nested = extractor.get_pathway_equations("hsa00010")
|
|
246
|
+
"""
|
|
247
|
+
modules = self.get_modules_from_pathway(pathway_id)
|
|
248
|
+
return {
|
|
249
|
+
module_id: self.get_module_equations(module_id) for module_id in modules
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
def get_compound_name(self, compound_id: str) -> Optional[str]:
|
|
253
|
+
"""Retrieve the primary KEGG compound name.
|
|
254
|
+
|
|
255
|
+
When multiple synonyms are present in the ``NAME`` field, only the
|
|
256
|
+
first entry is returned.
|
|
257
|
+
|
|
258
|
+
:param compound_id:
|
|
259
|
+
KEGG compound identifier such as ``"C00001"``.
|
|
260
|
+
:type compound_id: str
|
|
261
|
+
|
|
262
|
+
:return:
|
|
263
|
+
Primary compound name if available, otherwise ``None``.
|
|
264
|
+
:rtype: Optional[str]
|
|
265
|
+
|
|
266
|
+
.. rubric:: Example
|
|
267
|
+
|
|
268
|
+
.. code-block:: python
|
|
269
|
+
|
|
270
|
+
name = extractor.get_compound_name("C00001")
|
|
271
|
+
"""
|
|
272
|
+
text = self.client.get_text(f"get/cpd:{compound_id}")
|
|
273
|
+
payloads = parse_kegg_field_blocks(text, "NAME")
|
|
274
|
+
if not payloads:
|
|
275
|
+
return None
|
|
276
|
+
|
|
277
|
+
first_payload = payloads[0].strip()
|
|
278
|
+
return first_payload.split(";")[0].strip()
|
|
279
|
+
|
|
280
|
+
def get_compound_molblock(self, compound_id: str) -> Optional[str]:
|
|
281
|
+
"""Retrieve the KEGG MOL block for a compound.
|
|
282
|
+
|
|
283
|
+
:param compound_id:
|
|
284
|
+
KEGG compound identifier.
|
|
285
|
+
:type compound_id: str
|
|
286
|
+
|
|
287
|
+
:return:
|
|
288
|
+
MOL block text when available, otherwise ``None``.
|
|
289
|
+
:rtype: Optional[str]
|
|
290
|
+
|
|
291
|
+
.. rubric:: Example
|
|
292
|
+
|
|
293
|
+
.. code-block:: python
|
|
294
|
+
|
|
295
|
+
molblock = extractor.get_compound_molblock("C00001")
|
|
296
|
+
"""
|
|
297
|
+
return self.client.get_optional_text(f"get/cpd:{compound_id}/mol")
|
|
298
|
+
|
|
299
|
+
def build_compound_table(
|
|
300
|
+
self,
|
|
301
|
+
compound_ids: list[str],
|
|
302
|
+
) -> CompoundTable:
|
|
303
|
+
"""Build a compound table for a list of KEGG compound identifiers.
|
|
304
|
+
|
|
305
|
+
Each returned record includes the KEGG compound identifier, the primary
|
|
306
|
+
compound name, the optional MOL block, and a canonical SMILES string
|
|
307
|
+
derived from the MOL block when RDKit parsing succeeds.
|
|
308
|
+
|
|
309
|
+
:param compound_ids:
|
|
310
|
+
KEGG compound identifiers.
|
|
311
|
+
:type compound_ids: list[str]
|
|
312
|
+
|
|
313
|
+
:return:
|
|
314
|
+
Compound table of the form
|
|
315
|
+
``{cid: {"id", "name", "smiles", "molblock"}}``.
|
|
316
|
+
:rtype: dict[str, dict[str, Any]]
|
|
317
|
+
|
|
318
|
+
.. rubric:: Example
|
|
319
|
+
|
|
320
|
+
.. code-block:: python
|
|
321
|
+
|
|
322
|
+
compounds = extractor.build_compound_table(["C00001", "C00002"])
|
|
323
|
+
"""
|
|
324
|
+
compounds: CompoundTable = {}
|
|
325
|
+
|
|
326
|
+
for compound_id in compound_ids:
|
|
327
|
+
name = self.get_compound_name(compound_id)
|
|
328
|
+
molblock = self.get_compound_molblock(compound_id)
|
|
329
|
+
smiles = molblock_to_smiles(molblock)
|
|
330
|
+
|
|
331
|
+
compounds[compound_id] = {
|
|
332
|
+
"id": compound_id,
|
|
333
|
+
"name": name,
|
|
334
|
+
"smiles": smiles,
|
|
335
|
+
"molblock": molblock,
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return compounds
|
|
339
|
+
|
|
340
|
+
def build_reaction_smiles_dict(
|
|
341
|
+
self,
|
|
342
|
+
parsed_by_rid: Mapping[str, Any],
|
|
343
|
+
compounds_by_cid: Mapping[str, Mapping[str, Any]],
|
|
344
|
+
) -> tuple[ReactionSmilesMap, MissingByReaction]:
|
|
345
|
+
"""Build reaction SMILES strings for parsed KEGG equations.
|
|
346
|
+
|
|
347
|
+
:param parsed_by_rid:
|
|
348
|
+
Parsed equation objects keyed by reaction identifier.
|
|
349
|
+
:type parsed_by_rid: Mapping[str, Any]
|
|
350
|
+
:param compounds_by_cid:
|
|
351
|
+
Compound table keyed by KEGG compound identifier.
|
|
352
|
+
:type compounds_by_cid: Mapping[str, Mapping[str, Any]]
|
|
353
|
+
|
|
354
|
+
:return:
|
|
355
|
+
Tuple ``(reaction_smiles_by_id, missing_by_id)``.
|
|
356
|
+
:rtype: tuple[dict[str, str], dict[str, dict[str, list[str]]]]
|
|
357
|
+
|
|
358
|
+
.. rubric:: Example
|
|
359
|
+
|
|
360
|
+
.. code-block:: python
|
|
361
|
+
|
|
362
|
+
rsmi_by_rid, missing = extractor.build_reaction_smiles_dict(
|
|
363
|
+
parsed_by_rid,
|
|
364
|
+
compounds_by_cid,
|
|
365
|
+
)
|
|
366
|
+
"""
|
|
367
|
+
reaction_smiles: ReactionSmilesMap = {}
|
|
368
|
+
missing_by_rid: MissingByReaction = {}
|
|
369
|
+
|
|
370
|
+
for reaction_id, parsed_equation in parsed_by_rid.items():
|
|
371
|
+
rsmi, missing = reaction_smiles_from_equation(
|
|
372
|
+
parsed_equation,
|
|
373
|
+
compounds_by_cid,
|
|
374
|
+
)
|
|
375
|
+
reaction_smiles[reaction_id] = rsmi
|
|
376
|
+
missing_by_rid[reaction_id] = missing
|
|
377
|
+
|
|
378
|
+
return reaction_smiles, missing_by_rid
|
|
379
|
+
|
|
380
|
+
def atom_map_reactions(
|
|
381
|
+
self,
|
|
382
|
+
reaction_smiles_by_id: Mapping[str, str],
|
|
383
|
+
) -> dict[str, Optional[str]]:
|
|
384
|
+
"""Atom-map reaction SMILES using RXNMapper.
|
|
385
|
+
|
|
386
|
+
:param reaction_smiles_by_id:
|
|
387
|
+
Mapping ``{reaction_id: reaction_smiles}``.
|
|
388
|
+
:type reaction_smiles_by_id: Mapping[str, str]
|
|
389
|
+
|
|
390
|
+
:return:
|
|
391
|
+
Mapping ``{reaction_id: mapped_reaction_smiles_or_none}``.
|
|
392
|
+
:rtype: dict[str, Optional[str]]
|
|
393
|
+
|
|
394
|
+
.. rubric:: Example
|
|
395
|
+
|
|
396
|
+
.. code-block:: python
|
|
397
|
+
|
|
398
|
+
mapped = extractor.atom_map_reactions({"R00001": "CCO>>CC=O"})
|
|
399
|
+
"""
|
|
400
|
+
mapper = self.mapper_cls() if self.mapper_cls is not None else None
|
|
401
|
+
mapped_by_id: dict[str, Optional[str]] = {}
|
|
402
|
+
|
|
403
|
+
for reaction_id, reaction_smiles in reaction_smiles_by_id.items():
|
|
404
|
+
if (
|
|
405
|
+
">>" not in reaction_smiles
|
|
406
|
+
or reaction_smiles.startswith(">>")
|
|
407
|
+
or reaction_smiles.endswith(">>")
|
|
408
|
+
):
|
|
409
|
+
mapped_by_id[reaction_id] = None
|
|
410
|
+
continue
|
|
411
|
+
|
|
412
|
+
try:
|
|
413
|
+
result = mapper.get_attention_guided_atom_maps([reaction_smiles])[0]
|
|
414
|
+
mapped_by_id[reaction_id] = result.get("mapped_rxn")
|
|
415
|
+
except Exception:
|
|
416
|
+
mapped_by_id[reaction_id] = None
|
|
417
|
+
|
|
418
|
+
return mapped_by_id
|
|
419
|
+
|
|
420
|
+
def build_missing_compound_report(
|
|
421
|
+
self,
|
|
422
|
+
equations_by_rid: ReactionEquationMap,
|
|
423
|
+
compounds_by_cid: Mapping[str, Mapping[str, Any]],
|
|
424
|
+
) -> JSONDict:
|
|
425
|
+
"""Build a report for compounds lacking SMILES.
|
|
426
|
+
|
|
427
|
+
:param equations_by_rid:
|
|
428
|
+
Reaction equations keyed by reaction identifier.
|
|
429
|
+
:type equations_by_rid: dict[str, Optional[str]]
|
|
430
|
+
:param compounds_by_cid:
|
|
431
|
+
Compound records keyed by KEGG compound identifier.
|
|
432
|
+
:type compounds_by_cid: Mapping[str, Mapping[str, Any]]
|
|
433
|
+
|
|
434
|
+
:return:
|
|
435
|
+
Report containing missing compounds and per-reaction provenance.
|
|
436
|
+
:rtype: dict[str, Any]
|
|
437
|
+
|
|
438
|
+
.. rubric:: Example
|
|
439
|
+
|
|
440
|
+
.. code-block:: python
|
|
441
|
+
|
|
442
|
+
report = extractor.build_missing_compound_report(
|
|
443
|
+
equations_by_rid,
|
|
444
|
+
compounds_by_cid,
|
|
445
|
+
)
|
|
446
|
+
"""
|
|
447
|
+
cid_to_rids: dict[str, set[str]] = {}
|
|
448
|
+
|
|
449
|
+
for reaction_id, equation in equations_by_rid.items():
|
|
450
|
+
if not equation:
|
|
451
|
+
continue
|
|
452
|
+
|
|
453
|
+
for compound_id in get_compound_ids_from_text(equation):
|
|
454
|
+
cid_to_rids.setdefault(compound_id, set()).add(reaction_id)
|
|
455
|
+
|
|
456
|
+
missing_compounds: list[dict[str, Any]] = []
|
|
457
|
+
missing_ids: set[str] = set()
|
|
458
|
+
involving_reactions: set[str] = set()
|
|
459
|
+
|
|
460
|
+
for compound_id, record in compounds_by_cid.items():
|
|
461
|
+
if record.get("smiles") is None:
|
|
462
|
+
reaction_ids = sorted(cid_to_rids.get(compound_id, set()))
|
|
463
|
+
missing_compounds.append(
|
|
464
|
+
{
|
|
465
|
+
"id": compound_id,
|
|
466
|
+
"name": record.get("name"),
|
|
467
|
+
"reactions": reaction_ids,
|
|
468
|
+
}
|
|
469
|
+
)
|
|
470
|
+
missing_ids.add(compound_id)
|
|
471
|
+
involving_reactions.update(reaction_ids)
|
|
472
|
+
|
|
473
|
+
missing_compounds.sort(key=lambda record: record["id"])
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
"missing_compounds": missing_compounds,
|
|
477
|
+
"missing_compound_ids": sorted(missing_ids),
|
|
478
|
+
"reactions_involving_missing": sorted(involving_reactions),
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
def build_kegg_json(
|
|
482
|
+
self,
|
|
483
|
+
equations_by_rid: ReactionEquationMap,
|
|
484
|
+
*,
|
|
485
|
+
smiles_by_rid: Optional[Mapping[str, str]] = None,
|
|
486
|
+
rules_by_rid: Optional[Mapping[str, Optional[str]]] = None,
|
|
487
|
+
molecules_by_cid: Optional[Mapping[str, Mapping[str, Any]]] = None,
|
|
488
|
+
) -> JSONDict:
|
|
489
|
+
"""Build a compact KEGG JSON block with reactions and molecules.
|
|
490
|
+
|
|
491
|
+
:param equations_by_rid:
|
|
492
|
+
Reaction equations keyed by reaction identifier.
|
|
493
|
+
:type equations_by_rid: dict[str, Optional[str]]
|
|
494
|
+
:param smiles_by_rid:
|
|
495
|
+
Optional reaction SMILES keyed by reaction identifier.
|
|
496
|
+
:type smiles_by_rid: Optional[Mapping[str, str]]
|
|
497
|
+
:param rules_by_rid:
|
|
498
|
+
Optional atom-mapped reaction strings keyed by reaction identifier.
|
|
499
|
+
:type rules_by_rid: Optional[Mapping[str, Optional[str]]]
|
|
500
|
+
:param molecules_by_cid:
|
|
501
|
+
Optional molecule table keyed by compound identifier.
|
|
502
|
+
:type molecules_by_cid: Optional[Mapping[str, Mapping[str, Any]]]
|
|
503
|
+
|
|
504
|
+
:return:
|
|
505
|
+
Dictionary with ``"reactions"`` and ``"molecules"`` entries.
|
|
506
|
+
:rtype: dict[str, Any]
|
|
507
|
+
|
|
508
|
+
.. rubric:: Example
|
|
509
|
+
|
|
510
|
+
.. code-block:: python
|
|
511
|
+
|
|
512
|
+
data = extractor.build_kegg_json(equations_by_rid)
|
|
513
|
+
"""
|
|
514
|
+
smiles_by_rid = dict(smiles_by_rid or {})
|
|
515
|
+
rules_by_rid = dict(rules_by_rid or {})
|
|
516
|
+
molecules_by_cid = dict(molecules_by_cid or {})
|
|
517
|
+
|
|
518
|
+
all_compound_ids: set[str] = set()
|
|
519
|
+
reactions: list[dict[str, Any]] = []
|
|
520
|
+
|
|
521
|
+
for reaction_id in sorted(equations_by_rid.keys()):
|
|
522
|
+
equation = equations_by_rid[reaction_id]
|
|
523
|
+
if not equation:
|
|
524
|
+
continue
|
|
525
|
+
|
|
526
|
+
all_compound_ids.update(get_compound_ids_from_text(equation))
|
|
527
|
+
reactions.append(
|
|
528
|
+
{
|
|
529
|
+
"id": reaction_id,
|
|
530
|
+
"reaction": equation,
|
|
531
|
+
"rule": rules_by_rid.get(reaction_id),
|
|
532
|
+
"smiles": smiles_by_rid.get(reaction_id),
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
molecules: list[dict[str, Any]] = []
|
|
537
|
+
for compound_id in sorted(all_compound_ids):
|
|
538
|
+
record = molecules_by_cid.get(
|
|
539
|
+
compound_id,
|
|
540
|
+
{"id": compound_id, "name": None, "smiles": None},
|
|
541
|
+
)
|
|
542
|
+
molecules.append(
|
|
543
|
+
{
|
|
544
|
+
"id": compound_id,
|
|
545
|
+
"name": record.get("name"),
|
|
546
|
+
"smiles": record.get("smiles"),
|
|
547
|
+
}
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
return {"reactions": reactions, "molecules": molecules}
|
|
551
|
+
|
|
552
|
+
def build_module_json(
|
|
553
|
+
self,
|
|
554
|
+
module_id: str,
|
|
555
|
+
*,
|
|
556
|
+
with_compounds: bool = True,
|
|
557
|
+
with_atom_maps: bool = True,
|
|
558
|
+
save_as: Optional[str] = None,
|
|
559
|
+
) -> JSONDict:
|
|
560
|
+
"""Build a JSON block for a KEGG module.
|
|
561
|
+
|
|
562
|
+
:param module_id:
|
|
563
|
+
KEGG module ID.
|
|
564
|
+
:type module_id: str
|
|
565
|
+
:param with_compounds:
|
|
566
|
+
Whether to resolve compound names, MOL blocks, and SMILES strings.
|
|
567
|
+
:type with_compounds: bool
|
|
568
|
+
:param with_atom_maps:
|
|
569
|
+
Whether to compute atom-mapped reactions.
|
|
570
|
+
:type with_atom_maps: bool
|
|
571
|
+
:param save_as:
|
|
572
|
+
Optional output path for writing the JSON block to disk.
|
|
573
|
+
:type save_as: Optional[str]
|
|
574
|
+
|
|
575
|
+
:return:
|
|
576
|
+
Module JSON dictionary.
|
|
577
|
+
:rtype: dict[str, Any]
|
|
578
|
+
|
|
579
|
+
.. rubric:: Example
|
|
580
|
+
|
|
581
|
+
.. code-block:: python
|
|
582
|
+
|
|
583
|
+
data = extractor.build_module_json(
|
|
584
|
+
"M00001",
|
|
585
|
+
with_compounds=True,
|
|
586
|
+
with_atom_maps=False,
|
|
587
|
+
)
|
|
588
|
+
"""
|
|
589
|
+
equations_by_rid = self.get_module_equations(module_id)
|
|
590
|
+
compound_ids, parsed_by_rid = get_compound_ids_from_equations(equations_by_rid)
|
|
591
|
+
|
|
592
|
+
compounds_by_cid = (
|
|
593
|
+
self.build_compound_table(compound_ids) if with_compounds else {}
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
reaction_smiles_by_rid, _ = (
|
|
597
|
+
self.build_reaction_smiles_dict(parsed_by_rid, compounds_by_cid)
|
|
598
|
+
if with_compounds
|
|
599
|
+
else ({}, {})
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
rules_by_rid = (
|
|
603
|
+
self.atom_map_reactions(reaction_smiles_by_rid)
|
|
604
|
+
if (with_compounds and with_atom_maps)
|
|
605
|
+
else {}
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
data: JSONDict = {"module_id": module_id}
|
|
609
|
+
data.update(
|
|
610
|
+
self.build_kegg_json(
|
|
611
|
+
equations_by_rid,
|
|
612
|
+
smiles_by_rid=reaction_smiles_by_rid,
|
|
613
|
+
rules_by_rid=rules_by_rid,
|
|
614
|
+
molecules_by_cid={
|
|
615
|
+
cid: {
|
|
616
|
+
"id": cid,
|
|
617
|
+
"name": compounds_by_cid[cid]["name"],
|
|
618
|
+
"smiles": compounds_by_cid[cid]["smiles"],
|
|
619
|
+
}
|
|
620
|
+
for cid in compounds_by_cid
|
|
621
|
+
},
|
|
622
|
+
)
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
if with_compounds:
|
|
626
|
+
data["missing"] = self.build_missing_compound_report(
|
|
627
|
+
equations_by_rid,
|
|
628
|
+
compounds_by_cid,
|
|
629
|
+
)
|
|
630
|
+
else:
|
|
631
|
+
data["missing"] = {
|
|
632
|
+
"missing_compounds": [],
|
|
633
|
+
"missing_compound_ids": [],
|
|
634
|
+
"reactions_involving_missing": [],
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
self.save_json(data, save_as)
|
|
638
|
+
|
|
639
|
+
return data
|
|
640
|
+
|
|
641
|
+
def build_pathway_json(
|
|
642
|
+
self,
|
|
643
|
+
pathway_id: str,
|
|
644
|
+
*,
|
|
645
|
+
with_compounds: bool = True,
|
|
646
|
+
with_atom_maps: bool = True,
|
|
647
|
+
save_as: Optional[str] = None,
|
|
648
|
+
) -> JSONDict:
|
|
649
|
+
"""Build a JSON block for a KEGG pathway, organized by module.
|
|
650
|
+
|
|
651
|
+
:param pathway_id:
|
|
652
|
+
KEGG pathway ID.
|
|
653
|
+
:type pathway_id: str
|
|
654
|
+
:param with_compounds:
|
|
655
|
+
Whether to resolve compound records.
|
|
656
|
+
:type with_compounds: bool
|
|
657
|
+
:param with_atom_maps:
|
|
658
|
+
Whether to compute atom-mapped reactions.
|
|
659
|
+
:type with_atom_maps: bool
|
|
660
|
+
:param save_as:
|
|
661
|
+
Optional output path for writing the JSON block to disk.
|
|
662
|
+
:type save_as: Optional[str]
|
|
663
|
+
|
|
664
|
+
:return:
|
|
665
|
+
Pathway JSON dictionary.
|
|
666
|
+
:rtype: dict[str, Any]
|
|
667
|
+
|
|
668
|
+
.. rubric:: Example
|
|
669
|
+
|
|
670
|
+
.. code-block:: python
|
|
671
|
+
|
|
672
|
+
data = extractor.build_pathway_json(
|
|
673
|
+
"hsa00010",
|
|
674
|
+
with_compounds=True,
|
|
675
|
+
with_atom_maps=False,
|
|
676
|
+
)
|
|
677
|
+
"""
|
|
678
|
+
modules = self.get_modules_from_pathway(pathway_id)
|
|
679
|
+
by_module: dict[str, Any] = {}
|
|
680
|
+
|
|
681
|
+
aggregate_missing_ids: set[str] = set()
|
|
682
|
+
aggregate_reaction_ids: set[str] = set()
|
|
683
|
+
|
|
684
|
+
for module_id in modules:
|
|
685
|
+
module_block = self.build_module_json(
|
|
686
|
+
module_id,
|
|
687
|
+
with_compounds=with_compounds,
|
|
688
|
+
with_atom_maps=with_atom_maps,
|
|
689
|
+
)
|
|
690
|
+
by_module[module_id] = module_block
|
|
691
|
+
|
|
692
|
+
if with_compounds and "missing" in module_block:
|
|
693
|
+
aggregate_missing_ids.update(
|
|
694
|
+
module_block["missing"].get("missing_compound_ids", [])
|
|
695
|
+
)
|
|
696
|
+
aggregate_reaction_ids.update(
|
|
697
|
+
module_block["missing"].get("reactions_involving_missing", [])
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
data: JSONDict = {
|
|
701
|
+
"pathway_id": pathway_id,
|
|
702
|
+
"modules": modules,
|
|
703
|
+
"by_module": by_module,
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if with_compounds:
|
|
707
|
+
data["missing"] = {
|
|
708
|
+
"missing_compound_ids": sorted(aggregate_missing_ids),
|
|
709
|
+
"reactions_involving_missing": sorted(aggregate_reaction_ids),
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
self.save_json(data, save_as)
|
|
713
|
+
|
|
714
|
+
return data
|