chython 2.19__cp313-cp313-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.
Files changed (175) hide show
  1. chython/__init__.py +35 -0
  2. chython/_functions.py +95 -0
  3. chython/_java.py +57 -0
  4. chython/algorithms/__init__.py +18 -0
  5. chython/algorithms/_isomorphism.cp313-win_amd64.pyd +0 -0
  6. chython/algorithms/_isomorphism.pyx +189 -0
  7. chython/algorithms/_rings.cp313-win_amd64.pyd +0 -0
  8. chython/algorithms/_rings.pyx +478 -0
  9. chython/algorithms/aromatics/__init__.py +27 -0
  10. chython/algorithms/aromatics/_rules.py +124 -0
  11. chython/algorithms/aromatics/kekule.py +532 -0
  12. chython/algorithms/aromatics/test/__init__.py +18 -0
  13. chython/algorithms/aromatics/test/test_kekule.py +160 -0
  14. chython/algorithms/aromatics/test/test_thiele.py +263 -0
  15. chython/algorithms/aromatics/thiele.py +222 -0
  16. chython/algorithms/calculate2d/__init__.py +23 -0
  17. chython/algorithms/calculate2d/clean2d.js +1 -0
  18. chython/algorithms/calculate2d/molecule.py +191 -0
  19. chython/algorithms/calculate2d/reaction.py +75 -0
  20. chython/algorithms/conformers.py +106 -0
  21. chython/algorithms/depict.py +596 -0
  22. chython/algorithms/fingerprints/__init__.py +43 -0
  23. chython/algorithms/fingerprints/linear.py +202 -0
  24. chython/algorithms/fingerprints/morgan.py +132 -0
  25. chython/algorithms/fingerprints/test/__init__.py +18 -0
  26. chython/algorithms/fingerprints/test/test_linear.py +127 -0
  27. chython/algorithms/fingerprints/test/test_morgan.py +79 -0
  28. chython/algorithms/groups/__init__.py +212 -0
  29. chython/algorithms/groups/_functional.py +290 -0
  30. chython/algorithms/groups/_oxidations.py +70 -0
  31. chython/algorithms/groups/_protective.py +964 -0
  32. chython/algorithms/groups/_reactions.py +809 -0
  33. chython/algorithms/groups/_reductions.py +88 -0
  34. chython/algorithms/groups/_transformations.py +278 -0
  35. chython/algorithms/groups/test/__init__.py +18 -0
  36. chython/algorithms/groups/test/test_deprotection.py +108 -0
  37. chython/algorithms/groups/test/test_reactions.py +377 -0
  38. chython/algorithms/isomorphism.py +664 -0
  39. chython/algorithms/mapping/__init__.py +188 -0
  40. chython/algorithms/mapping/_groups.py +94 -0
  41. chython/algorithms/mapping/_reactions.py +72 -0
  42. chython/algorithms/mapping/attention.py +266 -0
  43. chython/algorithms/mapping/reconstruct.py +346 -0
  44. chython/algorithms/mcs.py +201 -0
  45. chython/algorithms/morgan.py +77 -0
  46. chython/algorithms/rings.py +178 -0
  47. chython/algorithms/smiles.py +597 -0
  48. chython/algorithms/standardize/__init__.py +30 -0
  49. chython/algorithms/standardize/_groups.py +958 -0
  50. chython/algorithms/standardize/_isomers.py +330 -0
  51. chython/algorithms/standardize/_metal_organics.py +189 -0
  52. chython/algorithms/standardize/_reagents.py +44 -0
  53. chython/algorithms/standardize/_salts.py +68 -0
  54. chython/algorithms/standardize/molecule.py +475 -0
  55. chython/algorithms/standardize/reaction.py +384 -0
  56. chython/algorithms/standardize/resonance.py +191 -0
  57. chython/algorithms/standardize/salts.py +128 -0
  58. chython/algorithms/standardize/saturation.py +373 -0
  59. chython/algorithms/standardize/test/__init__.py +18 -0
  60. chython/algorithms/standardize/test/test_canonicalize.py +66 -0
  61. chython/algorithms/standardize/test/test_groups.py +146 -0
  62. chython/algorithms/standardize/test/test_isomers.py +198 -0
  63. chython/algorithms/stereo.py +1215 -0
  64. chython/algorithms/tautomers/__init__.py +167 -0
  65. chython/algorithms/tautomers/_acid.py +59 -0
  66. chython/algorithms/tautomers/_base.py +116 -0
  67. chython/algorithms/tautomers/_keto_enol.py +107 -0
  68. chython/algorithms/tautomers/acid_base.py +208 -0
  69. chython/algorithms/tautomers/heteroarenes.py +103 -0
  70. chython/algorithms/tautomers/keto_enol.py +143 -0
  71. chython/algorithms/tautomers/test/__init__.py +18 -0
  72. chython/algorithms/tautomers/test/test_tautomers.py +80 -0
  73. chython/algorithms/test/__init__.py +18 -0
  74. chython/algorithms/test/test_isomorphism.py +58 -0
  75. chython/algorithms/test/test_smiles.py +76 -0
  76. chython/algorithms/x3dom.py +350 -0
  77. chython/containers/__init__.py +48 -0
  78. chython/containers/_pack_v2.cp313-win_amd64.pyd +0 -0
  79. chython/containers/_pack_v2.pyx +271 -0
  80. chython/containers/_unpack_v0v2.cp313-win_amd64.pyd +0 -0
  81. chython/containers/_unpack_v0v2.pyx +302 -0
  82. chython/containers/bonds.py +255 -0
  83. chython/containers/cgr.py +115 -0
  84. chython/containers/chimera.py +63 -0
  85. chython/containers/graph.py +199 -0
  86. chython/containers/molecule.py +817 -0
  87. chython/containers/query.py +71 -0
  88. chython/containers/rdkit.py +183 -0
  89. chython/containers/reaction.py +324 -0
  90. chython/containers/test/__init__.py +18 -0
  91. chython/containers/test/test_molecule.py +117 -0
  92. chython/containers/test/test_pack.py +60 -0
  93. chython/containers/test/test_rdkit.py +70 -0
  94. chython/containers/test/test_reaction.py +40 -0
  95. chython/exceptions.py +114 -0
  96. chython/files/MRVrw.py +532 -0
  97. chython/files/PDBrw.py +255 -0
  98. chython/files/RDFrw.py +309 -0
  99. chython/files/SDFrw.py +221 -0
  100. chython/files/__init__.py +30 -0
  101. chython/files/_convert.py +207 -0
  102. chython/files/_mapping.py +117 -0
  103. chython/files/_xyz.cp313-win_amd64.pyd +0 -0
  104. chython/files/_xyz.pyx +74 -0
  105. chython/files/daylight/__init__.py +24 -0
  106. chython/files/daylight/parser.py +157 -0
  107. chython/files/daylight/smarts.py +107 -0
  108. chython/files/daylight/smiles.py +260 -0
  109. chython/files/daylight/test/__init__.py +18 -0
  110. chython/files/daylight/test/test_daylight_smarts.py +289 -0
  111. chython/files/daylight/test/test_daylight_smiles.py +101 -0
  112. chython/files/daylight/test/test_parser.py +118 -0
  113. chython/files/daylight/test/test_tokenize.py +77 -0
  114. chython/files/daylight/tokenize.py +376 -0
  115. chython/files/libinchi/__init__.py +22 -0
  116. chython/files/libinchi/libinchi.dll +0 -0
  117. chython/files/libinchi/wrapper.py +554 -0
  118. chython/files/mdl/__init__.py +25 -0
  119. chython/files/mdl/emol.py +251 -0
  120. chython/files/mdl/erxn.py +67 -0
  121. chython/files/mdl/mol.py +186 -0
  122. chython/files/mdl/read.py +223 -0
  123. chython/files/mdl/rxn.py +67 -0
  124. chython/files/mdl/stereo.py +63 -0
  125. chython/files/mdl/write.py +201 -0
  126. chython/files/opsin.py +35 -0
  127. chython/files/test/__init__.py +0 -0
  128. chython/files/test/test_inchi.py +27 -0
  129. chython/files/test/test_mrv.py +47 -0
  130. chython/files/test/test_sdf_rdf.py +64 -0
  131. chython/files/test/test_xyz.py +20 -0
  132. chython/files/xyz.py +78 -0
  133. chython/periodictable/__init__.py +69 -0
  134. chython/periodictable/base/__init__.py +25 -0
  135. chython/periodictable/base/dynamic.py +149 -0
  136. chython/periodictable/base/element.py +451 -0
  137. chython/periodictable/base/groups.py +90 -0
  138. chython/periodictable/base/periods.py +46 -0
  139. chython/periodictable/base/query.py +473 -0
  140. chython/periodictable/base/vector.py +119 -0
  141. chython/periodictable/groupI.py +252 -0
  142. chython/periodictable/groupII.py +223 -0
  143. chython/periodictable/groupIII.py +1154 -0
  144. chython/periodictable/groupIV.py +210 -0
  145. chython/periodictable/groupIX.py +196 -0
  146. chython/periodictable/groupV.py +192 -0
  147. chython/periodictable/groupVI.py +183 -0
  148. chython/periodictable/groupVII.py +162 -0
  149. chython/periodictable/groupVIII.py +161 -0
  150. chython/periodictable/groupX.py +166 -0
  151. chython/periodictable/groupXI.py +164 -0
  152. chython/periodictable/groupXII.py +158 -0
  153. chython/periodictable/groupXIII.py +239 -0
  154. chython/periodictable/groupXIV.py +262 -0
  155. chython/periodictable/groupXV.py +276 -0
  156. chython/periodictable/groupXVI.py +457 -0
  157. chython/periodictable/groupXVII.py +324 -0
  158. chython/periodictable/groupXVIII.py +260 -0
  159. chython/periodictable/test/__init__.py +0 -0
  160. chython/periodictable/test/test_element.py +100 -0
  161. chython/reactor/__init__.py +24 -0
  162. chython/reactor/base.py +222 -0
  163. chython/reactor/reactor.py +177 -0
  164. chython/reactor/test/__init__.py +18 -0
  165. chython/reactor/test/test_reactor.py +40 -0
  166. chython/reactor/test/test_transformer.py +78 -0
  167. chython/reactor/transformer.py +72 -0
  168. chython/utils/__init__.py +50 -0
  169. chython/utils/free_wilson.py +114 -0
  170. chython/utils/grid.py +130 -0
  171. chython/utils/retro.py +139 -0
  172. chython-2.19.dist-info/METADATA +105 -0
  173. chython-2.19.dist-info/RECORD +175 -0
  174. chython-2.19.dist-info/WHEEL +4 -0
  175. chython-2.19.dist-info/licenses/LICENSE +165 -0
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2025, 2026 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from .._java import get_cdk
20
+
21
+
22
+ class Chimera:
23
+ __slots__ = ()
24
+
25
+ def to_cdk(self):
26
+ """
27
+ Convert molecule to CDK Molecule object.
28
+
29
+ Due to translation through SMILES string, atom order is not preserved.
30
+ Use `self.smiles_atoms_order` to map atoms back.
31
+ """
32
+ cdk = get_cdk()
33
+ parser = cdk.smiles.SmilesParser(cdk.DefaultChemObjectBuilder.getInstance())
34
+ return parser.parseSmiles(str(self))
35
+
36
+ def to_openbabel(self):
37
+ """
38
+ Convert molecule to OpenBabel OBMol object.
39
+
40
+ Due to translation through SMILES string, atom order is not preserved.
41
+ Use `self.smiles_atoms_order` to map atoms back.
42
+ """
43
+ from openbabel import openbabel
44
+
45
+ conv = openbabel.OBConversion()
46
+ conv.SetInFormat('smi')
47
+ mol = openbabel.OBMol()
48
+ assert conv.ReadString(mol, str(self)), 'OpenBabel failed to parse smiles'
49
+ return mol
50
+
51
+ def to_indigo(self):
52
+ """
53
+ Convert molecule to Indigo molecule object.
54
+
55
+ Due to translation through SMILES string, atom order is not preserved.
56
+ Use `self.smiles_atoms_order` to map atoms back.
57
+ """
58
+ from indigo import Indigo
59
+
60
+ return Indigo().loadMolecule(str(self))
61
+
62
+
63
+ __all__ = ['Chimera']
@@ -0,0 +1,199 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2018-2026 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from abc import ABC, abstractmethod
20
+ from functools import cached_property
21
+ from typing import Dict, Generic, Iterator, Optional, Tuple, TypeVar
22
+ from ..exceptions import AtomNotFound, MappingError, BondNotFound
23
+
24
+
25
+ Atom = TypeVar('Atom')
26
+ Bond = TypeVar('Bond')
27
+
28
+
29
+ class Graph(Generic[Atom, Bond], ABC):
30
+ __slots__ = ('_atoms', '_bonds', '__dict__')
31
+
32
+ _atoms: Dict[int, Atom]
33
+ _bonds: Dict[int, Dict[int, Bond]]
34
+
35
+ def __init__(self):
36
+ self._atoms = {}
37
+ self._bonds = {}
38
+
39
+ def atom(self, n: int) -> Atom:
40
+ return self._atoms[n]
41
+
42
+ def has_atom(self, n: int) -> bool:
43
+ return n in self._atoms
44
+
45
+ def atoms(self) -> Iterator[Tuple[int, Atom]]:
46
+ """
47
+ iterate over all atoms
48
+ """
49
+ return iter(self._atoms.items())
50
+
51
+ @property
52
+ def atoms_count(self) -> int:
53
+ return len(self._atoms)
54
+
55
+ @property
56
+ def atoms_numbers(self) -> Iterator[int]:
57
+ return iter(self._atoms)
58
+
59
+ def bond(self, n: int, m: int) -> Bond:
60
+ try:
61
+ return self._bonds[n][m]
62
+ except KeyError as e:
63
+ raise BondNotFound from e
64
+
65
+ def has_bond(self, n: int, m: int) -> bool:
66
+ try:
67
+ self._bonds[n] # check if atom exists
68
+ return n in self._bonds[m]
69
+ except KeyError:
70
+ raise AtomNotFound
71
+
72
+ def bonds(self) -> Iterator[Tuple[int, int, Bond]]:
73
+ """
74
+ iterate other all bonds
75
+ """
76
+ seen = set()
77
+ for n, m_bond in self._bonds.items():
78
+ seen.add(n)
79
+ for m, bond in m_bond.items():
80
+ if m not in seen:
81
+ yield n, m, bond
82
+
83
+ @cached_property
84
+ def bonds_count(self) -> int:
85
+ return sum(len(x) for x in self._bonds.values()) // 2
86
+
87
+ @abstractmethod
88
+ def add_atom(self, atom: Atom, n: Optional[int] = None) -> int:
89
+ """
90
+ new atom addition
91
+ """
92
+ if n is None:
93
+ n = max(self._atoms, default=0) + 1
94
+ elif not isinstance(n, int):
95
+ raise TypeError('mapping should be integer')
96
+ elif n in self._atoms:
97
+ raise MappingError('atom with same number exists')
98
+
99
+ self._atoms[n] = atom
100
+ self._bonds[n] = {}
101
+ self.flush_cache()
102
+ return n
103
+
104
+ @abstractmethod
105
+ def add_bond(self, n: int, m: int, bond: Bond):
106
+ """
107
+ Add bond.
108
+ """
109
+ if n == m:
110
+ raise MappingError('atom loops impossible')
111
+ if n not in self._bonds or m not in self._bonds:
112
+ raise AtomNotFound('atoms not found')
113
+ if n in self._bonds[m]:
114
+ raise MappingError('atoms already bonded')
115
+
116
+ self._bonds[n][m] = self._bonds[m][n] = bond
117
+ self.flush_cache()
118
+
119
+ def copy(self):
120
+ """
121
+ copy of graph
122
+ """
123
+ copy = object.__new__(self.__class__)
124
+ copy._atoms = {n: atom.copy(full=True) for n, atom in self.atoms()}
125
+ copy._bonds = cb = {}
126
+ for n, m_bond in self._bonds.items():
127
+ cb[n] = cbn = {}
128
+ for m, bond in m_bond.items():
129
+ if m in cb: # bond partially exists. need back-connection.
130
+ cbn[m] = cb[m][n]
131
+ else:
132
+ cbn[m] = bond.copy(full=True)
133
+ return copy
134
+
135
+ def remap(self, mapping: Dict[int, int]):
136
+ """
137
+ Change atom numbers
138
+
139
+ :param mapping: mapping of old numbers to the new
140
+ """
141
+ if len(mapping) != len(set(mapping.values())) or \
142
+ not (self._atoms.keys() - mapping.keys()).isdisjoint(mapping.values()):
143
+ raise ValueError('mapping overlap')
144
+
145
+ mg = mapping.get
146
+ self._atoms = {mg(n, n): atom for n, atom in self.atoms()}
147
+ self._bonds = {mg(n, n): {mg(m, m): bond for m, bond in m_bond.items()} for n, m_bond in self._bonds.items()}
148
+ self.flush_cache()
149
+
150
+ def union(self, other: 'Graph', *, remap: bool = False, copy: bool = True):
151
+ """
152
+ Merge Graphs into one.
153
+
154
+ :param remap: if atoms has collisions then remap other graph atoms else raise exception.
155
+ :param copy: keep original structure and return a new object
156
+ """
157
+ if self._atoms.keys() & other._atoms.keys():
158
+ if not remap:
159
+ raise MappingError('mapping of graphs is not disjoint')
160
+ other = other.copy()
161
+ other.remap({n: i for i, n in enumerate(other, start=max(self._atoms) + 1)})
162
+ else:
163
+ other = other.copy() # make a copy
164
+ u = self.copy() if copy else self
165
+ u._atoms.update(other._atoms)
166
+ u._bonds.update(other._bonds)
167
+ if not copy:
168
+ self.flush_cache()
169
+ return u
170
+
171
+ def flush_cache(self):
172
+ self.__dict__.clear()
173
+
174
+ def __copy__(self):
175
+ return self.copy()
176
+
177
+ def __or__(self, other):
178
+ """
179
+ G | H is union of graphs
180
+ """
181
+ return self.union(other, remap=True)
182
+
183
+ def __ior__(self, other):
184
+ """
185
+ G =| H is union of graphs
186
+ """
187
+ return self.union(other, remap=True, copy=False)
188
+
189
+ def __len__(self):
190
+ return len(self._atoms)
191
+
192
+ def __iter__(self) -> Iterator[int]:
193
+ return iter(self._atoms)
194
+
195
+ def __bool__(self):
196
+ return bool(self._atoms)
197
+
198
+
199
+ __all__ = ['Graph']