modelbase2 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.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.
@@ -211,7 +211,7 @@ def generate_model_code_py(model: Model) -> str:
211
211
  stoich_source = []
212
212
  for variable, stoich in stoichiometries.items():
213
213
  stoich_source.append(
214
- f" d{variable}dt = {conditional_join(stoich, lambda x: x.startswith("-"), " ", " + ")}"
214
+ f" d{variable}dt = {conditional_join(stoich, lambda x: x.startswith('-'), ' ', ' + ')}"
215
215
  )
216
216
 
217
217
  # Surrogates
@@ -508,14 +508,10 @@ def get_model_tex_diff(
508
508
  gls = default_init(gls)
509
509
  section_label = "sec:model-diff"
510
510
 
511
- return f"""{' start autogenerated ':%^60}
511
+ return f"""{" start autogenerated ":%^60}
512
512
  {_clearpage()}
513
- {_subsubsection('Model changes')}{_label(section_label)}
514
- {(
515
- (_to_tex_export(m1) - _to_tex_export(m2))
516
- .rename_with_glossary(gls)
517
- .export_all()
518
- )}
513
+ {_subsubsection("Model changes")}{_label(section_label)}
514
+ {((_to_tex_export(m1) - _to_tex_export(m2)).rename_with_glossary(gls).export_all())}
519
515
  {_clearpage()}
520
- {' end autogenerated ':%^60}
516
+ {" end autogenerated ":%^60}
521
517
  """
modelbase2/model.py CHANGED
@@ -25,7 +25,13 @@ from modelbase2.types import (
25
25
  Readout,
26
26
  )
27
27
 
28
- __all__ = ["ArityMismatchError", "Model", "ModelCache", "SortError"]
28
+ __all__ = [
29
+ "ArityMismatchError",
30
+ "CircularDependencyError",
31
+ "MissingDependenciesError",
32
+ "Model",
33
+ "ModelCache",
34
+ ]
29
35
 
30
36
  if TYPE_CHECKING:
31
37
  from collections.abc import Iterable, Mapping
@@ -34,19 +40,38 @@ if TYPE_CHECKING:
34
40
  from modelbase2.types import AbstractSurrogate, Callable, Param, RateFn, RetType
35
41
 
36
42
 
37
- class SortError(Exception):
43
+ class MissingDependenciesError(Exception):
38
44
  """Raised when dependencies cannot be sorted topologically.
39
45
 
40
46
  This typically indicates circular dependencies in model components.
41
47
  """
42
48
 
43
- def __init__(self, unsorted: list[str], order: list[str]) -> None:
49
+ def __init__(self, not_solvable: dict[str, list[str]]) -> None:
44
50
  """Initialise exception."""
51
+ missing_by_module = "\n".join(f"\t{k}: {v}" for k, v in not_solvable.items())
45
52
  msg = (
46
- f"Exceeded max iterations on sorting derived. "
47
- "Check if there are circular references.\n"
48
- f"Unsorted: {unsorted}\n"
49
- f"Order: {order}"
53
+ f"Dependencies cannot be solved. Missing dependencies:\n{missing_by_module}"
54
+ )
55
+ super().__init__(msg)
56
+
57
+
58
+ class CircularDependencyError(Exception):
59
+ """Raised when dependencies cannot be sorted topologically.
60
+
61
+ This typically indicates circular dependencies in model components.
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ missing: dict[str, set[str]],
67
+ ) -> None:
68
+ """Initialise exception."""
69
+ missing_by_module = "\n".join(f"\t{k}: {v}" for k, v in missing.items())
70
+ msg = (
71
+ f"Exceeded max iterations on sorting dependencies.\n"
72
+ "Check if there are circular references. "
73
+ "Missing dependencies:\n"
74
+ f"{missing_by_module}"
50
75
  )
51
76
  super().__init__(msg)
52
77
 
@@ -119,6 +144,24 @@ def _invalidate_cache(method: Callable[Param, RetType]) -> Callable[Param, RetTy
119
144
  return wrapper # type: ignore
120
145
 
121
146
 
147
+ def _check_if_is_sortable(
148
+ available: set[str],
149
+ elements: list[tuple[str, set[str]]],
150
+ ) -> None:
151
+ all_available = available.copy()
152
+ for name, _ in elements:
153
+ all_available.add(name)
154
+
155
+ # Check if it can be sorted in the first place
156
+ not_solvable = {}
157
+ for name, args in elements:
158
+ if not args.issubset(all_available):
159
+ not_solvable[name] = sorted(args.difference(all_available))
160
+
161
+ if not_solvable:
162
+ raise MissingDependenciesError(not_solvable=not_solvable)
163
+
164
+
122
165
  def _sort_dependencies(
123
166
  available: set[str], elements: list[tuple[str, set[str]]]
124
167
  ) -> list[str]:
@@ -137,6 +180,8 @@ def _sort_dependencies(
137
180
  """
138
181
  from queue import Empty, SimpleQueue
139
182
 
183
+ _check_if_is_sortable(available, elements)
184
+
140
185
  order = []
141
186
  # FIXME: what is the worst case here?
142
187
  max_iterations = len(elements) ** 2
@@ -170,7 +215,10 @@ def _sort_dependencies(
170
215
  unsorted.append(queue.get_nowait()[0])
171
216
  except Empty:
172
217
  break
173
- raise SortError(unsorted=unsorted, order=order)
218
+
219
+ mod_to_args: dict[str, set[str]] = dict(elements)
220
+ missing = {k: mod_to_args[k].difference(available) for k in unsorted}
221
+ raise CircularDependencyError(missing=missing)
174
222
  return order
175
223
 
176
224
 
modelbase2/plot.py CHANGED
@@ -818,7 +818,7 @@ def relative_label_distribution(
818
818
  isos = mapper.get_isotopomers_of_at_position(name, i)
819
819
  labels = cast(pd.DataFrame, concs.loc[:, isos])
820
820
  total = concs.loc[:, f"{name}__total"]
821
- ax.plot(labels.index, (labels.sum(axis=1) / total), label=f"C{i+1}")
821
+ ax.plot(labels.index, (labels.sum(axis=1) / total), label=f"C{i + 1}")
822
822
  ax.set_title(name)
823
823
  ax.legend()
824
824
  else:
@@ -827,6 +827,6 @@ def relative_label_distribution(
827
827
  ):
828
828
  ax.plot(concs.index, concs.loc[:, isos])
829
829
  ax.set_title(name)
830
- ax.legend([f"C{i+1}" for i in range(len(isos))])
830
+ ax.legend([f"C{i + 1}" for i in range(len(isos))])
831
831
 
832
832
  return fig, axs
@@ -507,7 +507,11 @@ def _codgen(name: str, sbml: Parser) -> Path:
507
507
 
508
508
  # Initial assignments
509
509
  initial_assignment_order = _sort_dependencies(
510
- available=set(sbml.initial_assignment) ^ set(parameters) ^ set(variables),
510
+ available=set(sbml.initial_assignment)
511
+ ^ set(parameters)
512
+ ^ set(variables)
513
+ ^ set(sbml.derived)
514
+ | {"time"},
511
515
  elements=[(k, set(v.args)) for k, v in sbml.initial_assignment.items()],
512
516
  )
513
517
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelbase2
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: A package to build metabolic models
5
5
  Author-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
6
6
  Maintainer-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
@@ -6,13 +6,13 @@ modelbase2/label_map.py,sha256=LUwcOHQWiGfBGV5XUmPM_SOwM9IyDVcQVJ11DPfVpAo,17774
6
6
  modelbase2/linear_label_map.py,sha256=gA8CHxcehgtI6ovwZ9qNUPDvxfqbO1J1kBC_mltD4TY,10225
7
7
  modelbase2/mc.py,sha256=zlDL7e_udpIMRhSjfFJo5AwkigD0B_3H2rQxyelBuzI,16285
8
8
  modelbase2/mca.py,sha256=nMS2VnzR2VEujCFUaj9WL82CNd-oxTb3jCHP8IlJvxA,8845
9
- modelbase2/model.py,sha256=mrc2Wz1IkINX1TQvuLZFdxSINqOaZGkn8FOd40qn5BY,53842
9
+ modelbase2/model.py,sha256=d-iAu64oxVgH9QgNYhNnJnrISic_U1Z5hX6ij6eDqh0,55260
10
10
  modelbase2/nnarchitectures.py,sha256=OA1X4UHrn7gsLuuqxK6Dhv5aiKnQflhHezYCUV-NuO8,4012
11
11
  modelbase2/npe.py,sha256=o876zHjyfJelGijSmCL0vUBfWbIhcbQyyPkwp8hZ4NA,8743
12
12
  modelbase2/parallel.py,sha256=kX4Td5YoovDwZp6kX_3cfO6QtHSS9ieJ0bMZiKs3Xv8,5002
13
13
  modelbase2/parameterise.py,sha256=7VrYxrQv0visraqUthWSnWfx-cxh2evlXbszIY5031U,690
14
14
  modelbase2/paths.py,sha256=uatKXDa79uniUB2Z3dr8eBJVuUPXDI-o_bf-DqPKq1Y,1039
15
- modelbase2/plot.py,sha256=txKF6Xnyh2JPJ06Wu803Wn7_VijMMJ1Kbq4WQB-xKE8,22720
15
+ modelbase2/plot.py,sha256=72Oivv-jsCF9J9U7Uli15p5SnuEHSnHRXCaRP8uUaJo,22724
16
16
  modelbase2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  modelbase2/scan.py,sha256=PvWZA4EgNS0JVMvm87bF72hSmhvo6O2KGg4vRzxve_8,18104
18
18
  modelbase2/scope.py,sha256=4twnEh8LrTmlLE-uRvubVkE3SSWejlLvtBzTCPqG3Aw,3710
@@ -21,26 +21,26 @@ modelbase2/surrogates.py,sha256=Dk-YEXb-ot22W3r5Bl3rxApbCyvNdBnNCvRi_1f_NnA,9276
21
21
  modelbase2/types.py,sha256=N74pWUZDcGlSMfDkjqqwHn5dkozlqgS6Wqg-58YKdvg,9904
22
22
  modelbase2/experimental/__init__.py,sha256=IzgcQ7MtMII7n6cg1PMp-oZm06CNVR19ax2exvb9Ny0,444
23
23
  modelbase2/experimental/_backup.py,sha256=As-L75tMQjWfkheRPk8xcroQPKDsSSejBJ2dXqPXmVo,46644
24
- modelbase2/experimental/codegen.py,sha256=J_0iCtojwjmDXAfC8EqiXP0gmWaSH8MPkWvdLsZWsXU,6962
24
+ modelbase2/experimental/codegen.py,sha256=i0soAT64oMBILGsWonoSSVkYMWOcCTY4RJ4TZoYlTos,6962
25
25
  modelbase2/experimental/diff.py,sha256=e7fjD9kqxkRUNxSevbAznd5cOlEdWJ6pj0y7Kd5KKrw,8973
26
26
  modelbase2/experimental/notes.md,sha256=YlM2biTzub6jSlx-aDZaBYsvQcGwb7NHyVAbbl2acGE,238
27
27
  modelbase2/experimental/strikepy.py,sha256=cKBs9InXR9mEPgx70Ynv0qkmAGfloksqinbpppTiC6U,19464
28
28
  modelbase2/experimental/symbolic.py,sha256=QT82TSW42RSVsvXK2WTQW1XluXnflWzrHbx6RFr_YmY,9953
29
- modelbase2/experimental/tex.py,sha256=M-Pdq3eQw1Huo-z1gv8EhWVO5ecJyFS8MMy9yoX81VI,13634
29
+ modelbase2/experimental/tex.py,sha256=q9k9NfQucUhYzNjAKkroU9XnBcfdegPK6h3DHhkfGOg,13618
30
30
  modelbase2/integrators/__init__.py,sha256=kqmV6a0TRyLGR_XqbyAI652AfptYnXAUpqbSFg0CpP8,450
31
31
  modelbase2/integrators/int_assimulo.py,sha256=VEQIZFZcEovLPy8i_jR8H8XcxBRQoRVmNzzCYzInPc0,4611
32
32
  modelbase2/integrators/int_scipy.py,sha256=-_9MS55eTc9jI7tk-3X49p-c7zrydoXaCCvDTn7Tybw,4334
33
33
  modelbase2/sbml/__init__.py,sha256=FBaQsVvrVc7QbCBXuG9tZOdSzHcqmmsaRbFx80rxrac,231
34
34
  modelbase2/sbml/_data.py,sha256=XwT1sSxn6KLTXYMbk4ORbEAEgZhQDBfoyrjMBDAoY_s,1135
35
35
  modelbase2/sbml/_export.py,sha256=9BLD3Qz86vlfDTZXwOnNOSVWq8mHrJoQjQmKJRZL_Wo,20285
36
- modelbase2/sbml/_import.py,sha256=uT5JpFvCKjQNBFmGPba61xYShHmjzjczqnaYflilSMI,21523
36
+ modelbase2/sbml/_import.py,sha256=1hP3xSktmbNic5asyk-b7L-FYQccEYvGAPchuLT4gqE,21586
37
37
  modelbase2/sbml/_mathml.py,sha256=bNk9RQ_NQFDhY1R354p-gwqqHaIiyAwZ1xLPHHhiguQ,24436
38
38
  modelbase2/sbml/_name_conversion.py,sha256=XK9DEyzhrD0GBBwwjK9RA0yORrDX5c-Uvx0VtKMR5rA,1325
39
39
  modelbase2/sbml/_unit_conversion.py,sha256=dW_I6_Ou09ccwnp6LIdrPriIQnQUK5lJcjzM2Fawm6U,1927
40
40
  modelbase2/surrogates/__init__.py,sha256=N_iXERECKvmrHiihwnyQEKOSBsmlGEuQhEotn-mWKdk,924
41
41
  modelbase2/surrogates/_poly.py,sha256=zjlNL4iYR9G51gjvZPHe3CAYF-tgACGdIBe4QUYXLQk,3110
42
42
  modelbase2/surrogates/_torch.py,sha256=CBS_3JzSgI2-xQrbq9CIXY0fJQsxbhBnWkG2TQyj7Zs,5885
43
- modelbase2-0.4.0.dist-info/METADATA,sha256=esuEQXsT-gP3-f_UJe65bcmXTVO5J6D-MiegzUtmxak,3344
44
- modelbase2-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
- modelbase2-0.4.0.dist-info/licenses/LICENSE,sha256=qvG2VolmSkrcocL34V1ieOx-Rn-fpVcUbb25gHzVgZw,35079
46
- modelbase2-0.4.0.dist-info/RECORD,,
43
+ modelbase2-0.5.0.dist-info/METADATA,sha256=plD8PQFIOOvu2jENW3PLVROFUOuSrXElAj6knn0YDeo,3344
44
+ modelbase2-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
+ modelbase2-0.5.0.dist-info/licenses/LICENSE,sha256=qvG2VolmSkrcocL34V1ieOx-Rn-fpVcUbb25gHzVgZw,35079
46
+ modelbase2-0.5.0.dist-info/RECORD,,