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,377 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 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
+ import pytest
20
+ from chython import smiles
21
+
22
+
23
+ # (test_id, reaction_name, reaction_smiles, expected_count, exclude)
24
+ # Reaction SMILES are parsed, canonicalized, then reactants are fed to @ operator.
25
+ # expected_count: number of results from @ (2 for tautomeric azoles).
26
+ # exclude: optional set of reaction names to filter from results (known overlaps).
27
+ _two_component = [
28
+ ('amidation_acyl_chloride_primary_amine',
29
+ 'amidation', 'ClC(=O)C.NCC>>CCNC(=O)C', 1),
30
+ ('suzuki_aryl_bromide_boronic_acid',
31
+ 'suzuki', 'Brc1ccc(cc1)C.OB(O)c1ccccc1>>c1cc(ccc1-c1ccccc1)C', 1),
32
+ ('suzuki_alkenyl_boronic_acid',
33
+ 'suzuki', 'Brc1ccc(cc1)C.OB(O)C=CC>>c1cc(ccc1C=CC)C', 1),
34
+ ('suzuki_alkyl_boronic_acid',
35
+ 'suzuki', 'Brc1ccc(cc1)C.OB(O)CCC>>c1cc(ccc1CCC)C', 1),
36
+ ('buchwald_hartwig_aryl_bromide_primary_amine',
37
+ 'buchwald_hartwig', 'Brc1ccc(cc1)C.NCC>>c1cc(ccc1C)NCC', 1),
38
+ ('buchwald_hartwig_pyridone_bromide_primary_amine',
39
+ 'buchwald_hartwig', 'CN1C=CC(Br)=CC1=O.NCC>>CN1C=CC(=CC1=O)NCC', 1),
40
+ ('mitsunobu_ether_primary_alcohol_phenol',
41
+ 'mitsunobu', 'OCC.Oc1ccc(cc1)C>>c1cc(ccc1C)OCC', 1),
42
+ ('mitsunobu_ester_primary_alcohol_acid',
43
+ 'mitsunobu', 'OCC.OC(=O)c1ccccc1>>c1ccccc1C(OCC)=O', 1),
44
+ ('deoxygenative_coupling_alcohol_aryl_bromide',
45
+ 'deoxygenative_coupling', 'OCC.Brc1ccc(cc1)C>>c1cc(ccc1C)CC', 1, {'snar'}),
46
+ ('decarboxylative_coupling_acid_aryl_bromide',
47
+ 'decarboxylative_coupling', 'OC(=O)CC.Brc1ccc(cc1)C>>c1cc(ccc1C)CC', 1),
48
+ ('xec_aryl_bromide_alkyl_bromide',
49
+ 'xec', 'Brc1ccc(cc1)C.BrCCC>>c1cc(ccc1CCC)C', 1),
50
+ ('reductive_amination_aldehyde_primary_amine',
51
+ 'reductive_amination', 'O=CC.NCc1ccccc1>>c1cc(ccc1)CNCC', 1),
52
+ ('reductive_amination_ketone_secondary_amine',
53
+ 'reductive_amination', 'O=C(C)C.N(C)CC>>CC(C)N(C)CC', 1),
54
+ ('ullmann_phenol_aryl_bromide_cresol',
55
+ 'ullmann_phenol', 'Brc1ccc(cc1)C.Oc1ccc(cc1)CC>>c1cc(ccc1C)Oc1ccc(cc1)CC', 1),
56
+ ('ullmann_pyrrole_aryl_bromide_pyrrole',
57
+ 'ullmann_pyrrole', 'Brc1ccc(cc1)C.[nH]1cccc1>>c1ccn(c1)-c1ccc(cc1)C', 1),
58
+ ('ullmann_pyrrole_aryl_bromide_pyrazole',
59
+ 'ullmann_pyrrole', 'Brc1ccc(cc1)C.[nH]1nccc1>>c1cc(ccc1-n1nccc1)C', 2),
60
+ ('ullmann_pyrrole_aryl_bromide_imidazole',
61
+ 'ullmann_pyrrole', 'Brc1ccc(cc1)C.[nH]1cncc1>>c1cc(ccc1-n1ccnc1)C', 2),
62
+ ('ullmann_pyrrole_pyridone_chloride_pyrrole',
63
+ 'ullmann_pyrrole', 'CN1C=CC(Cl)=CC1=O.[nH]1cccc1>>CN1C=CC(=CC1=O)-n1cccc1', 1),
64
+ ('chan_lam_boronic_acid_primary_amine',
65
+ 'chan_lam', 'OB(O)c1ccc(cc1)C.NCC>>c1cc(ccc1C)NCC', 1),
66
+ ('chan_lam_boronic_acid_phenol',
67
+ 'chan_lam', 'OB(O)c1ccc(cc1)C.Oc1ccc(cc1)CC>>c1cc(ccc1C)Oc1ccc(cc1)CC', 1),
68
+ ('sulfonylation_sulfonyl_chloride_alcohol',
69
+ 'sulfonylation', 'ClS(=O)(=O)c1ccccc1.OCCC>>c1ccccc1S(=O)(=O)OCCC', 1),
70
+ ('sulfonamide_formation_sulfonyl_chloride_amine',
71
+ 'sulfonamide_formation', 'ClS(=O)(=O)c1ccccc1.NCC>>c1ccccc1S(=O)(=O)NCC', 1),
72
+ ('aminolysis_ester_primary_amine',
73
+ 'aminolysis', 'COC(=O)c1ccc(cc1)C.NCC>>c1cc(ccc1C(NCC)=O)C', 1),
74
+ ('grignard_alkyl_bromide_aldehyde',
75
+ 'grignard', 'BrCC.O=Cc1ccc(cc1)C>>c1cc(ccc1C)C(CC)O', 1),
76
+ ('grignard_alkyl_bromide_ketone',
77
+ 'grignard', 'BrCC.O=C(C)c1ccccc1>>c1cc(ccc1)C(O)(C)CC', 1),
78
+ ('sonogashira_aryl_bromide_terminal_alkyne',
79
+ 'sonogashira', 'Brc1ccc(cc1)C.C#CC>>c1cc(ccc1C)C#CC', 1),
80
+ ('urea_synthesis_isocyanate_primary_amine',
81
+ 'urea_synthesis', 'O=C=Nc1ccccc1.NCC>>c1ccccc1NC(NCC)=O', 1),
82
+ ('cuaac_azide_terminal_alkyne',
83
+ 'cuaac', 'CC#C.CN=[N+]=[N-]>>Cc1cn(C)nn1', 1),
84
+ ('snar_aryl_fluoride_primary_amine',
85
+ 'snar', 'Fc1ccc(cc1)C(F)(F)F.NCC>>c1cc(ccc1C(F)(F)F)NCC', 1),
86
+ ('snar_aryl_fluoride_phenol',
87
+ 'snar', 'Fc1ccc(cc1)C(F)(F)F.Oc1ccc(cc1)C>>c1cc(ccc1C(F)(F)F)Oc1ccc(cc1)C', 1),
88
+ ('snar_aryl_fluoride_thiol',
89
+ 'snar', 'Fc1ccc(cc1)C(F)(F)F.SCC>>c1cc(ccc1C(F)(F)F)SCC', 1),
90
+ ('williamson_alkyl_bromide_phenol',
91
+ 'williamson', 'BrCC.Oc1ccc(cc1)C>>c1cc(ccc1C)OCC', 1),
92
+ ('williamson_alkyl_bromide_alcohol',
93
+ 'williamson', 'BrCCC.OCC>>CCCOCC', 1),
94
+ ('williamson_mesylate_phenol',
95
+ 'williamson', 'CS(=O)(=O)OCC.Oc1ccc(cc1)C>>c1cc(ccc1C)OCC', 1),
96
+ ('williamson_triflate_alcohol',
97
+ 'williamson', 'FC(F)(F)S(=O)(=O)OCC.OCCC>>CCCOCC', 1),
98
+ ('acylation_acyl_chloride_alcohol',
99
+ 'acylation', 'ClC(=O)c1ccccc1.OCC>>c1ccccc1C(OCC)=O', 1),
100
+ ('thioether_thiol_alkyl_bromide',
101
+ 'thioether', 'SCC.BrCCC>>CCSCCC', 1),
102
+ ('carbamate_isocyanate_alcohol',
103
+ 'carbamate', 'O=C=Nc1ccccc1.OCC>>c1ccccc1NC(OCC)=O', 1),
104
+ ('tetrazole_azide_nitrile',
105
+ 'tetrazole', 'CN=[N+]=[N-].N#Cc1ccccc1>>c1ccc(cc1)-c1nnn(C)n1', 1),
106
+ ('kumada_aryl_bromide_alkyl_grignard',
107
+ 'kumada', 'Brc1ccc(cc1)C.C[Mg]Br>>c1cc(ccc1C)C', 1),
108
+ ('kumada_aryl_bromide_aryl_grignard',
109
+ 'kumada', 'Brc1ccc(cc1)C.c1ccccc1[Mg]Br>>c1cc(ccc1-c1ccccc1)C', 1),
110
+ ('negishi_aryl_bromide_alkyl_zinc',
111
+ 'negishi', 'Brc1ccc(cc1)C.CC[Zn]Cl>>c1cc(ccc1C)CC', 1),
112
+ ('stille_aryl_bromide_aryl_stannane',
113
+ 'stille', 'Brc1ccc(cc1)C.c1ccccc1[Sn](C)(C)C>>c1cc(ccc1-c1ccccc1)C', 1),
114
+ ('stille_aryl_bromide_alkenyl_stannane',
115
+ 'stille', 'Brc1ccc(cc1)C.C=C[Sn](C)(C)C>>c1cc(ccc1C=C)C', 1),
116
+ ('hiyama_aryl_bromide_aryl_silane',
117
+ 'hiyama', 'Brc1ccc(cc1)C.c1ccccc1[Si](C)(C)C>>c1cc(ccc1-c1ccccc1)C', 1),
118
+ ('grignard_explicit_alkyl_grignard_aldehyde',
119
+ 'grignard', 'CC[Mg]Br.O=Cc1ccccc1>>c1ccccc1C(CC)O', 1),
120
+ ('nitrile_grignard_alkyl',
121
+ 'nitrile_grignard', 'N#CCC.CC[Mg]Br>>CCC(=O)CC', 1),
122
+ ('heck_aryl_bromide_terminal_alkene',
123
+ 'heck', 'Brc1ccc(cc1)C.C=CC>>c1cc(ccc1C=CC)C', 1),
124
+ ('heck_aryl_bromide_internal_alkene',
125
+ 'heck', 'Brc1ccccc1.CC=CC>>c1ccccc1C(C)=CC', 1),
126
+ ('cross_metathesis_two_terminal_alkenes',
127
+ 'cross_metathesis', 'C=CC.C=CCCC>>CC=CCCC', 1),
128
+ ('wittig_ylide_aldehyde',
129
+ 'wittig', 'c1ccccc1P(c1ccccc1)(c1ccccc1)=C.c1cc(ccc1C=O)C>>c1cc(ccc1C)C=C', 1),
130
+ ('hwe_phosphonate_aldehyde',
131
+ 'hwe', 'CCP(=O)(OC)OC.c1cc(ccc1C=O)C>>c1cc(ccc1C=CC)C', 1),
132
+ ('weinreb_explicit_grignard',
133
+ 'weinreb', 'CC(=O)N(C)OC.CC[Mg]Br>>CCC(=O)C', 1),
134
+ ('weinreb_ester_surrogate_grignard',
135
+ 'weinreb', 'COC(=O)c1ccccc1.CC[Mg]Br>>c1ccccc1C(=O)CC', 1),
136
+ ('weinreb_acyl_chloride_surrogate_grignard',
137
+ 'weinreb', 'c1ccccc1C(=O)Cl.CC[Mg]Br>>c1ccccc1C(=O)CC', 1),
138
+ ('friedel_crafts_acyl_chloride_benzene',
139
+ 'friedel_crafts', 'CC(=O)Cl.c1ccccc1>>c1ccccc1C(=O)C', 1),
140
+ ('hantzsch_thiazole_chloroacetone_thioacetamide',
141
+ 'hantzsch_thiazole', 'ClCC(=O)C.NC(=S)C>>c1(C)scc(C)n1', 1),
142
+ ('knorr_pyrazole_acetylacetone_methylhydrazine',
143
+ 'knorr_pyrazole', 'O=C(C)CC(=O)C.NNC>>c1(C)nn(c(C)c1)C', 1),
144
+ ('paal_knorr_hexanedione_ethylamine',
145
+ 'paal_knorr', 'O=C(C)CCC(=O)C.NCC>>Cc1ccc(C)n1CC', 1, {'reductive_amination'}),
146
+ ('fischer_indole_phenylhydrazine_acetone',
147
+ 'fischer_indole', 'NNc1ccccc1.O=C(C)C>>c1cc2c(cc(C)[nH]2)cc1', 1, {'hydrazone'}),
148
+ ('benzimidazole_diamine_aldehyde',
149
+ 'benzimidazole', 'Nc1ccccc1N.O=CC>>c1(C)[nH]c2c(cccc2)n1', 1, {'reductive_amination'}),
150
+ ('benzoxazole_aminophenol_aldehyde',
151
+ 'benzoxazole', 'Nc1ccccc1O.O=CC>>c1cccc2nc(oc12)C', 1, {'reductive_amination'}),
152
+ ('benzothiazole_aminothiophenol_aldehyde',
153
+ 'benzothiazole', 'Nc1ccccc1S.O=CC>>Cc1nc2c(s1)cccc2', 1, {'reductive_amination'}),
154
+ ('quinoxaline_diamine_diketone',
155
+ 'quinoxaline', 'Nc1ccccc1N.O=C(C)C(=O)C>>c12c(nc(c(n1)C)C)cccc2', 1, {'reductive_amination'}),
156
+ ('friedlander_aminobenzaldehyde_acetone',
157
+ 'friedlander', 'Nc1ccccc1C=O.O=C(C)C>>n1c2c(ccc1C)cccc2', 1, {'reductive_amination', 'aldol'}),
158
+ ('pictet_spengler_phenethylamine_aldehyde',
159
+ 'pictet_spengler', 'NCCc1ccccc1.O=CC>>N1CCc2ccccc2C1C', 1, {'reductive_amination'}),
160
+ ('oxadiazole_124_amidoxime_acyl_chloride',
161
+ 'oxadiazole_124', 'N=C(NO)C.ClC(=O)C>>c1(C)noc(n1)C', 1),
162
+ ('pyrimidine_diketone_amidine',
163
+ 'pyrimidine', 'O=C(C)CC(=O)C.NC(=N)C>>Cc1nc(nc(C)c1)C', 1),
164
+ ('van_leusen_oxazole_tosmic_aldehyde',
165
+ 'van_leusen_oxazole', '[C-]#[N+]CS(=O)(=O)c1ccc(cc1)C.O=CC>>c1oc(C)nc1', 1),
166
+ ('imidazopyridine_aminopyridine_haloketone',
167
+ 'imidazopyridine', 'Nc1ncccc1.ClCC(=O)C>>c1cccn2c1nc(C)c2', 1, {'reductive_amination', 'n_alkylation'}),
168
+ ('niementowski_anthranilic_acid_amide',
169
+ 'niementowski', 'Nc1ccccc1C(=O)O.NC(=O)C>>Oc1c2c(nc(n1)C)cccc2', 1),
170
+ ('liebeskind_srogl_thioester_boronic_acid',
171
+ 'liebeskind_srogl', 'O=C(SC)c1ccccc1.OB(O)c1ccccc1>>O=C(c1ccccc1)c1ccccc1', 1),
172
+ ('knoevenagel_malononitrile_aldehyde',
173
+ 'knoevenagel', 'N#CCC#N.O=Cc1ccccc1>>c1cc(ccc1)C=C(C#N)C#N', 1),
174
+ ('aldol_acetone_benzaldehyde',
175
+ 'aldol', 'O=C(C)C.O=Cc1ccccc1>>c1cc(ccc1)C(CC(=O)C)O', 1, {'reductive_amination'}),
176
+ ('larock_indole_bromoaniline_butyne',
177
+ 'larock_indole', 'Nc1ccccc1Br.CC#CC>>Cc1[nH]c2c(cccc2)c1C', 1, {'reductive_amination'}),
178
+ ('doebner_miller_aniline_crotonaldehyde',
179
+ 'doebner_miller', 'Nc1ccccc1.O=CC=CC>>C1=CC=CC=2C(C)=CC=NC12', 1, {'reductive_amination'}),
180
+ ]
181
+
182
+ _three_component = [
183
+ ('ugi_3cr_aldehyde_amine_isocyano',
184
+ 'ugi_3cr', 'O=CC.NCC.[C-]#[N+]C>>CCNC(C(=O)NC)C', 1),
185
+ ('biginelli_aldehyde_ketoester_urea',
186
+ 'biginelli', 'O=CC.O=C(C)CC(=O)OC.NC(=O)N>>N1C(NC(C)C=C1C)=O', 1),
187
+ ('hantzsch_pyridine_aldehyde_ketoester',
188
+ 'hantzsch_pyridine', 'O=CC.O=C(C)CC(=O)OCC.O=C(C)CC(=O)OCC>>c1(C)c(c(nc(c1C(=O)OCC)C)C)C(=O)OCC', 1),
189
+ ]
190
+
191
+ _four_component = [
192
+ ('ugi_4cr_aldehyde_amine_acid_isocyano',
193
+ 'ugi_4cr', 'O=CC.NCC.OC(=O)C.[C-]#[N+]C>>N(CC)(C(C(NC)=O)C)C(C)=O', 1),
194
+ ]
195
+
196
+ _transformations = [
197
+ ('isoxazole_from_diketone', 'isoxazole', 'O=C(C)CC(=O)C>>c1(onc(C)c1)C', 1,
198
+ {'alpha_halogenation', 'oximation', 'oxo_to_difluoro', 'oxo_to_thioxo'}),
199
+ ('pyridazine_from_diketone', 'pyridazine', 'O=C(C)CCC(=O)C>>c1(C)nnc(C)cc1', 1,
200
+ {'alpha_halogenation', 'oximation', 'oxo_to_difluoro', 'oxo_to_thioxo'}),
201
+ ('appel_primary_alcohol', 'appel', 'OCC>>BrCC', 1,
202
+ {'triflation', 'appel_chloride', 'mesylation', 'tosylation', 'fluorination', 'appel_iodide', 'azidation'}),
203
+ ('appel_secondary_alcohol', 'appel', 'OC(C)CC>>BrC(C)CC', 1,
204
+ {'triflation', 'appel_chloride', 'mesylation', 'tosylation', 'fluorination', 'appel_iodide', 'azidation'}),
205
+ ('borylation_aryl_bromide', 'borylation_acid', 'Brc1c(C)c(C)c(C)c(C)c1C>>OB(O)c1c(C)c(C)c(C)c(C)c1C', 1,
206
+ {'borylation_ester', 'cyanation', 'halide_hydrolysis', 'azidation', 'finkelstein', 'halex',
207
+ 'halide_to_chloride', 'halide_to_methoxy', 'halide_to_thioether', 'halide_to_thiol'}),
208
+ ('nitrile_hydrolysis', 'nitrile_hydrolysis', 'N#CCC>>NC(=O)CC', 1, {'nitrile_to_acid'}),
209
+ ('nitration_benzene', 'nitration', 'c1ccccc1>>[O-][N+](=O)c1ccccc1', 1,
210
+ {'bromination', 'chlorination', 'iodination', 'fluorination'}),
211
+ ('bromination_benzene', 'bromination', 'c1ccccc1>>Brc1ccccc1', 1,
212
+ {'nitration', 'chlorination', 'iodination', 'fluorination'}),
213
+ ('chlorination_benzene', 'chlorination', 'c1ccccc1>>Clc1ccccc1', 1,
214
+ {'nitration', 'bromination', 'iodination', 'fluorination'}),
215
+ ('iodination_benzene', 'iodination', 'c1ccccc1>>Ic1ccccc1', 1,
216
+ {'nitration', 'bromination', 'chlorination', 'fluorination'}),
217
+ ]
218
+
219
+ _oxidations = [
220
+ ('alcohol_to_aldehyde', 'alcohol_to_aldehyde', 'OCC>>O=CC', 1),
221
+ ('alcohol_to_ketone', 'alcohol_to_ketone', 'OC(C)C>>O=C(C)C', 1),
222
+ ('aldehyde_to_acid', 'aldehyde_to_acid', 'O=CC>>OC(=O)C', 1),
223
+ ('dihydroxylation', 'dihydroxylation', 'C=Cc1ccccc1>>OC(CO)c1ccccc1', 1),
224
+ ('thioether_to_sulfoxide', 'thioether_to_sulfoxide', 'CSC>>CS(=O)C', 1, {'thioether_to_sulfone'}),
225
+ ('thioether_to_sulfone', 'thioether_to_sulfone', 'CSC>>CS(=O)(=O)C', 1, {'thioether_to_sulfoxide'}),
226
+ ('sulfoxide_to_sulfone', 'sulfoxide_to_sulfone', 'CS(=O)C>>CS(=O)(=O)C', 1),
227
+ ]
228
+
229
+ _reductions = [
230
+ ('aldehyde_to_alcohol', 'aldehyde_to_alcohol', 'O=Cc1ccccc1>>OCc1ccccc1', 1, {'carbonyl_to_amine'}),
231
+ ('ketone_to_alcohol', 'ketone_to_alcohol', 'O=C(C)c1ccccc1>>OC(C)c1ccccc1', 1, {'carbonyl_to_amine'}),
232
+ ('acid_to_alcohol', 'acid_to_alcohol', 'OC(=O)c1ccccc1>>OCc1ccccc1', 1),
233
+ ('ester_to_alcohol', 'ester_to_alcohol', 'COC(=O)c1ccccc1>>OCc1ccccc1', 1),
234
+ ('amide_to_amine_primary', 'amide_to_amine', 'NC(=O)c1ccccc1>>NCc1ccccc1', 1),
235
+ ('amide_to_amine_secondary', 'amide_to_amine', 'CNC(=O)c1ccccc1>>CNCc1ccccc1', 1),
236
+ ('nitrile_to_amine', 'nitrile_to_amine', 'N#Cc1ccccc1>>NCc1ccccc1', 1),
237
+ ('nitro_to_amine', 'nitro_to_amine', '[O-][N+](=O)c1ccccc1>>Nc1ccccc1', 1),
238
+ ('azide_to_amine', 'azide_to_amine', 'CN=[N+]=[N-]>>CN', 1),
239
+ ('deoxygenation_primary', 'deoxygenation', 'OCC1CCCCC1>>CC1CCCCC1', 1),
240
+ ('deoxygenation_secondary', 'deoxygenation', 'OC(C)c1ccccc1>>CCc1ccccc1', 1),
241
+ ]
242
+
243
+
244
+ @pytest.mark.parametrize(
245
+ 'args',
246
+ _two_component,
247
+ ids=[x[0] for x in _two_component]
248
+ )
249
+ def test_two_component(args):
250
+ test_id, rxn_name, rxn_smi, expected_count = args[:4]
251
+ exclude = args[4] if len(args) > 4 else set()
252
+
253
+ r = smiles(rxn_smi)
254
+ r.canonicalize()
255
+ r1, r2 = r.reactants
256
+
257
+ results = [(n, rxn) for n, rxn in r1 @ r2 if n not in exclude]
258
+
259
+ names = set(n for n, _ in results)
260
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
261
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
262
+ for _, rxn in results:
263
+ assert rxn == r, f'expected {r}, got {rxn}'
264
+
265
+
266
+ @pytest.mark.parametrize(
267
+ 'test_id,rxn_name,rxn_smi,expected_count',
268
+ _three_component,
269
+ ids=[x[0] for x in _three_component]
270
+ )
271
+ def test_three_component(test_id, rxn_name, rxn_smi, expected_count):
272
+ r = smiles(rxn_smi)
273
+ r.canonicalize()
274
+ r1, r2, r3 = r.reactants
275
+
276
+ results = list(r1 @ [r2, r3])
277
+
278
+ names = set(n for n, _ in results)
279
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
280
+
281
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
282
+
283
+ for _, rxn in results:
284
+ assert rxn == r, f'expected {r}, got {rxn}'
285
+
286
+
287
+ @pytest.mark.parametrize(
288
+ 'test_id,rxn_name,rxn_smi,expected_count',
289
+ _four_component,
290
+ ids=[x[0] for x in _four_component]
291
+ )
292
+ def test_four_component(test_id, rxn_name, rxn_smi, expected_count):
293
+ r = smiles(rxn_smi)
294
+ r.canonicalize()
295
+ r1, r2, r3, r4 = r.reactants
296
+
297
+ results = list(r1 @ [r2, r3, r4])
298
+
299
+ names = set(n for n, _ in results)
300
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
301
+
302
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
303
+
304
+ for _, rxn in results:
305
+ assert rxn == r, f'expected {r}, got {rxn}'
306
+
307
+
308
+ @pytest.mark.parametrize(
309
+ 'args',
310
+ _oxidations,
311
+ ids=[x[0] for x in _oxidations]
312
+ )
313
+ def test_oxidation(args):
314
+ test_id, rxn_name, rxn_smi, expected_count = args[:4]
315
+ exclude = args[4] if len(args) > 4 else set()
316
+
317
+ r = smiles(rxn_smi)
318
+ r.canonicalize()
319
+ mol = r.reactants[0]
320
+
321
+ results = [(n, rxn) for n, rxn in mol.oxidize() if n not in exclude]
322
+
323
+ names = set(n for n, _ in results)
324
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
325
+
326
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
327
+
328
+ for _, rxn in results:
329
+ assert rxn == r, f'expected {r}, got {rxn}'
330
+
331
+
332
+ @pytest.mark.parametrize(
333
+ 'args',
334
+ _reductions,
335
+ ids=[x[0] for x in _reductions]
336
+ )
337
+ def test_reduction(args):
338
+ test_id, rxn_name, rxn_smi, expected_count = args[:4]
339
+ exclude = args[4] if len(args) > 4 else set()
340
+
341
+ r = smiles(rxn_smi)
342
+ r.canonicalize()
343
+ mol = r.reactants[0]
344
+
345
+ results = [(n, rxn) for n, rxn in mol.reduce() if n not in exclude]
346
+
347
+ names = set(n for n, _ in results)
348
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
349
+
350
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
351
+
352
+ for _, rxn in results:
353
+ assert rxn == r, f'expected {r}, got {rxn}'
354
+
355
+
356
+ @pytest.mark.parametrize(
357
+ 'args',
358
+ _transformations,
359
+ ids=[x[0] for x in _transformations]
360
+ )
361
+ def test_transformation(args):
362
+ test_id, rxn_name, rxn_smi, expected_count = args[:4]
363
+ exclude = args[4] if len(args) > 4 else set()
364
+
365
+ r = smiles(rxn_smi)
366
+ r.canonicalize()
367
+ mol = r.reactants[0]
368
+
369
+ results = [(n, rxn) for n, rxn in mol.transform() if n not in exclude]
370
+
371
+ names = set(n for n, _ in results)
372
+ assert names == {rxn_name}, f'expected {rxn_name}, got {sorted(names)}'
373
+
374
+ assert len(results) == expected_count, f'expected {expected_count}, got {len(results)}'
375
+
376
+ for _, rxn in results:
377
+ assert rxn == r, f'expected {r}, got {rxn}'