molformula 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ Copyright 2026 Hiroshi Nakayama and RIKEN (The Institute of Physical and Chemical Research)
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,373 @@
1
+ Metadata-Version: 2.4
2
+ Name: molformula
3
+ Version: 0.1.0
4
+ Summary: A simple chemical formula processor for analyzing mass spectrometry data
5
+ Keywords: chemical formula,molecular formula,mass spectrometry,exact mass,isotopic mass,isotope,mz,proteomics,lipidomics,metabolomics,cheminformatics,bioinformatics
6
+ Author: Hiroshi Nakayama, RIKEN (The Institute of Physical and Chemical Research)
7
+ Author-email: Hiroshi Nakayama <64342563+benkeicrab@users.noreply.github.com>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
+ Classifier: Operating System :: OS Independent
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Project-URL: Repository, https://github.com/benkeicrab/molformula.git
26
+ Project-URL: Issues, https://github.com/benkeicrab/molformula/issues
27
+ Description-Content-Type: text/markdown
28
+
29
+ # molformula
30
+
31
+ A simple, dependency-free Python library for safe chemical-formula manipulation and mass-spectrometry-oriented calculations.
32
+
33
+ ## Overview
34
+
35
+ This library handles molecular formulas and simple condensed formulas (See Supported formula syntax), arithmetic processing of these formulas, ionization, and exact mass and m/z calculations with enforced formula invariants.
36
+ The API is designed to support a functional style, using immutable formula values and composable, non-mutating operations.
37
+ It is intended as a foundation for mass spectrometry data processing.
38
+
39
+
40
+ ## Installation
41
+
42
+ ### Python version
43
+
44
+ Supports Python >=3.10
45
+
46
+ ### Dependency
47
+
48
+ No third-party library is required for using the library. `pytest` for developers / contributors.
49
+
50
+ ### Installation / uninstallation
51
+
52
+ ```Bash
53
+ # installation
54
+ pip install molformula
55
+
56
+ # uninstallation
57
+ pip uninstall molformula
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ ### Import
63
+
64
+ ```python
65
+ >>> import molformula as mf
66
+ ```
67
+ or more explicitly (and thus more preferable)
68
+
69
+ ```python
70
+ >>> from molformula import Formula, IonFormula, apply_formula_change, deprotonated, exact_mass, ion_mz, make_formula_change, protonated, sum_formulas, to_str
71
+
72
+ ```
73
+
74
+ ### Creating and showing canonical formulas
75
+
76
+ ```python
77
+ >>> # molecular formula and simple condensed formulas are supported.
78
+ >>> glucose = Formula("CH2OH(CHOH)4CHO")
79
+ >>> # Output is canonicalized to Hill-system order [1].
80
+ >>> to_str(glucose)
81
+ 'C6H12O6'
82
+ >>> # A symbol for explicit isotope must be written with a bracket in a formula.
83
+ >>> labeled_glucose = Formula("[13C]H2OH(CHOH)4CHO")
84
+ >>> # Labeled positions in a condensed formula are not preserved.
85
+ >>> # this package's additional rule: the ordinary symbol first, then explicit isotopes in increasing mass-number order.
86
+ >>> to_str(labeled_glucose)
87
+ 'C5[13C]H12O6'
88
+ ```
89
+
90
+ ### Formula arithmetic
91
+
92
+ ```python
93
+ >>> H2O = Formula('H2O')
94
+ >>> apply_formula_change(glucose, losses=(H2O,))
95
+ Formula('C6H10O5')
96
+ >>> C, C13 = Formula('C'), Formula('[13C]')
97
+ >>> apply_formula_change(glucose, gains=(C13,), losses=(C,))
98
+ Formula('C5[13C]H12O6')
99
+ ```
100
+
101
+ ### Reusable formula changes
102
+
103
+ Repeating application of a chemical change is supported.
104
+
105
+ ```python
106
+ >>> # Define a specific formula change such as dehydration.
107
+ >>> dehydrated = make_formula_change(losses=(H2O,))
108
+ >>> dehydrated(glucose)
109
+ Formula('C6H10O5')
110
+ >>> C13_labeled = make_formula_change(gains=(C13,), losses=(C,))
111
+ >>> C13_labeled(glucose)
112
+ Formula('C5[13C]H12O6')
113
+ >>> C13_labeled(C13_labeled(glucose))
114
+ Formula('C4[13C]2H12O6')
115
+ ```
116
+
117
+ ### Ionization
118
+
119
+ ```python
120
+ >>> protonated_glucose = protonated(glucose, 1)
121
+ >>> protonated_glucose
122
+ IonFormula(formula=Formula('C6H13O6'), z=1)
123
+ >>> deprotonated_glucose = deprotonated(glucose, 1)
124
+ >>> deprotonated_glucose
125
+ IonFormula(formula=Formula('C6H11O6'), z=-1)
126
+ ```
127
+
128
+ ### Exact mass and m/z
129
+
130
+ ```python
131
+ >>> exact_mass(glucose)
132
+ 180.06338810418
133
+ >>> ion_mz(deprotonated_glucose)
134
+ 179.05611165185906
135
+ ```
136
+
137
+ Exact mass and m/z are calculated using atomic mass values from NIST Physical Measurement Laboratory [2] and electron mass from 2022 CODATA recommended value [3]
138
+
139
+
140
+ ### Application in peptide MS/MS
141
+
142
+ The following example constructs b- and y-ion series from amino-acid residue formulas for peptide AGSK.
143
+
144
+ ```python
145
+ >>> def b_y_ion_series(seq, z):
146
+ ... water = Formula('H2O')
147
+ ... b_ions, y_ions = [], []
148
+ ... l = len(seq)
149
+ ... for i in range(l):
150
+ ... b_neutral = sum_formulas(*seq[: i+1])
151
+ ... b_ion = protonated(b_neutral, z)
152
+ ... b_ions.append(b_ion)
153
+ ...
154
+ ... y_neutral = sum_formulas(water, *seq[l-1-i: ])
155
+ ... y_ion = protonated(y_neutral, z)
156
+ ... y_ions.append(y_ion)
157
+ ...
158
+ ... return b_ions, y_ions
159
+ ...
160
+ >>> gly = Formula('HNCH2CO')
161
+ >>> ser = Formula('HNCH(CH2OH)CO')
162
+ >>> ala = Formula('HNCH(CH3)CO')
163
+ >>> lys = Formula('HNCH(CH2CH2CH2CH2NH2)CO')
164
+ >>> pep_seq = [ala, gly, ser, lys]
165
+
166
+ >>> b_ions, y_ions = b_y_ion_series(pep_seq, 1)
167
+ >>> [ion_mz(ion) for ion in b_ions]
168
+ [72.04439023747095, 129.06585395816097, 216.09788236288097, 344.19284537807096]
169
+ >>> [ion_mz(ion) for ion in y_ions]
170
+ [147.11280415154096, 234.14483255626095, 291.16629627695096, 362.20341006210094]
171
+ ```
172
+
173
+ The example includes full-length prefix and suffix compositions for completeness; these entries do not correspond to distinct backbone cleavage sites.
174
+
175
+ For phosphorylation of Ser and H3PO4-loss of phospho-Ser,
176
+ see examples/peptide_msms.py.
177
+
178
+
179
+ ## Supported formula syntax
180
+
181
+ ### Supported notation
182
+
183
+ - 'C6H12O6' # Molecular formula
184
+ - 'C5[13C]H12O6' # Molecular formula with explicit isotope
185
+ - 'CH4O' # Count 1 can be omitted.
186
+ - 'CH3OH' # Simple condensed formula
187
+ - '(CH3)2CHOH' # Condensed formula with parentheses and multipliers
188
+ - '[ 13 C] 6H12O6' # Whitespace is allowed between tokens but not within lexical tokens such as elemental symbols or integer counts.
189
+
190
+ ### Unsupported notation
191
+
192
+ - '2H2O' # leading stoichiometric coefficient
193
+ - 'CuSO4.H2O' # component separator / hydrate notation
194
+ - '[CH3COO]-' # Charged formula
195
+ - 'K3[Fe(CN)6]' # Complex
196
+ - 'CH3-OH' # Bond representation with '-' and/or '='
197
+
198
+ - Formulas with unsupported atom species (See Limitations below)
199
+
200
+
201
+ ## API overview
202
+
203
+ The library has immutable types: Formula and IonFormula, as well as functions for manipulating these types.
204
+
205
+ ### Types
206
+
207
+ #### `Formula`:
208
+
209
+ - Representation of non-negative atom-species counts.
210
+
211
+ - Must contain at least one atom.
212
+
213
+ - Does not encode charge, bonding, valence, or molecular structure.
214
+
215
+
216
+ #### `IonFormula`:
217
+
218
+ - Combines a Formula with a non-zero charge (z).
219
+
220
+ - Cannot be constructed directly; use ionization functions below.
221
+
222
+ - Ionization functions treat their Formula argument as a neutral
223
+ precursor.
224
+
225
+
226
+ ### Operations to the types
227
+
228
+ #### Parsing and formatting
229
+
230
+ - `Formula()`: Construct formula object.
231
+
232
+ - `to_str()`: Output a canonical representation of formula in Hill-system order [1]. Structural information in the original notation is not preserved.
233
+
234
+ - `atom_species_counts()`: Return atom-species counts as a new dictionary.
235
+
236
+ #### Arithmetic operation between Formula
237
+
238
+ The library offers high-level API of arithmetic operations between Formulas.
239
+
240
+ Intermediates can have negative atom counts; however, the resulting Formula must have non-negative counts and contain at least one atom.
241
+
242
+ - `apply_formula_change()`:
243
+ Apply atom-count gains and losses to a target Formula.
244
+
245
+ - `make_formula_change()`:
246
+ The atom-count gains and losses are baked into the return function.
247
+ The function applies gains/losses to a target Formula.
248
+
249
+ - `sum_formulas()`:
250
+ Sum up multiple Formulas.
251
+
252
+
253
+ #### Ionization
254
+
255
+ Ionization functions manipulate atom counts and charges. Currently, three types of ionization are supported.
256
+
257
+ - `protonated()`:
258
+ Adds n hydrogen atoms and sets charge to +n.
259
+
260
+ - `deprotonated()`:
261
+ Removes n hydrogen atoms and sets charge to -n.
262
+
263
+ - `deelectronated()`:
264
+ Leaves atom counts unchanged and sets charge to +1.
265
+
266
+
267
+ #### Mass calculation
268
+
269
+ `exact_mass()` calculates the exact mass of a `Formula`, and `ion_mz()`
270
+ calculates the m/z of an `IonFormula`.
271
+ The mass and m/z values are calculated with the atomic/isotopic masses [2] and electron mass [3].
272
+ No explicit decimal rounding is applied to the calculated mass or m/z values.
273
+
274
+ - `exact_mass()`:
275
+ Calculates exact mass of Formula. No electron-mass correction is applied.
276
+
277
+ - `ion_mz()`:
278
+ Calculates an ion m/z from an instance of IonFormula
279
+ The m/z value of ion: IonFormula is calculated as
280
+
281
+ (exact_mass(ion.formula) - ion.z * electron_mass) / abs(ion.z)
282
+
283
+ so positive charge removes electron mass and negative charge adds it.
284
+
285
+
286
+ #### Exceptions
287
+
288
+ The class hierarchy is as shown below:
289
+
290
+ ```bash
291
+ TypeError # Error in Python types
292
+ ValueError
293
+ └── ChemicalFormulaError # Base class for domain-value errors.
294
+ ├── FormulaChangeError # Change producing invalid Formula.
295
+ ├── IonizationError
296
+ │ ├── InvalidProtonCountError
297
+ │ ├── InsufficientHydrogenError
298
+ │ └── EmptyIonFormulaError
299
+ └── FormulaParseError
300
+ ├── EmptyParenthesisError
301
+ ├── UnmatchedParenthesesError
302
+ ├── InvalidBracketError
303
+ ├── EmptyFormulaError
304
+ ├── InvalidFormulaError
305
+ ├── UnsupportedAtomSpeciesError
306
+ └── InvalidCountError
307
+ ```
308
+
309
+ - The `position` attribute in `FormulaParseError` is a zero-based offset into the original input string. It may equal `len(input)` when expected input is missing at the end of the string.
310
+
311
+ - When raised by this package, the `deficits` attribute in `FormulaChangeError` is a dictionary mapping each atom species that would have a negative count to the positive number of missing atoms.
312
+
313
+ - The `zero_result` attribute in `FormulaChangeError` is True only when the formula change would remove all atoms exactly, without producing any negative counts.
314
+
315
+ - See the API documentation for details.
316
+
317
+
318
+ ## Limitations
319
+
320
+ - Supported atom species: C, 13C, H, 2H, N, 15N, O, 18O, P, S, Se, F, Cl, 37Cl, Br, 81Br, I, Si, Li, Na, K, Mg, Ca, Fe;
321
+ The principal isotope of each element is represented by the ordinary elemental symbol. Other supported isotopes use mass-number-prefixed atom-species symbols, which are written in brackets in formula strings (e.g. 13C as [13C]).
322
+
323
+ - Complexes, hydrates, SMILES, and condensed-formula syntax other than the supported forms shown above are not supported.
324
+
325
+ - Formula validates atom-species counts, but does not validate chemical valence, bonding, structural plausibility, or electrical neutrality.
326
+
327
+ - Arithmetic operations on IonFormula are not allowed; ion reactions are expressed by arithmetic operations on Formula followed by ionization.
328
+
329
+ - Radical character and spin state are not represented.
330
+
331
+ - `to_str()` returns a canonical formula in Hill-system order, losing input order, grouping, etc.
332
+
333
+ - Adduct ions are not supported as a dedicated model. Existing formula-change and ionization operations can be composed to construct many adduct compositions, for example:
334
+
335
+ ```Python
336
+ >>> glycine = Formula('C2H5NO2')
337
+ >>> ammonium_adduct = make_formula_change(gains=(Formula('NH3'),))
338
+ >>> ammonium_adducted = protonated(ammonium_adduct(glycine), 1)
339
+ >>> ammonium_adducted
340
+ IonFormula(formula=Formula('C2H9N2O2'), z=1)
341
+ ```
342
+
343
+ See examples/lipid_adduct_ions.py for more details.
344
+
345
+ However, molformula does not determine whether such ions are chemically plausible or experimentally observable.
346
+
347
+ - `deprotonated()` strictly removes ordinary hydrogen (1H) atoms. It does not remove deuterium (2H) or tritium. To model deuterated loss, use `apply_formula_change()` with an explicit deuterium Formula('[2H]') as a loss.
348
+ ```Python
349
+ >>> deuterium = Formula('[2H]')
350
+ >>> deuterated_glycine = Formula('C2H8[2H]N2O2')
351
+ >>> to_str(apply_formula_change(deuterated_glycine, losses=(deuterium,)))
352
+ 'C2H8N2O2'
353
+ ```
354
+
355
+ - Exact masses are calculated from the configured principal or explicitly specified isotopic masses. Isotopic abundance distributions, fine structure, and peak centroiding are not supported.
356
+
357
+
358
+ ## License
359
+
360
+ This project is licensed under the 3-clause BSD License. See LICENSE for details.
361
+
362
+ ## Contributing
363
+
364
+ Bug reports and suggestions are welcome through GitHub Issues.
365
+ Contribution guidelines will be added as the project develops.
366
+
367
+
368
+ ## References
369
+ 1. Hill, E. A., JACS (1900) 22 (8): 478–494. https://doi.org/10.1021/ja02046a005
370
+
371
+ 2. Atomic mass from NIST Physical Measurement Laboratory https://physics.nist.gov/cgi-bin/Compositions/stand_alone.pl
372
+
373
+ 3. 2022 CODATA recommended value https://physics.nist.gov/cgi-bin/cuu/Value?eqmeu|search_for=electron+mass