Skip to content

Changes by Jules#104

Open
akutuva21 wants to merge 851 commits into
RuleWorld:mainfrom
akutuva21:main
Open

Changes by Jules#104
akutuva21 wants to merge 851 commits into
RuleWorld:mainfrom
akutuva21:main

Conversation

@akutuva21

Copy link
Copy Markdown
Member

PyBioNetGen: Security, Performance, Code Health, and Test Coverage Overhaul

Summary

This PR rolls up 419 commits spanning April 13 – June 4, 2026 into a single contribution against PyBioNetGen. It touches 151 unique files with roughly +10,800 / −9,100 lines changed across the run. The work is a broad maintenance and hardening pass over the codebase — closing security holes, eliminating long-standing TODO/FIXME/assert debt, optimizing hot paths, and substantially expanding test coverage — alongside a set of targeted bug fixes in the SBML→BNGL atomizer and the simulator/runner stack.

Work was developed with assistance from AI coding agents (Jules), with all commits co-authored and reviewed; Co-authored-by trailers credit google-labs-jules[bot] on ~115 commits.

Commit breakdown by category

Category Count
Bug fixes 113
Code health / refactor 101
Test coverage 88
Performance 33
Security 18
Features 11
PR merges / integration 14
Docs 1
Misc / formatting 40

Most-affected files

atomizer/sbml2bngl.py, core/tools/visualize.py, modelapi/runner.py, atomizer/bngModel.py, simulator/csimulator.py, atomizer/libsbml2bngl.py, modelapi/bngfile.py, and merging/namingDatabase.py, plus a large number of new and expanded test modules under tests/.


1. Security fixes

Hardening focused on unsafe deserialization, code injection vectors, XML parsing, path traversal, and leaked secrets.

  • Insecure deserialization removed in multiple modules: replaced unsafe pickle.load with json.load in atomizer/contactMap.py and annotationComparison.py, and fixed insecure deserialization in detectOntology.py.
  • eval()ast.literal_eval() across the atomizer and postAnalysis.py to remove arbitrary-code-execution risk.
  • ast.literal_eval DoS vulnerabilities fixed in postAnalysis.py and analyzeTrends (untrusted assumption strings), with one path further hardened by switching to json.loads.
  • XXE (XML External Entity) mitigation in readBNGXML.py and a full migration to defusedxml for safe XML parsing.
  • Path traversal in tarfile.extractall resolved.
  • Insecure YAML loading replaced (yaml.loadyaml.safe_load).
  • Hardcoded BioGRID API key removed from pathwaycommons.py; the key is now read from the BIOGRID_API_KEY environment variable with a graceful warning-and-skip fallback when unset.
  • Secure handling of missing molec.name in the atomizer.

2. Performance optimizations

  • NamingDatabase SQLite layer: persistent connection handling and reduced per-query overhead, reported as a ~3.7x query speedup; fixed an N+1 query in annotation insertion; batched annotation-ID caching to avoid full-table refetches; batched SQL in namespace detection.
  • String concatenation hot paths converted to join/buffered builds in bnglReaction, bnglWriter.py, BNGResult.__repr__, bngmodel.__str__, and side_string.
  • Membership checks converted from list/tuple scans to set lookups in tight loops (moleculeCreation, smallStructures, classifyReactions, atomizer constant lists).
  • Regex compilation/substitution caching in bnglWriter.py and distanceToModification; Levenshtein distance memoized in analyzeSBML.
  • Replaced type() == list checks with isinstance(), removed redundant .keys() lookups and len() == 0 checks, and added early-exit traversal in deleteMolecule.
  • Cached queryActiveSite within the resolveSCT loop.

3. Code health & refactoring

  • Error-handling modernization: transitioned assert statements to structured BNGError/BNGParseError plus BNGLogger across reactions parsing, csimulator init, network.py, and model parsing; replaced bare except clauses with specific exceptions; converted silent assignment failures to logged warnings.
  • os.chdir / CWD discipline: a large sustained effort to eliminate working-directory leaks — refactored VisResult and visualize.py to avoid os.chdir, wrapped directory changes in try/finally, replaced a module-level app instantiation that corrupted CWD, and used TemporaryDirectory contexts correctly. This resolved widespread Windows PermissionError/WinError 32 and FileNotFoundError failures in CI.
  • Topological sorting: function/dependency ordering in libsbml2bngl.py and bngModel.py refactored to use networkx topological sort (Kahn's algorithm).
  • Resolved numerous TODO/FIXME items and removed dead code throughout the atomizer, network structs, and model API; standardized shutil import (dropped the import shutil as spawn alias); refactored oversized files (e.g. splitting sbml2bngl.py helpers into utility modules) and long methods (ActionList.__init__).
  • Repo-wide black formatting and removal of stray test/build artifacts.

4. Bug fixes

  • SBML→BNGL converter correctness: fixed reaction-rate stoichiometry symmetry factors (removing an incorrect mathematical hack), mass-action kinetics detection, compartment removal in rate expressions, constant species-name parsing, parameter-namespace handling for observables and assignment rules, and correct updating of observablesDict when overridden by assignment rules. Fixed nl/nr assignment when reactants/products appear in rate expressions.
  • Atomizer: outer-compartment logic in Pattern, dimer component classification, volume adjustment for multiple species in rate functions, double-modification queueing in SCTSolver, and parameter namespace collisions in bngModel assignment rules.
  • Graph diff (gdiff): fixed single-node-to-list conversion and nested node recoloring/renaming.
  • Runner/simulator: bngl2xml now runs with a multiprocessing/subprocess timeout; fixed runner.py SectionProxy attribute error; restored CWD in finally blocks across visualize/runner/atomizer/simulator.
  • CLI: BioNetGen version is auto-loaded via module metadata for the --version flag (after one revert/re-land cycle); fixed BNGPATH resolution when BNG2.pl is on PATH.
  • Empty ListOfBonds tag handling in xmltodict parsing; invalid escape sequences in parameter rate-rule regexes; setup.py duplicate manifest inclusions.

5. New features

  • Parsing support for Include/Exclude Reactants/Products rule modifiers.
  • PSA simulation arguments added (poplevel, check_product_scale) and a psa simulation method.
  • Mathematical parameter evaluation via sympy in ParameterBlock / NetworkBlock.add_item.
  • BNGResult extension-based file filtering; standalone find_dat_files / load_results methods; consolidated path argument in the constructor.
  • A verbosity option for the parser and XML parsing logging.
  • add_bngl_function helper migrated into the bngModel class.

6. Test coverage

~88 commits add or expand tests, with new suites for pathwaycommons (BioGRID/Reactome/Uniprot query paths and HTTPError fallbacks), detectOntology.levenshtein, sbml2json utilities, the csimulator/libRRSimulator wrappers, BNGSimulator properties, gdiff, sympy_odes, Pattern equality, ModelObj/ActionBlock operations, the runner, and the notebook/graphdiff CLI commands. Several commits specifically add exception-path and edge-case coverage (e.g. add_block, _safe_rmtree OS errors, _get_color_id).


Notes for reviewers

  • The history includes a number of CI-stabilization commits (Windows file-locking/CWD fixes, black formatting, pytest-mockunittest.mock, Python 3.8 compatibility for parenthesized with) that account for some apparent duplication in the log; the net effect is a green, cross-platform test suite.
  • Commits 285–297 (Merging PR #340#367) and a few others fold in earlier sub-PRs from the same branch series.
  • Given the size, this is best reviewed by category (security → performance → atomizer correctness → tests) rather than commit-by-commit. Happy to split into smaller PRs along those lines if preferred.

akutuva21 and others added 30 commits June 2, 2026 10:57
…3761045350582060

🧹 [Code Health] Simplify dictionary lookup logic in sbml2bngl.py
…recated actions

- Run black on 9 files failing formatting check
- Fix _resolve_block_adder to raise BNGModelError instead of ValueError
- Fix test assertion expectations to match actual exception types
- Fix simulator tests to properly skip when BNG2.pl unavailable
- Update deprecated actions/checkout@v2/v3 to v4
- Update deprecated docker actions from v2 to v3/v5/v6
…ssertions, mock exception types, and SBML skip
Extracted duplicate logic for grouping equivalent molecules from different rules in `contextAnalyzer.py` into a new `groupEquivalentItems` helper function. This satisfies the long-standing "TODO: i have to find the way to group together equivalent molecules from different rules and find the metarule" and improves code readability.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…g slicing.

* Fix contactMap.py to only process the first cluster using slicing.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix contactMap.py to only process the first cluster using slicing.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix contactMap.py to only process the first cluster using slicing.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Fix string copying bug in analyzeSBML by performing token-based prefix matching

The original logic was iterating character-by-character over
`tmpRuleList[1][0]` and checking if the character itself (`in sym`)
was present in the list of symbols (`sym`). However, `sym` can contain
multi-character strings (e.g. '~P', '~U'), meaning the first character
('~') alone evaluates to False, causing the loop to fail to copy the
symbols properly.

The fix sorts the symbols by length in descending order to handle
overlapping prefixes correctly and then uses `.startswith` from the
current index to greedily match the longest possible valid string
token in `sym`.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix string copying bug in analyzeSBML by performing token-based prefix matching

The original logic was iterating character-by-character over
`tmpRuleList[1][0]` and checking if the character itself (`in sym`)
was present in the list of symbols (`sym`). However, `sym` can contain
multi-character strings (e.g. '~P', '~U'), meaning the first character
('~') alone evaluates to False, causing the loop to fail to copy the
symbols properly.

The fix sorts the symbols by length in descending order to handle
overlapping prefixes correctly and then uses `.startswith` from the
current index to greedily match the longest possible valid string
token in `sym`.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix string copying bug in analyzeSBML by performing token-based prefix matching

The original logic was iterating character-by-character over
`tmpRuleList[1][0]` and checking if the character itself (`in sym`)
was present in the list of symbols (`sym`). However, `sym` can contain
multi-character strings (e.g. '~P', '~U'), meaning the first character
('~') alone evaluates to False, causing the loop to fail to copy the
symbols properly.

The fix sorts the symbols by length in descending order to handle
overlapping prefixes correctly and then uses `.startswith` from the
current index to greedily match the longest possible valid string
token in `sym`.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix(atomizer): apply greedy matching fix to analyzeSBML string copy

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Implemented the verbosity check in `bionetgen/modelapi/bngparser.py` that was mentioned in a TODO comment. If `self.verbose` is set to true, it will now print "Parsing XML" before calling `xml_file.read()`.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* fix(parser): handle 0 as a valid dictionary key in BNGL action arguments

Modified `curly_arg_token` in `ActionList.define_parser` to allow `0` as a bare dictionary key using `pp.Literal("0")`. This resolves the TODO for handling the 0 case and ensures action strings like `simulate({print_functions=>{0=>1}})` are properly parsed instead of failing with a syntax error.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: adjust curly_arg_token formatting to pass black lint check

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…tion in analyzeSBML

* perf: optimize levenshtein distance calculations using memoization

The `levenshtein` method in `analyzeSBML.py` is repeatedly called during string processing and matching. Adding the `@pmemoize` decorator caches its results for duplicate inputs, significantly speeding up nested string comparisons across the atomizer module. The method was safely converted to a `@staticmethod` to ensure compatibility with `pmemoize`'s underlying `marshal` logic, which cannot serialize `self`.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* perf: optimize levenshtein distance calculations using memoization

The `levenshtein` method in `analyzeSBML.py` is repeatedly called during string processing and matching. Adding the `@pmemoize` decorator caches its results for duplicate inputs, significantly speeding up nested string comparisons across the atomizer module. The method was safely converted to a `@staticmethod` to ensure compatibility with `pmemoize`'s underlying `marshal` logic, which cannot serialize `self`.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* 🧪 Add error test for shutil.rmtree in CSimulator

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix syntax error and compile errors in test_csimulator.py

- Fixed Python 3.8/3.9 syntax error by unwrapping parenthesized context managers.
- Fixed `distutils.errors.CompileError` by correctly mocking `bionetgen.simulator.csimulator._new_ccompiler` instead of `ccompiler` directly, returning `compile_shared_lib` compatibility with tests.
- Reverted unintentional use of `Exception` instead of `ValueError` in test expectations.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Ran black to fix formatting issues caught by CI.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Includes proper black formatting.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Includes proper black formatting.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Includes proper black formatting.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* fix: migrate BNGL function creation logic to bngModel class

This commit adds a new `add_bngl_function` method to the `bngModel` class
which encapsulates the repetitive logic of instantiating a Function object,
parsing its definition from a BNGL string, assigning its properties, and
adding it to the model.

It then updates the `sbml2bngl.py` converter to use this new method
instead of executing the logic inline, satisfying the previous "TODO: Add
to bngModel functions" task.

Includes proper black formatting.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Remove hardcoded BioGRID API key

- Removed the hardcoded API key (`f74b8d6f4c394fcc9d97b11c8c83d7f3`) from `bionetgen/atomizer/utils/pathwaycommons.py`.
- Updated `queryBioGridByName` to retrieve the key from the `BIOGRID_API_KEY` environment variable.
- Added a graceful fallback: if the key is not set, a warning is logged (`WARNING:ATO006`), and the function returns `False`.
- Updated tests in `tests/test_pathwaycommons.py` to mock `os.environ` so they continue passing.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Remove hardcoded BioGRID API key

- Removed the hardcoded API key (`f74b8d6f4c394fcc9d97b11c8c83d7f3`) from `bionetgen/atomizer/utils/pathwaycommons.py`.
- Updated `queryBioGridByName` to retrieve the key from the `BIOGRID_API_KEY` environment variable.
- Added a graceful fallback: if the key is not set, a warning is logged (`WARNING:ATO006`), and the function returns `False`.
- Updated tests in `tests/test_pathwaycommons.py` to mock `os.environ` so they continue passing.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* 🔒 fix(pathwaycommons): Remove hardcoded API key

Refactor `queryBioGridByName` in `bionetgen/atomizer/utils/pathwaycommons.py` to retrieve the BioGRID API key via the `BIOGRID_API_KEY` environment variable instead of using a hardcoded string.

A fallback was added to return `False` gracefully if the key is not set, logging a warning. This addresses the security vulnerability of hardcoded secrets in the code.

Tests in `tests/test_pathwaycommons.py` were also updated to mock the environment variable to ensure existing tests pass.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* 🔒 fix(pathwaycommons): Remove hardcoded API key

Refactor `queryBioGridByName` in `bionetgen/atomizer/utils/pathwaycommons.py` to retrieve the BioGRID API key via the `BIOGRID_API_KEY` environment variable instead of using a hardcoded string.

A fallback was added to return `False` gracefully if the key is not set, logging a warning. This addresses the security vulnerability of hardcoded secrets in the code.

Tests in `tests/test_pathwaycommons.py` were also updated to mock the environment variable to ensure existing tests pass.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Previously the BNGsim backend hook rejected PLA actions and routed them
to the BNG2.pl subprocess, where the bundled run_network binary fails
on the '-p pla' method. Now PLA is treated like ode/ssa/psa: the Perl
hook intercepts it and delegates to the backend helper, which passes it
through to BNGsim when available. The method alias map, routing checks,
and test patch hook are all updated accordingly.
Replaced the assert statement with proper BNGModelError raising and
logger calls, maintaining consistency with all other block adders in
bionetgen/modelapi/model.py.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
- Modified `add_protocol_block` in `bionetgen/modelapi/model.py` to replace the bare `assert` statement with an `if not isinstance` check.
- Now properly uses `self.logger.error()` with the location passed as `loc`, and raises a `BNGModelError` in case of failure.
- This brings `add_protocol_block` in line with the consistent exception and logging pattern applied to all other model blocks in the codebase.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
…emoving redundant detectOntology call

Remove the `detectOntology.analyzeNamingConventions` call inside `SBMLAnalyzer.processNamingConventions2` in `bionetgen/atomizer/atomizer/analyzeSBML.py`. This call was identified as the single biggest execution bottleneck. This redundant work can be safely removed because an equivalent call is already correctly made at a higher scope level (`processNamingConventions`) resolving naming conventions without this inline nested duplication. Tests verify that the removal causes no functional regressions.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
Replaced O(N) list membership checks (e.g., `in ["pow"]`) with O(1) set membership checks (e.g., `in {"pow"}`) in `bionetgen/atomizer/writer/bnglWriter.py` to improve performance. Checked other occurrences in the file and applied the optimization to them as well (`["root", "pow"]`, `["sqr", "sqrt"]`, `["and", "or"]`, and a large keyword list in `any()`). All tests pass.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
This commit addresses a missing testing coverage for the error paths
in the `generate_notebook` function inside `bionetgen/core/main.py`.
Specifically, `AttributeError` and `KeyError` exception paths related
to checking custom stdout/stderr configurations are now verified.

Two new tests are added to `tests/test_notebook_cmd.py`:
- `test_bionetgen_notebook_attribute_error` sets missing config strings.
- `test_bionetgen_notebook_key_error` dynamically deletes config keys.
Both tests verify that `subprocess.PIPE` and `subprocess.STDOUT` fallbacks
are used in the resulting Popen call.

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
…_bngpath

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
akutuva21 and others added 30 commits June 16, 2026 11:08
* Add unit tests for Action.print_line method

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Add unit tests for Action.print_line method

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Add unit tests for Action.print_line method

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added a unit test for `Observable.add_pattern` in `tests/test_structs.py` to test the state mutation on the `MatchOnce` attribute depending on `Observable.type` being Species vs Molecules.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…ed BNGNotebook.write() to use whole-file string replacement\ninstead of nested line-by-line dictionary iterations. This significantly\nimproves generation speed (3-4x in benchmarks) while retaining identical\nsequential replacement semantics and lowering memory overhead by\navoiding list allocation for lines. (#561)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* refactor: extract getAssignmentRules logic to helpers

- Extracted rate rule processing to `_process_rate_rule`
- Extracted assignment rule processing to `_process_assignment_rule`
- Extracted default/other rule processing to `_process_other_rule`
- Preserved all existing behavior, including rule appending via early returns from helpers
- Fixed SyntaxWarning with raw string literals

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* refactor: extract getAssignmentRules logic to helpers

- Extracted rate rule processing to `_process_rate_rule`
- Extracted assignment rule processing to `_process_assignment_rule`
- Extracted default/other rule processing to `_process_other_rule`
- Preserved all existing behavior, including rule appending via early returns from helpers
- Fixed SyntaxWarning with raw string literals
- Applied black formatting

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* refactor: fix syntax error logic in getAssignmentRules

- Fixed `NameError` by passing `zparams` to `_process_rate_rule`
- Fixed broken logic control flow by replacing `return` with `return True` in helper function and executing `continue` in `getAssignmentRules` loop when returned True.
- Cleaned up temp scripts and formatted code

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added test coverage for the `repl` nested method inside `_replace_parameters_brackets` in `bionetgen/modelapi/sympy_odes.py`. The new tests effectively test both standard, in-bounds inputs as well as out-of-bounds boundary conditions correctly handled by the `repl` helper method.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Replace `range(len(time))` with `enumerate(time)` to loop over
  the time array and unpack the value directly.
- Replace manual list comprehensions `[data_2d[i, j] for j in ...]`
  with the `data_2d[i].tolist()` method to fetch a full row from
  the NumPy array.

These changes result in a significant speedup (e.g., around ~35% for
`_write_bng_dat` and ~35% for `_append_bng_dat_rows`) for larger outputs
while maintaining identical behavior.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaced a manual loop iterating over kwargs keys with
direct dictionary instantiation (`self.odict = dict(kwargs)`)
to improve performance and code readability.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…iguration (#539)

The doubleModifications mapping in moleculeCreation.py was previously
hardcoded and contained a typo. This commit extracts the mapping into
the respective namingConventions.json configuration files and modifies
moleculeCreation.py and detectOntology.py to retrieve and use it
dynamically from the configuration object instead.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Instead of doing a simple split by `_` when extracting actionable units, we now compare against `strippedMolecules` and split by smallest actionable units utilizing `self.greedyModificationMatching()`. If `greedyModificationMatching()` fails to find a valid match, we fall back to splitting the string by `_`.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
)

Removed the `.keys()` call in `bionetgen/core/tools/gdiff.py`'s `_get_node_text` method.
Iterating directly over the dictionary is faster and more idiomatic as it avoids creating a temporary view object in Python 3.

Measured improvement (via 1,000,000 simulated iterations): ~11.29% speedup for node text retrieval.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Iterating directly over a dictionary avoids allocating a view object
for `.keys()` and slightly improves CPU and memory efficiency.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* test: add coverage for ModelObj comment setter

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* style: format test_structs.py with black

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Add unit tests for Species gen_string method

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix formatting in test_structs.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix formatting in tests/test_structs.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…xes (#529)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added test_rule_gen_string to tests/test_structs.py to cover
bidirectional rules, unidirectional rules, rules with multiple
reactants/products, and rules with RuleMod modifiers.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…_symbols (#531)

Added comprehensive test cases for the `_replace_indexed_symbols` function, specifically covering its parameter indexing logic (including the internal `repl_param` method). This ensures `param[...]`, `params[...]`, and `p[...]` constructs are correctly substituted with explicit parameter names or appropriate index fallbacks when out of bounds.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added a new unit test test_modelobj_comment to tests/test_structs.py to verify the getter and setter functionality of the comment property in bionetgen.modelapi.structs.ModelObj. The test covers setting strings with hash marks, leading whitespaces, strings without hashes, and non-string values.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Resolves an issue where BNGModelError printed the empty self object
representation instead of the model path when there are no active
blocks. Updates `bionetgen/modelapi/model.py` and `bionetgen/network/network.py`
to correctly pass the file path context.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* 🧪 Add test for EnergyPattern.gen_string

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* 🧪 Add test for EnergyPattern.gen_string

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Add tests for Rule.set_rate_constants

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix tests/test_structs.py formatting to pass CI

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Add test for repl_param in sympy_odes.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Add test for repl_param in sympy_odes.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix test to pass using proper regex patterns

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Add unit tests for Observable.gen_string method

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix PEP8 violation by moving Observable import to top of test_structs.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

* Fix PEP8 violation by moving Observable import to top of test_structs.py

Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants