chython 3.3__tar.gz → 3.3.1__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.
Files changed (468) hide show
  1. {chython-3.3/chython.egg-info → chython-3.3.1}/PKG-INFO +1 -1
  2. {chython-3.3 → chython-3.3.1}/chython/chemistry/_salts.py +49 -3
  3. {chython-3.3 → chython-3.3.1}/chython/chemistry/_tables.py +14 -9
  4. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/salts.tsv +22 -7
  5. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_salts.py +206 -5
  6. {chython-3.3 → chython-3.3.1/chython.egg-info}/PKG-INFO +1 -1
  7. {chython-3.3 → chython-3.3.1}/pyproject.toml +1 -1
  8. {chython-3.3 → chython-3.3.1}/LICENSE +0 -0
  9. {chython-3.3 → chython-3.3.1}/MANIFEST.in +0 -0
  10. {chython-3.3 → chython-3.3.1}/README.md +0 -0
  11. {chython-3.3 → chython-3.3.1}/build_inchi.py +0 -0
  12. {chython-3.3 → chython-3.3.1}/chython/__init__.py +0 -0
  13. {chython-3.3 → chython-3.3.1}/chython/_functions.py +0 -0
  14. {chython-3.3 → chython-3.3.1}/chython/chemistry/__init__.py +0 -0
  15. {chython-3.3 → chython-3.3.1}/chython/chemistry/_abbreviations.py +0 -0
  16. {chython-3.3 → chython-3.3.1}/chython/chemistry/_canonicalize.py +0 -0
  17. {chython-3.3 → chython-3.3.1}/chython/chemistry/_counts.py +0 -0
  18. {chython-3.3 → chython-3.3.1}/chython/chemistry/_crippen.py +0 -0
  19. {chython-3.3 → chython-3.3.1}/chython/chemistry/_hydrogens.py +0 -0
  20. {chython-3.3 → chython-3.3.1}/chython/chemistry/_implicit.py +0 -0
  21. {chython-3.3 → chython-3.3.1}/chython/chemistry/_isomers.py +0 -0
  22. {chython-3.3 → chython-3.3.1}/chython/chemistry/_kekule_form.py +0 -0
  23. {chython-3.3 → chython-3.3.1}/chython/chemistry/_maccs.py +0 -0
  24. {chython-3.3 → chython-3.3.1}/chython/chemistry/_organometallics.py +0 -0
  25. {chython-3.3 → chython-3.3.1}/chython/chemistry/_perceive.py +0 -0
  26. {chython-3.3 → chython-3.3.1}/chython/chemistry/_pharmacophore.py +0 -0
  27. {chython-3.3 → chython-3.3.1}/chython/chemistry/_protomers.py +0 -0
  28. {chython-3.3 → chython-3.3.1}/chython/chemistry/_qed.py +0 -0
  29. {chython-3.3 → chython-3.3.1}/chython/chemistry/_residues.py +0 -0
  30. {chython-3.3 → chython-3.3.1}/chython/chemistry/_resonance.py +0 -0
  31. {chython-3.3 → chython-3.3.1}/chython/chemistry/_saturate.py +0 -0
  32. {chython-3.3 → chython-3.3.1}/chython/chemistry/_smarts.py +0 -0
  33. {chython-3.3 → chython-3.3.1}/chython/chemistry/_standardize.py +0 -0
  34. {chython-3.3 → chython-3.3.1}/chython/chemistry/_tpsa.py +0 -0
  35. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/abbreviations.tsv +0 -0
  36. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/acids.tsv +0 -0
  37. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/covalent_radii.tsv +0 -0
  38. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/crippen.tsv +0 -0
  39. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/hbond.tsv +0 -0
  40. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/maccs.tsv +0 -0
  41. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/maccs_corpus.tsv +0 -0
  42. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/pharmacophore.tsv +0 -0
  43. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/qed_alerts.tsv +0 -0
  44. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/residues.tsv +0 -0
  45. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/resonance.tsv +0 -0
  46. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/rotatable.tsv +0 -0
  47. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/standardize_groups.tsv +0 -0
  48. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/standardize_metals.tsv +0 -0
  49. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/sybyl_types.tsv +0 -0
  50. {chython-3.3 → chython-3.3.1}/chython/chemistry/tables/tpsa.tsv +0 -0
  51. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/__init__.py +0 -0
  52. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/_corpus.py +0 -0
  53. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/_oracle.py +0 -0
  54. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/gen_standardize_rules.py +0 -0
  55. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_abbreviations.py +0 -0
  56. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_acids_tsv.py +0 -0
  57. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_canonicalize.py +0 -0
  58. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_counts.py +0 -0
  59. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_covalent_radii_tsv.py +0 -0
  60. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_crippen.py +0 -0
  61. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_crippen_tsv.py +0 -0
  62. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_dependency_direction.py +0 -0
  63. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_featurizer_injection.py +0 -0
  64. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_featurizer_tables_lazy.py +0 -0
  65. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_isomers.py +0 -0
  66. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_kekule_form.py +0 -0
  67. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_maccs.py +0 -0
  68. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_maccs_corpus.py +0 -0
  69. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_maccs_tsv.py +0 -0
  70. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_organometallics.py +0 -0
  71. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_perceive.py +0 -0
  72. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_pharmacophore.py +0 -0
  73. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_protomers.py +0 -0
  74. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_qed.py +0 -0
  75. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_qed_alerts_tsv.py +0 -0
  76. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_reaction_hydrogen_repair.py +0 -0
  77. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_reaction_passes.py +0 -0
  78. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_residues.py +0 -0
  79. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_resonance.py +0 -0
  80. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_resonance_tsv.py +0 -0
  81. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_saturate.py +0 -0
  82. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_smarts.py +0 -0
  83. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_differential.py +0 -0
  84. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_groups_port.py +0 -0
  85. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_overvalent_nitrogen.py +0 -0
  86. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_rules_examples.py +0 -0
  87. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_rules_merges.py +0 -0
  88. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_standardize_rules_tsv.py +0 -0
  89. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_thiele_is_single_purpose.py +0 -0
  90. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_tpsa.py +0 -0
  91. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_tpsa_tsv.py +0 -0
  92. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_valence_report.py +0 -0
  93. {chython-3.3 → chython-3.3.1}/chython/chemistry/test/test_z_translation.py +0 -0
  94. {chython-3.3 → chython-3.3.1}/chython/core/RULES.md +0 -0
  95. {chython-3.3 → chython-3.3.1}/chython/core/__init__.py +0 -0
  96. {chython-3.3 → chython-3.3.1}/chython/core/_canonical.pxi +0 -0
  97. {chython-3.3 → chython-3.3.1}/chython/core/_cip.pxi +0 -0
  98. {chython-3.3 → chython-3.3.1}/chython/core/_core.pyx +0 -0
  99. {chython-3.3 → chython-3.3.1}/chython/core/_descriptors.pxi +0 -0
  100. {chython-3.3 → chython-3.3.1}/chython/core/_elements.pxi +0 -0
  101. {chython-3.3 → chython-3.3.1}/chython/core/_facade.py +0 -0
  102. {chython-3.3 → chython-3.3.1}/chython/core/_features.pxi +0 -0
  103. {chython-3.3 → chython-3.3.1}/chython/core/_fingerprints.pxi +0 -0
  104. {chython-3.3 → chython-3.3.1}/chython/core/_hydrogens.pxi +0 -0
  105. {chython-3.3 → chython-3.3.1}/chython/core/_inchi.pxi +0 -0
  106. {chython-3.3 → chython-3.3.1}/chython/core/_isomorphism.pxi +0 -0
  107. {chython-3.3 → chython-3.3.1}/chython/core/_kekule.pxi +0 -0
  108. {chython-3.3 → chython-3.3.1}/chython/core/_log.py +0 -0
  109. {chython-3.3 → chython-3.3.1}/chython/core/_ml.pxi +0 -0
  110. {chython-3.3 → chython-3.3.1}/chython/core/_molecule_arena.pxi +0 -0
  111. {chython-3.3 → chython-3.3.1}/chython/core/_molecule_container.pxi +0 -0
  112. {chython-3.3 → chython-3.3.1}/chython/core/_molecule_topology.pxi +0 -0
  113. {chython-3.3 → chython-3.3.1}/chython/core/_molecule_views.pxi +0 -0
  114. {chython-3.3 → chython-3.3.1}/chython/core/_morgan.pxi +0 -0
  115. {chython-3.3 → chython-3.3.1}/chython/core/_pach.pxi +0 -0
  116. {chython-3.3 → chython-3.3.1}/chython/core/_pach3.pxi +0 -0
  117. {chython-3.3 → chython-3.3.1}/chython/core/_query_arena.pxi +0 -0
  118. {chython-3.3 → chython-3.3.1}/chython/core/_query_boxes.pxi +0 -0
  119. {chython-3.3 → chython-3.3.1}/chython/core/_query_container.pxi +0 -0
  120. {chython-3.3 → chython-3.3.1}/chython/core/_query_seal.pxi +0 -0
  121. {chython-3.3 → chython-3.3.1}/chython/core/_reaction_passes.py +0 -0
  122. {chython-3.3 → chython-3.3.1}/chython/core/_rings.pxi +0 -0
  123. {chython-3.3 → chython-3.3.1}/chython/core/_smarts_read.pxi +0 -0
  124. {chython-3.3 → chython-3.3.1}/chython/core/_smiles_read.pxi +0 -0
  125. {chython-3.3 → chython-3.3.1}/chython/core/_smiles_write.pxi +0 -0
  126. {chython-3.3 → chython-3.3.1}/chython/core/_smirks_patch.pxi +0 -0
  127. {chython-3.3 → chython-3.3.1}/chython/core/_smirks_read.pxi +0 -0
  128. {chython-3.3 → chython-3.3.1}/chython/core/_sssr.pxi +0 -0
  129. {chython-3.3 → chython-3.3.1}/chython/core/_stereo.pxi +0 -0
  130. {chython-3.3 → chython-3.3.1}/chython/core/_thiele.pxi +0 -0
  131. {chython-3.3 → chython-3.3.1}/chython/core/_valence.pxi +0 -0
  132. {chython-3.3 → chython-3.3.1}/chython/core/elements.tsv +0 -0
  133. {chython-3.3 → chython-3.3.1}/chython/core/isotopes.tsv +0 -0
  134. {chython-3.3 → chython-3.3.1}/chython/core/reaction.py +0 -0
  135. {chython-3.3 → chython-3.3.1}/chython/core/test/__init__.py +0 -0
  136. {chython-3.3 → chython-3.3.1}/chython/core/test/arena_v4_corpus.bin.gz +0 -0
  137. {chython-3.3 → chython-3.3.1}/chython/core/test/bench_ml.py +0 -0
  138. {chython-3.3 → chython-3.3.1}/chython/core/test/chytorch_oracle.py +0 -0
  139. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_element_tables.py +0 -0
  140. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_modeling_view_corpus.py +0 -0
  141. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_pach3_corpus.py +0 -0
  142. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_reaction_pach_corpus.py +0 -0
  143. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_v3_fixtures.py +0 -0
  144. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_v4_fixtures.py +0 -0
  145. {chython-3.3 → chython-3.3.1}/chython/core/test/gen_valence_rules.py +0 -0
  146. {chython-3.3 → chython-3.3.1}/chython/core/test/modeling_view_corpus.json.gz +0 -0
  147. {chython-3.3 → chython-3.3.1}/chython/core/test/modeling_view_corpus.py +0 -0
  148. {chython-3.3 → chython-3.3.1}/chython/core/test/oracle.py +0 -0
  149. {chython-3.3 → chython-3.3.1}/chython/core/test/pach3_corpus.py +0 -0
  150. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_bond_group_corpus.bin.gz +0 -0
  151. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_corpus.py +0 -0
  152. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_v0_corpus.bin.gz +0 -0
  153. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_v0_native_corpus.bin.gz +0 -0
  154. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_v2_corpus.bin.gz +0 -0
  155. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_v3_corpus.bin.gz +0 -0
  156. {chython-3.3 → chython-3.3.1}/chython/core/test/pach_v4_corpus.bin.gz +0 -0
  157. {chython-3.3 → chython-3.3.1}/chython/core/test/reaction_pach_corpus.py +0 -0
  158. {chython-3.3 → chython-3.3.1}/chython/core/test/reaction_pach_v2_corpus.bin.gz +0 -0
  159. {chython-3.3 → chython-3.3.1}/chython/core/test/test_aggregates.py +0 -0
  160. {chython-3.3 → chython-3.3.1}/chython/core/test/test_alternative_spellings.py +0 -0
  161. {chython-3.3 → chython-3.3.1}/chython/core/test/test_apply_scratch_probe.py +0 -0
  162. {chython-3.3 → chython-3.3.1}/chython/core/test/test_arena_f60.py +0 -0
  163. {chython-3.3 → chython-3.3.1}/chython/core/test/test_arena_identity.py +0 -0
  164. {chython-3.3 → chython-3.3.1}/chython/core/test/test_arena_v3_compat.py +0 -0
  165. {chython-3.3 → chython-3.3.1}/chython/core/test/test_arena_v4_compat.py +0 -0
  166. {chython-3.3 → chython-3.3.1}/chython/core/test/test_aromatic_storage.py +0 -0
  167. {chython-3.3 → chython-3.3.1}/chython/core/test/test_canonical.py +0 -0
  168. {chython-3.3 → chython-3.3.1}/chython/core/test/test_canonical_mirror.py +0 -0
  169. {chython-3.3 → chython-3.3.1}/chython/core/test/test_cip_assign.py +0 -0
  170. {chython-3.3 → chython-3.3.1}/chython/core/test/test_cip_cases.py +0 -0
  171. {chython-3.3 → chython-3.3.1}/chython/core/test/test_cip_digraph.py +0 -0
  172. {chython-3.3 → chython-3.3.1}/chython/core/test/test_cip_ranking.py +0 -0
  173. {chython-3.3 → chython-3.3.1}/chython/core/test/test_cip_storage.py +0 -0
  174. {chython-3.3 → chython-3.3.1}/chython/core/test/test_clean_isotopes_and_coordinate_bonds.py +0 -0
  175. {chython-3.3 → chython-3.3.1}/chython/core/test/test_clean_stereo.py +0 -0
  176. {chython-3.3 → chython-3.3.1}/chython/core/test/test_conformers.py +0 -0
  177. {chython-3.3 → chython-3.3.1}/chython/core/test/test_container_log.py +0 -0
  178. {chython-3.3 → chython-3.3.1}/chython/core/test/test_copy_caches.py +0 -0
  179. {chython-3.3 → chython-3.3.1}/chython/core/test/test_derive.py +0 -0
  180. {chython-3.3 → chython-3.3.1}/chython/core/test/test_descriptors.py +0 -0
  181. {chython-3.3 → chython-3.3.1}/chython/core/test/test_element_tables.py +0 -0
  182. {chython-3.3 → chython-3.3.1}/chython/core/test/test_enrich.py +0 -0
  183. {chython-3.3 → chython-3.3.1}/chython/core/test/test_facade.py +0 -0
  184. {chython-3.3 → chython-3.3.1}/chython/core/test/test_features.py +0 -0
  185. {chython-3.3 → chython-3.3.1}/chython/core/test/test_featurizer_injection.py +0 -0
  186. {chython-3.3 → chython-3.3.1}/chython/core/test/test_fingerprints.py +0 -0
  187. {chython-3.3 → chython-3.3.1}/chython/core/test/test_geometry.py +0 -0
  188. {chython-3.3 → chython-3.3.1}/chython/core/test/test_h_unknown.py +0 -0
  189. {chython-3.3 → chython-3.3.1}/chython/core/test/test_hydrogens.py +0 -0
  190. {chython-3.3 → chython-3.3.1}/chython/core/test/test_inchi.py +0 -0
  191. {chython-3.3 → chython-3.3.1}/chython/core/test/test_interop_injection.py +0 -0
  192. {chython-3.3 → chython-3.3.1}/chython/core/test/test_isomorphism.py +0 -0
  193. {chython-3.3 → chython-3.3.1}/chython/core/test/test_kekule.py +0 -0
  194. {chython-3.3 → chython-3.3.1}/chython/core/test/test_log.py +0 -0
  195. {chython-3.3 → chython-3.3.1}/chython/core/test/test_magic.py +0 -0
  196. {chython-3.3 → chython-3.3.1}/chython/core/test/test_meta.py +0 -0
  197. {chython-3.3 → chython-3.3.1}/chython/core/test/test_ml_encoding.py +0 -0
  198. {chython-3.3 → chython-3.3.1}/chython/core/test/test_ml_reaction_transition.py +0 -0
  199. {chython-3.3 → chython-3.3.1}/chython/core/test/test_ml_state_view.py +0 -0
  200. {chython-3.3 → chython-3.3.1}/chython/core/test/test_ml_transition_view.py +0 -0
  201. {chython-3.3 → chython-3.3.1}/chython/core/test/test_ml_unpack_differential.py +0 -0
  202. {chython-3.3 → chython-3.3.1}/chython/core/test/test_modeling_view_frozen.py +0 -0
  203. {chython-3.3 → chython-3.3.1}/chython/core/test/test_molecule.py +0 -0
  204. {chython-3.3 → chython-3.3.1}/chython/core/test/test_morgan.py +0 -0
  205. {chython-3.3 → chython-3.3.1}/chython/core/test/test_no_chython_two_imports.py +0 -0
  206. {chython-3.3 → chython-3.3.1}/chython/core/test/test_oracle.py +0 -0
  207. {chython-3.3 → chython-3.3.1}/chython/core/test/test_pach.py +0 -0
  208. {chython-3.3 → chython-3.3.1}/chython/core/test/test_pach3.py +0 -0
  209. {chython-3.3 → chython-3.3.1}/chython/core/test/test_pack.py +0 -0
  210. {chython-3.3 → chython-3.3.1}/chython/core/test/test_query.py +0 -0
  211. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_edit.py +0 -0
  212. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_query.py +0 -0
  213. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_semantics.py +0 -0
  214. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_serialisation.py +0 -0
  215. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_smirks.py +0 -0
  216. {chython-3.3 → chython-3.3.1}/chython/core/test/test_r_storage.py +0 -0
  217. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_container.py +0 -0
  218. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_identity.py +0 -0
  219. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_pach.py +0 -0
  220. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_passes.py +0 -0
  221. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_patch_stereo.py +0 -0
  222. {chython-3.3 → chython-3.3.1}/chython/core/test/test_reaction_smiles.py +0 -0
  223. {chython-3.3 → chython-3.3.1}/chython/core/test/test_rings.py +0 -0
  224. {chython-3.3 → chython-3.3.1}/chython/core/test/test_rings_c60.py +0 -0
  225. {chython-3.3 → chython-3.3.1}/chython/core/test/test_set_element.py +0 -0
  226. {chython-3.3 → chython-3.3.1}/chython/core/test/test_sgroups.py +0 -0
  227. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smarts_read.py +0 -0
  228. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_r.py +0 -0
  229. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_read.py +0 -0
  230. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_roundtrip.py +0 -0
  231. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write.py +0 -0
  232. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_aromatic.py +0 -0
  233. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_cis_trans.py +0 -0
  234. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_detached.py +0 -0
  235. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_differential.py +0 -0
  236. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_h_unknown.py +0 -0
  237. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_stereo.py +0 -0
  238. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smiles_write_sticky.py +0 -0
  239. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smirks_filter.py +0 -0
  240. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smirks_patch.py +0 -0
  241. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smirks_read.py +0 -0
  242. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smirks_report.py +0 -0
  243. {chython-3.3 → chython-3.3.1}/chython/core/test/test_smirks_stereo.py +0 -0
  244. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_acceptance.py +0 -0
  245. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_anchor_identity.py +0 -0
  246. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_group_storage.py +0 -0
  247. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_owners.py +0 -0
  248. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_parity.py +0 -0
  249. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_perception.py +0 -0
  250. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_query.py +0 -0
  251. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_units.py +0 -0
  252. {chython-3.3 → chython-3.3.1}/chython/core/test/test_stereo_v2_differential.py +0 -0
  253. {chython-3.3 → chython-3.3.1}/chython/core/test/test_structure.py +0 -0
  254. {chython-3.3 → chython-3.3.1}/chython/core/test/test_thiele.py +0 -0
  255. {chython-3.3 → chython-3.3.1}/chython/core/test/test_title.py +0 -0
  256. {chython-3.3 → chython-3.3.1}/chython/core/test/test_topology.py +0 -0
  257. {chython-3.3 → chython-3.3.1}/chython/core/test/test_union_stereo.py +0 -0
  258. {chython-3.3 → chython-3.3.1}/chython/core/test/test_valence.py +0 -0
  259. {chython-3.3 → chython-3.3.1}/chython/core/test/test_view_surface.py +0 -0
  260. {chython-3.3 → chython-3.3.1}/chython/core/test/v3_fixtures.py +0 -0
  261. {chython-3.3 → chython-3.3.1}/chython/core/test/v4_fixtures.py +0 -0
  262. {chython-3.3 → chython-3.3.1}/chython/core/valence_rules.tsv +0 -0
  263. {chython-3.3 → chython-3.3.1}/chython/core/wedge.py +0 -0
  264. {chython-3.3 → chython-3.3.1}/chython/depict/__init__.py +0 -0
  265. {chython-3.3 → chython-3.3.1}/chython/depict/_config.py +0 -0
  266. {chython-3.3 → chython-3.3.1}/chython/depict/_hooks.py +0 -0
  267. {chython-3.3 → chython-3.3.1}/chython/depict/bonds.py +0 -0
  268. {chython-3.3 → chython-3.3.1}/chython/depict/colorbar.py +0 -0
  269. {chython-3.3 → chython-3.3.1}/chython/depict/colormap.py +0 -0
  270. {chython-3.3 → chython-3.3.1}/chython/depict/field.py +0 -0
  271. {chython-3.3 → chython-3.3.1}/chython/depict/figure.py +0 -0
  272. {chython-3.3 → chython-3.3.1}/chython/depict/label.py +0 -0
  273. {chython-3.3 → chython-3.3.1}/chython/depict/layout/__init__.py +0 -0
  274. {chython-3.3 → chython-3.3.1}/chython/depict/layout/clean2d.js +0 -0
  275. {chython-3.3 → chython-3.3.1}/chython/depict/layout/molecule.py +0 -0
  276. {chython-3.3 → chython-3.3.1}/chython/depict/layout/reaction.py +0 -0
  277. {chython-3.3 → chython-3.3.1}/chython/depict/metrics/__init__.py +0 -0
  278. {chython-3.3 → chython-3.3.1}/chython/depict/metrics/helvetica.tsv +0 -0
  279. {chython-3.3 → chython-3.3.1}/chython/depict/metrics/times.tsv +0 -0
  280. {chython-3.3 → chython-3.3.1}/chython/depict/overlay.py +0 -0
  281. {chython-3.3 → chython-3.3.1}/chython/depict/render/__init__.py +0 -0
  282. {chython-3.3 → chython-3.3.1}/chython/depict/render/svg.py +0 -0
  283. {chython-3.3 → chython-3.3.1}/chython/depict/scene.py +0 -0
  284. {chython-3.3 → chython-3.3.1}/chython/depict/style.py +0 -0
  285. {chython-3.3 → chython-3.3.1}/chython/depict/test/__init__.py +0 -0
  286. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_bonds.py +0 -0
  287. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_clean2d.py +0 -0
  288. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_colorbar.py +0 -0
  289. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_colormap.py +0 -0
  290. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_field.py +0 -0
  291. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_figure.py +0 -0
  292. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_label.py +0 -0
  293. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_metrics.py +0 -0
  294. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_overlay.py +0 -0
  295. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_package.py +0 -0
  296. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_r_atom.py +0 -0
  297. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_scene.py +0 -0
  298. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_style.py +0 -0
  299. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_svg.py +0 -0
  300. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_wedge_draw.py +0 -0
  301. {chython-3.3 → chython-3.3.1}/chython/depict/test/test_x3dom.py +0 -0
  302. {chython-3.3 → chython-3.3.1}/chython/depict/wedge.py +0 -0
  303. {chython-3.3 → chython-3.3.1}/chython/depict/x3dom.py +0 -0
  304. {chython-3.3 → chython-3.3.1}/chython/exceptions.py +0 -0
  305. {chython-3.3 → chython-3.3.1}/chython/formats/__init__.py +0 -0
  306. {chython-3.3 → chython-3.3.1}/chython/formats/_text.py +0 -0
  307. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/CTFILE.md +0 -0
  308. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/__init__.py +0 -0
  309. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_ctab.py +0 -0
  310. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_errors.py +0 -0
  311. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_facade.py +0 -0
  312. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_hydrogens.py +0 -0
  313. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_rdf.py +0 -0
  314. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_rxn.py +0 -0
  315. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_sdf.py +0 -0
  316. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_sgroup.py +0 -0
  317. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_stream.py +0 -0
  318. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_tokens.py +0 -0
  319. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_v2000.py +0 -0
  320. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/_v3000.py +0 -0
  321. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/__init__.py +0 -0
  322. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/conftest.py +0 -0
  323. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_aromatic.py +0 -0
  324. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_container_log.py +0 -0
  325. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_data_labels.py +0 -0
  326. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_facade.py +0 -0
  327. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_fidelity.py +0 -0
  328. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_hydrogens.py +0 -0
  329. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_r_atom.py +0 -0
  330. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_rdf.py +0 -0
  331. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_rxn.py +0 -0
  332. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_sdf.py +0 -0
  333. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_sgroup.py +0 -0
  334. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_stereo_label.py +0 -0
  335. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_stream.py +0 -0
  336. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_tokens.py +0 -0
  337. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_v2000.py +0 -0
  338. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_v3000.py +0 -0
  339. {chython-3.3 → chython-3.3.1}/chython/formats/ctfile/test/test_wedge.py +0 -0
  340. {chython-3.3 → chython-3.3.1}/chython/formats/mol2.py +0 -0
  341. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/__init__.py +0 -0
  342. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/_builder.py +0 -0
  343. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/_legacy.py +0 -0
  344. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/_mmcif.py +0 -0
  345. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/_records.py +0 -0
  346. {chython-3.3 → chython-3.3.1}/chython/formats/pdb/_star.py +0 -0
  347. {chython-3.3 → chython-3.3.1}/chython/formats/test/__init__.py +0 -0
  348. {chython-3.3 → chython-3.3.1}/chython/formats/test/conftest.py +0 -0
  349. {chython-3.3 → chython-3.3.1}/chython/formats/test/oracles.py +0 -0
  350. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_conformance.py +0 -0
  351. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_done_when.py +0 -0
  352. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_isolation.py +0 -0
  353. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_log_prefix.py +0 -0
  354. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_mmcif.py +0 -0
  355. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_mol2.py +0 -0
  356. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_no_review_bookkeeping.py +0 -0
  357. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_oracles.py +0 -0
  358. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_pdb.py +0 -0
  359. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_pdb_builder.py +0 -0
  360. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_perceive_agreement.py +0 -0
  361. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_read_only_facades.py +0 -0
  362. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_xyz.py +0 -0
  363. {chython-3.3 → chython-3.3.1}/chython/formats/test/test_xyz_builder.py +0 -0
  364. {chython-3.3 → chython-3.3.1}/chython/formats/xml/__init__.py +0 -0
  365. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_cml.py +0 -0
  366. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_dialect.py +0 -0
  367. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_errors.py +0 -0
  368. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_facade.py +0 -0
  369. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_mrv.py +0 -0
  370. {chython-3.3 → chython-3.3.1}/chython/formats/xml/_tree.py +0 -0
  371. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/__init__.py +0 -0
  372. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/conftest.py +0 -0
  373. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_cml.py +0 -0
  374. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_container_log.py +0 -0
  375. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_dialect.py +0 -0
  376. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_equivalence.py +0 -0
  377. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_facade.py +0 -0
  378. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_mrv.py +0 -0
  379. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_mrv_census.py +0 -0
  380. {chython-3.3 → chython-3.3.1}/chython/formats/xml/test/test_tree.py +0 -0
  381. {chython-3.3 → chython-3.3.1}/chython/formats/xyz.py +0 -0
  382. {chython-3.3 → chython-3.3.1}/chython/interop/__init__.py +0 -0
  383. {chython-3.3 → chython-3.3.1}/chython/interop/_cdk.py +0 -0
  384. {chython-3.3 → chython-3.3.1}/chython/interop/_cdpkit.py +0 -0
  385. {chython-3.3 → chython-3.3.1}/chython/interop/_indigo.py +0 -0
  386. {chython-3.3 → chython-3.3.1}/chython/interop/_iupac.py +0 -0
  387. {chython-3.3 → chython-3.3.1}/chython/interop/_java.py +0 -0
  388. {chython-3.3 → chython-3.3.1}/chython/interop/_openbabel.py +0 -0
  389. {chython-3.3 → chython-3.3.1}/chython/interop/_pandas.py +0 -0
  390. {chython-3.3 → chython-3.3.1}/chython/interop/_rdkit.py +0 -0
  391. {chython-3.3 → chython-3.3.1}/chython/interop/_records.py +0 -0
  392. {chython-3.3 → chython-3.3.1}/chython/interop/_stereo.py +0 -0
  393. {chython-3.3 → chython-3.3.1}/chython/interop/config.py +0 -0
  394. {chython-3.3 → chython-3.3.1}/chython/interop/conformers.py +0 -0
  395. {chython-3.3 → chython-3.3.1}/chython/interop/test/__init__.py +0 -0
  396. {chython-3.3 → chython-3.3.1}/chython/interop/test/conftest.py +0 -0
  397. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_cdk.py +0 -0
  398. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_cdpkit.py +0 -0
  399. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_config.py +0 -0
  400. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_conformers.py +0 -0
  401. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_coordinate_honesty.py +0 -0
  402. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_dispatch.py +0 -0
  403. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_indigo.py +0 -0
  404. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_iupac.py +0 -0
  405. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_log_delivery.py +0 -0
  406. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_openbabel.py +0 -0
  407. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_pandas.py +0 -0
  408. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_rdkit.py +0 -0
  409. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_stereo.py +0 -0
  410. {chython-3.3 → chython-3.3.1}/chython/interop/test/test_v2_oracle.py +0 -0
  411. {chython-3.3 → chython-3.3.1}/chython/reactions/__init__.py +0 -0
  412. {chython-3.3 → chython-3.3.1}/chython/reactions/_enumerate.py +0 -0
  413. {chython-3.3 → chython-3.3.1}/chython/reactions/_numbering.py +0 -0
  414. {chython-3.3 → chython-3.3.1}/chython/reactions/_reconstruct.py +0 -0
  415. {chython-3.3 → chython-3.3.1}/chython/reactions/_stickers.py +0 -0
  416. {chython-3.3 → chython-3.3.1}/chython/reactions/_tables.py +0 -0
  417. {chython-3.3 → chython-3.3.1}/chython/reactions/attention/__init__.py +0 -0
  418. {chython-3.3 → chython-3.3.1}/chython/reactions/attention/_assign.py +0 -0
  419. {chython-3.3 → chython-3.3.1}/chython/reactions/attention/_encode.py +0 -0
  420. {chython-3.3 → chython-3.3.1}/chython/reactions/attention/_session.py +0 -0
  421. {chython-3.3 → chython-3.3.1}/chython/reactions/tables/functional.tsv +0 -0
  422. {chython-3.3 → chython-3.3.1}/chython/reactions/tables/protective.tsv +0 -0
  423. {chython-3.3 → chython-3.3.1}/chython/reactions/tables/reactions.tsv +0 -0
  424. {chython-3.3 → chython-3.3.1}/chython/reactions/tables/roles.tsv +0 -0
  425. {chython-3.3 → chython-3.3.1}/chython/reactions/test/__init__.py +0 -0
  426. {chython-3.3 → chython-3.3.1}/chython/reactions/test/_frozen_ids.py +0 -0
  427. {chython-3.3 → chython-3.3.1}/chython/reactions/test/gen_corpus_glossary.py +0 -0
  428. {chython-3.3 → chython-3.3.1}/chython/reactions/test/golden_subset.smi +0 -0
  429. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_attention.py +0 -0
  430. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_attention_assign.py +0 -0
  431. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_attention_encode.py +0 -0
  432. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_attention_isolation.py +0 -0
  433. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_corpus_glossary.py +0 -0
  434. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_dependency_direction.py +0 -0
  435. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_enumerate.py +0 -0
  436. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_functional.py +0 -0
  437. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_id_stability.py +0 -0
  438. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_numbering.py +0 -0
  439. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_probes.py +0 -0
  440. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_protective.py +0 -0
  441. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_reconstruct.py +0 -0
  442. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_roles.py +0 -0
  443. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_stickers.py +0 -0
  444. {chython-3.3 → chython-3.3.1}/chython/reactions/test/test_tables.py +0 -0
  445. {chython-3.3 → chython-3.3.1}/chython/test/__init__.py +0 -0
  446. {chython-3.3 → chython-3.3.1}/chython/test/test_code_hygiene.py +0 -0
  447. {chython-3.3 → chython-3.3.1}/chython/test/test_container_methods.py +0 -0
  448. {chython-3.3 → chython-3.3.1}/chython/test/test_doc_figures.py +0 -0
  449. {chython-3.3 → chython-3.3.1}/chython/test/test_doc_references.py +0 -0
  450. {chython-3.3 → chython-3.3.1}/chython/test/test_doc_samples.py +0 -0
  451. {chython-3.3 → chython-3.3.1}/chython/test/test_facade_names.py +0 -0
  452. {chython-3.3 → chython-3.3.1}/chython/test/test_hydrogen_parity.py +0 -0
  453. {chython-3.3 → chython-3.3.1}/chython/test/test_libinchi_staging.py +0 -0
  454. {chython-3.3 → chython-3.3.1}/chython/test/test_log_records.py +0 -0
  455. {chython-3.3 → chython-3.3.1}/chython/test/test_optional_numpy.py +0 -0
  456. {chython-3.3 → chython-3.3.1}/chython/test/test_packaging.py +0 -0
  457. {chython-3.3 → chython-3.3.1}/chython/test/test_performance.py +0 -0
  458. {chython-3.3 → chython-3.3.1}/chython/test/test_r_atom_integration.py +0 -0
  459. {chython-3.3 → chython-3.3.1}/chython/test/test_release_build.py +0 -0
  460. {chython-3.3 → chython-3.3.1}/chython/test/test_stereo_bluebook.py +0 -0
  461. {chython-3.3 → chython-3.3.1}/chython/test/test_v2_boundary.py +0 -0
  462. {chython-3.3 → chython-3.3.1}/chython/test/test_writer_posture.py +0 -0
  463. {chython-3.3 → chython-3.3.1}/chython.egg-info/SOURCES.txt +0 -0
  464. {chython-3.3 → chython-3.3.1}/chython.egg-info/dependency_links.txt +0 -0
  465. {chython-3.3 → chython-3.3.1}/chython.egg-info/requires.txt +0 -0
  466. {chython-3.3 → chython-3.3.1}/chython.egg-info/top_level.txt +0 -0
  467. {chython-3.3 → chython-3.3.1}/setup.cfg +0 -0
  468. {chython-3.3 → chython-3.3.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chython
3
- Version: 3.3
3
+ Version: 3.3.1
4
4
  Summary: Library for processing molecules and reactions in python way
5
5
  Author-email: Ramil Nugmanov <nougmanoff@protonmail.com>
6
6
  License-Expression: LGPL-3.0-or-later
@@ -397,9 +397,12 @@ def _tags(build: list[dict], roles: list[str], guarded: bool) -> frozenset[str]:
397
397
  if len(formers) > 1:
398
398
  tags.add('competing_formers')
399
399
  if len(build) > 1:
400
- if any(row['klass'] == 'water' for row in build):
400
+ # A SOLVENT TAG NEEDS THE COMPONENT DRAWN NEUTRAL. `klass` is read off the neutralized probe,
401
+ # which is right for identity -- a conjugate is not a row -- and wrong for this question: the
402
+ # hydroxide of `[OH-].[Na+]` keys as water and is the counterion, not solvent of crystallization.
403
+ if any(row['klass'] == 'water' and not row['charge'] for row in build):
401
404
  tags.add('hydrate')
402
- if any(row['klass'] in _SOLVENT_CLASSES - {'water'} for row in build):
405
+ if any(row['klass'] in _SOLVENT_CLASSES - {'water'} and not row['charge'] for row in build):
403
406
  tags.add('solvate')
404
407
 
405
408
  if any(row['residual_charge'] for row, role in zip(build, roles) if role == 'parent'):
@@ -545,6 +548,34 @@ _RULE_PROTON = 'salts:charge-transfer'
545
548
  #: charges -- and 0 is the f block's unknown, which refuses for the same reason.
546
549
  _DETERMINATE_VALENCE = 3
547
550
 
551
+ #: The s block, as `valence_electrons`: group 1 answers 1 and group 2 answers 2, while the d block answers
552
+ #: its full count (Fe 8, Ag 11, Zn 12) and aluminium 3, so these two values name no other metal.
553
+ _REDUCING_ELECTRONS = frozenset({1, 2})
554
+
555
+ #: Beryllium, the one s-block metal that does not reduce water or an alcohol, excluded by element.
556
+ _BERYLLIUM = 4
557
+
558
+
559
+ def _hydride(molecule: MoleculeContainer, n: int, log: MutableSequence) -> bool:
560
+ """Does charging free metal `n` mean losing a hydrogen it was drawn with? Logs the refusal if so.
561
+
562
+ `standardize()` recomputes the implicit hydrogen count of every atom this stage writes, and the count
563
+ an ionic metal derives is 0, so writing a charge here is what would delete the hydride. `[NaH].CCO` is
564
+ sodium hydride in ethanol AS DRAWN; sodium ethoxide and H2 is a reaction, which this pass does not run.
565
+ The same guard `split_salts` applies before cutting a bond, for the same reason.
566
+ """
567
+ hydrogens = molecule.implicit_h_of(n)
568
+ if hydrogens is None:
569
+ count = 'an unknown number of'
570
+ elif hydrogens:
571
+ count = str(hydrogens)
572
+ else:
573
+ return False
574
+ log.append(LogRecord(_RULE_METAL, (n,),
575
+ f'atom {n} is a free metal carrying {count} implicit hydrogen(s); charging it '
576
+ f'would drop them, so the whole record is left as drawn', REFUSED))
577
+ return True
578
+
548
579
 
549
580
  def fix_salt_charges(molecule: MoleculeContainer, log: MutableSequence) -> set[int]:
550
581
  """Move the charges a salt was drawn without: `CC(=O)O.[Na]` is `CC(=O)[O-].[Na+]`. Written ids.
@@ -563,6 +594,11 @@ def fix_salt_charges(molecule: MoleculeContainer, log: MutableSequence) -> set[i
563
594
  ALL-OR-NOTHING PER RECORD, not per site, and both steps are planned entirely in reads: step 1 charges a
564
595
  metal on the strength of a balance step 2 may refuse. `[Na]` alone is that case, and it comes back as
565
596
  `[Na]`.
597
+
598
+ WATER AND AN ALCOHOL ARE SITES ONLY FOR AN S-BLOCK METAL. `CCO.[Na]` is sodium ethoxide and
599
+ `CCO.[Zn]` is left as drawn: the table's `metal_protic` rows join the rung ladder only when every free
600
+ metal in the record is group 1 or group 2 and none is beryllium. They sit on rung 6, below every acid,
601
+ so a record holding both an acid and an alcohol spends its metal on the acid.
566
602
  """
567
603
  metals = [atom.n for atom in molecule.atoms() if atom.is_metal and not atom.degree]
568
604
  if not metals:
@@ -574,6 +610,8 @@ def fix_salt_charges(molecule: MoleculeContainer, log: MutableSequence) -> set[i
574
610
  if not any(charges.values()):
575
611
  # step 1: no metal carries a charge, so the drawing states nothing to override
576
612
  for n in metals:
613
+ if _hydride(molecule, n, log):
614
+ return set()
577
615
  electrons = molecule.atom(n).valence_electrons
578
616
  if not 0 < electrons <= _DETERMINATE_VALENCE:
579
617
  if electrons == 0:
@@ -600,9 +638,14 @@ def fix_salt_charges(molecule: MoleculeContainer, log: MutableSequence) -> set[i
600
638
 
601
639
  sites: list[tuple[int, int, int, str]] = []
602
640
  if total > anions:
641
+ by_klass = salts_rows_by_klass()
642
+ rows = by_klass['protic_acid']
643
+ if all(molecule.atom(n).valence_electrons in _REDUCING_ELECTRONS and
644
+ molecule.element_of(n) != _BERYLLIUM for n in metals):
645
+ rows += by_klass['metal_protic']
603
646
  ranks = molecule.atoms_order
604
647
  best: dict[int, tuple[int, str]] = {}
605
- for row in salts_rows_by_klass()['protic_acid']:
648
+ for row in rows:
606
649
  for mapping in row.query.get_mapping(molecule):
607
650
  n = mapping[row.anchor]
608
651
  if molecule.charge_of(n) or (n in best and best[n][0] <= row.order):
@@ -646,6 +689,9 @@ def fix_salt_charges(molecule: MoleculeContainer, log: MutableSequence) -> set[i
646
689
  group_numbers[n] = electrons
647
690
  held = {n: planned.get(n, charges[n]) for n in metals}
648
691
  raises = {n: group_numbers[n] for n in metals if held[n] < group_numbers[n]}
692
+ for n in raises:
693
+ if _hydride(molecule, n, log):
694
+ return set()
649
695
  reached = sum(raises.get(n, held[n]) for n in metals)
650
696
  if reached != anions:
651
697
  log.append(LogRecord(_RULE_METAL, tuple(metals),
@@ -303,14 +303,18 @@ SALT_MATCHES = ('embed', 'whole')
303
303
 
304
304
  #: The closed class vocabulary. A row naming anything else is a load-time error, because a class the
305
305
  #: passes never ask for is a row that silently does nothing.
306
- SALT_CLASSES = ('metal_cation', 'charge_acceptor', 'protic_acid',
306
+ SALT_CLASSES = ('metal_cation', 'charge_acceptor', 'protic_acid', 'metal_protic',
307
307
  'mineral_acid', 'sulfonic_acid', 'short_carboxylic_acid', 'carboxylic_acid',
308
308
  'aromatic_acid', 'fatty_acid', 'amino_acid', 'amine_base', 'quaternary_ammonium',
309
309
  'water', 'alcohol', 'hydrocarbon', 'halo_solvent', 'aprotic_solvent')
310
310
 
311
311
  #: Which classes are matched by embedding. Pinned here rather than trusted from the row so a typo in
312
312
  #: `match` is a load-time error instead of a row that never fires.
313
- _EMBED_CLASSES = frozenset({'metal_cation', 'charge_acceptor', 'protic_acid'})
313
+ _EMBED_CLASSES = frozenset({'metal_cation', 'charge_acceptor', 'protic_acid', 'metal_protic'})
314
+
315
+ #: Which classes carry an acidity rung. Both, and on one scale: `fix_salt_charges` ranks the two pools
316
+ #: together, so a rung that meant something different per class would decide nothing.
317
+ _RUNGED_CLASSES = frozenset({'protic_acid', 'metal_protic'})
314
318
 
315
319
 
316
320
  class SaltRow(NamedTuple):
@@ -319,9 +323,10 @@ class SaltRow(NamedTuple):
319
323
  Exactly one of `query` (an `embed` row) and `key` (a `whole` row) is set. `anchor` is the stable id
320
324
  of the query atom mapped `:1` -- the subject, since a row may name a whole neighbourhood. `key` is
321
325
  `format(species, '!s')`, the stereo-free canonical SMILES a species row is matched by. `charges` is
322
- the set of charges a cation may end up with, `metal_cation` only. `order` is the acidity rung,
323
- `protic_acid` only, low being more acidic; equal values are tied. `heavy_atoms` is the species' atom
324
- count, `0` for an `embed` row -- a size judgement the caller would otherwise re-measure per component.
326
+ the set of charges a cation may end up with, `metal_cation` only. `order` is the acidity rung on one
327
+ scale over `protic_acid` and `metal_protic`, low being more acidic; equal values are tied.
328
+ `heavy_atoms` is the species' atom count, `0` for an `embed` row -- a size judgement the caller would
329
+ otherwise re-measure per component.
325
330
  """
326
331
  id: str
327
332
  match: str
@@ -393,11 +398,11 @@ def _compile_salts() -> tuple[SaltRow, ...]:
393
398
 
394
399
  if row['order'] == '-':
395
400
  order = 0
396
- if klass == 'protic_acid':
397
- raise ValueError(f'{row_id}: a protic_acid row must state its acidity rung; without one '
398
- 'the proton fix_salt_charges() moves would be chosen by file position')
401
+ if klass in _RUNGED_CLASSES:
402
+ raise ValueError(f'{row_id}: a {klass} row must state its acidity rung; without one the '
403
+ 'proton fix_salt_charges() moves would be chosen by file position')
399
404
  else:
400
- if klass != 'protic_acid':
405
+ if klass not in _RUNGED_CLASSES:
401
406
  raise ValueError(f'{row_id}: order is the acidity rung and means nothing for a {klass} '
402
407
  'row; write `-`')
403
408
  order = int(row['order'])
@@ -17,6 +17,8 @@
17
17
  # that one atom -- a lone [Na+]. All 93 metals `[M]` accepts qualify.
18
18
  # charge_acceptor embed split_salts (the atom that keeps the electron pair)
19
19
  # protic_acid embed decompose_salts (the acid_salt tag), fix_salt_charges (the proton source)
20
+ # metal_protic embed fix_salt_charges ONLY, and only when every free metal is s-block -- a site a
21
+ # reducing metal opens and no acid table calls an acid
20
22
  # the fourteen species classes whole decompose_salts
21
23
  #
22
24
  # A SPECIES ROW IS COMPARED BY `format(component, '!s')` -- the canonical SMILES with stereo disabled,
@@ -38,14 +40,19 @@
38
40
  # at charge+k; the row lists every value that is allowed to be, and the whole atom is refused before
39
41
  # anything is cut -- all-or-nothing, never a partially split molecule.
40
42
  #
41
- # `order` IS THE ACIDITY RUNG AND ONLY A `protic_acid` ROW HAS ONE. Low is more acidic; rows sharing a
42
- # value are tied, and a tie is resolved by canonical order and logged rather than by file position.
43
+ # `order` IS THE ACIDITY RUNG AND ONLY A `protic_acid` OR `metal_protic` ROW HAS ONE. Low is more acidic;
44
+ # rows sharing a value are tied, and a tie is resolved by canonical order and logged rather than by file
45
+ # position. ONE SCALE FOR BOTH CLASSES, because `fix_salt_charges` ranks them in one pool: a carboxylic
46
+ # acid beside an alcohol and one sodium gives the carboxylate, rung 4 against rung 6.
43
47
  #
44
- # ALCOHOLS ARE DELIBERATELY ABSENT. `CCO.[Na]` is more often sodium metal in ethanol than sodium ethoxide,
45
- # and a row here would resolve that against the commoner reading. So is every azole but tetrazole: below
46
- # sulfonamide's rung an N-H needs a hydride or an organolithium, and a metal drawn beside one is reagent
47
- # chemistry. An acid with no row refuses, logs, and surfaces as a `charges_undrawn` tag -- the count of
48
- # those refusals is what would justify a row.
48
+ # WATER AND ALCOHOL ARE NOT ACIDS, THEY ARE WHAT A FREE S-BLOCK METAL REDUCES. `CCN.CCO` is a mixture and
49
+ # `CCO` is no acid site, so `decompose_salts` reads neither as a salt and a hydrate stays droppable;
50
+ # `CCO.[Na]` is sodium ethoxide, because sodium does not stand beside a hydroxyl. That distinction is the
51
+ # whole of `metal_protic`. Beryllium is the one s-block metal outside it, not reducing water.
52
+ #
53
+ # EVERY AZOLE BUT TETRAZOLE IS ABSENT. Below sulfonamide's rung an N-H needs a hydride or an
54
+ # organolithium, and a metal drawn beside one is reagent chemistry. An acid with no row refuses, logs, and
55
+ # surfaces as a `charges_undrawn` tag -- the count of those refusals is what would justify a row.
49
56
  #
50
57
  # There is no `elements` column: `pattern` already names the elements a row applies to, and `keep=['Na']` is
51
58
  # resolved against the MOLECULE's atoms.
@@ -58,18 +65,26 @@ salts:thiophosphate embed charge_acceptor [O,S,Se;D2;z1:1]-[P]=[S,Se] - - thio-
58
65
  salts:phenolate embed charge_acceptor [O,S,Se;D2;z1:1]-[C,N;a] - - phenolate, thiophenolate, N-hydroxy azole
59
66
  salts:nitrate embed charge_acceptor [O;D2;z1:1]-[N+](-[O-])=O - - nitrate, drawn charge-separated as standardize() leaves it
60
67
  salts:halide-hydroxide embed charge_acceptor [O,F,Cl,Br,I;D1;z1:1] - - a terminal halogen or oxygen: halide, hydroxide, alkoxide
68
+ salts:alkoxide embed charge_acceptor [O,S,Se;D2;z1:1](-[C,Si;z1])-[M] - - alkoxide, thiolate, silanolate drawn with the metal bonded. The `[M]` is the row: without it the pattern is true of diethyl ether
61
69
  # --- acidic sites: which hydrogen a metal may take, most acidic first ----------------------------- #
62
70
  salts:sulfonic-oh embed protic_acid [O;D1;z1;h1:1]-[S;z5](=O)=O - 1 sulfonic and sulfuric acid
63
71
  salts:oxo-acid-oh embed protic_acid [O;D1;z1;h1:1]-[N,P,Cl,Br,I]=O - 2 phosphoric, phosphonic, nitrous, perchloric
64
72
  salts:nitric-oh embed protic_acid [O;D1;z1;h1:1]-[N+,P+,Cl+,Br+,I+]-[O-] - 2 nitric, drawn charge-separated as standardize() leaves it
65
73
  salts:acyl-sulfonamide embed protic_acid [N;D2;z1;h1:1](-[C;z2]=O)-[S;z5](=O)=O - 2 acyl sulfonamide: saccharin
74
+ salts:sulfinic-oh embed protic_acid [O;D1;z1;h1:1]-[S;z2]=O - 2 sulfinic acid. The sulfonic row above is `z5`, which this S is not
75
+ salts:thio-acid-sh embed protic_acid [S;D1;z1;h1:1]-[C;z2]=[O,S] - 2 thioacid, dithioacid, xanthic acid, dithiocarbamic acid. Thioacetic acid is a rung optimistic here, which costs a tie broken the wrong way when one component holds two sites
66
76
  salts:hydrogen-halide embed protic_acid [F,Cl,Br,I;D0;h1:1] - 3 HF HCl HBr HI: the unbonded halogen holding its hydrogen
67
77
  salts:carboxylic-oh embed protic_acid [O;D1;z1;h1:1]-[C;z2]=O - 4 carboxylic acid
68
78
  salts:tetrazole-1h embed protic_acid [nH;r5:1]:1:n:n:n:c:1 - 4 tetrazole 1H, the carboxylic-acid bioisostere
69
79
  salts:tetrazole-2h embed protic_acid n:1:[nH;r5:1]:n:n:c:1 - 4 tetrazole 2H: standardize() converges no mobile hydrogen, so both tautomers get a row
80
+ salts:thiophenol-sh embed protic_acid [S;D1;z1;h1:1]-[C,N;a] - 4 thiophenol
70
81
  salts:phenol-oh embed protic_acid [O;D1;z1;h1:1]-[C,N;a] - 5 phenol, N-hydroxy azole
71
82
  salts:imide embed protic_acid [N;D2;z1;h1:1](-[C;z2]=O)-[C;z2]=O - 5 imide: phenytoin, succinimide
72
83
  salts:sulfonamide embed protic_acid [N;z1;h1,h2:1]-[S;z5](=O)=O - 5 sulfonamide, tosylamide
84
+ salts:thiol-sh embed protic_acid [S;D1;z1;h1:1]-[C;z1] - 5 thiol
85
+ # --- sites only an s-block metal opens, on the same rung scale ------------------------------------ #
86
+ salts:water-oh embed metal_protic [O;D0;z1;h2:1] - 6 water
87
+ salts:alcohol-oh embed metal_protic [O;D1;z1;h1:1]-[C,Si;z1] - 6 alcohol, silanol. `D1` and `z1`, so a phenol, a carboxylic acid and an ether are each somebody else's row or nobody's
73
88
  # --- species: the acids --------------------------------------------------------------------------- #
74
89
  salts:hf whole mineral_acid F - - hydrofluoric
75
90
  salts:hcl whole mineral_acid Cl - - hydrochloric
@@ -57,6 +57,24 @@ def test_the_metals_chython_two_left_alone_now_split():
57
57
  assert format(m) == expect, s
58
58
 
59
59
 
60
+ def test_an_alkoxide_drawn_with_the_metal_bonded_splits():
61
+ """The drawn O-metal bond states the alkoxide, so there is nothing left to disambiguate and
62
+ `salts:alkoxide` reads it. Silicon and boron are outside `[M]`, so a silyl ether is untouched."""
63
+ for s, expect in [('CCO[Na]', 'C(C)[O-].[Na+]'), # sodium ethoxide
64
+ ('CC(C)(C)O[K]', 'C(C)([O-])(C)C.[K+]'), # potassium tert-butoxide
65
+ ('CCS[K]', 'C(C)[S-].[K+]'), # potassium ethanethiolate
66
+ ('C[Si](C)(C)O[Na]', 'C[Si]([O-])(C)C.[Na+]'), # sodium trimethylsilanolate
67
+ ('CCO[Mg]OCC', 'C(C)[O-].C(C)[O-].[Mg+2]')]:
68
+ m = smiles(s)
69
+ assert split_salts(m) is True, s
70
+ assert format(m) == expect, s
71
+ for s in ['CCOCC', 'CSC', 'CCO[Si](C)(C)C', 'CCOB(OCC)OCC']: # no metal, no acceptor
72
+ m = smiles(s)
73
+ before = m.canonical_bytes
74
+ assert split_salts(m) is False, s
75
+ assert m.canonical_bytes == before, s
76
+
77
+
60
78
  def test_the_atom_count_never_changes():
61
79
  """The atom count is a contract of this pass; nothing in this module deletes a component."""
62
80
  for s in ['CC(=O)O[Na]', 'CC(=O)O[Zn]OC(C)=O', '[Al](OC(C)=O)(OC(C)=O)OC(C)=O', '[Na][Cl]']:
@@ -627,7 +645,8 @@ def test_classes_are_grouped_and_none_is_missing():
627
645
  assert set(grouped) == set(SALT_CLASSES)
628
646
  assert sum(len(rows) for rows in grouped.values()) == len(salts_rows())
629
647
  assert len(grouped['metal_cation']) == 1
630
- assert len(grouped['charge_acceptor']) == 5
648
+ assert len(grouped['charge_acceptor']) == 6
649
+ assert len(grouped['metal_protic']) == 2
631
650
  assert len(grouped['water']) == 1
632
651
 
633
652
 
@@ -646,9 +665,10 @@ def test_only_the_metal_cation_row_carries_charges():
646
665
  assert bool(row.charges) == (row.klass == 'metal_cation'), row.id
647
666
 
648
667
 
649
- def test_only_a_protic_acid_row_carries_an_order():
668
+ def test_only_a_runged_row_carries_an_order():
669
+ """One rung scale over the two classes `fix_salt_charges` ranks together, and no rung anywhere else."""
650
670
  for row in salts_rows():
651
- assert bool(row.order) == (row.klass == 'protic_acid'), row.id
671
+ assert bool(row.order) == (row.klass in ('protic_acid', 'metal_protic')), row.id
652
672
 
653
673
 
654
674
  def test_the_metal_row_covers_every_metal_the_core_calls_one():
@@ -700,17 +720,30 @@ ACID_LADDER = (
700
720
  ('salts:oxo-acid-oh', 2, 'OP(=O)(O)O'),
701
721
  ('salts:nitric-oh', 2, 'O[N+](=O)[O-]'),
702
722
  ('salts:acyl-sulfonamide', 2, 'O=C1NS(=O)(=O)c2ccccc21'),
723
+ ('salts:sulfinic-oh', 2, 'CS(=O)O'),
724
+ ('salts:thio-acid-sh', 2, 'CCOC(=S)S'),
703
725
  ('salts:hydrogen-halide', 3, 'Cl'),
704
726
  ('salts:carboxylic-oh', 4, 'CC(=O)O'),
705
727
  ('salts:tetrazole-1h', 4, 'c1nnn[nH]1'),
706
728
  ('salts:tetrazole-2h', 4, 'c1nn[nH]n1'),
729
+ ('salts:thiophenol-sh', 4, 'Sc1ccccc1'),
707
730
  ('salts:phenol-oh', 5, 'Oc1ccccc1'),
708
731
  ('salts:imide', 5, 'O=C1CCC(=O)N1'),
709
732
  ('salts:sulfonamide', 5, 'Cc1ccc(cc1)S(N)(=O)=O'),
733
+ ('salts:thiol-sh', 5, 'CCS'),
710
734
  )
711
735
 
712
- #: Nothing here is a salt-forming acid, and no row may fire on any of it. Every azole people draw is in
713
- #: the list: only tetrazole sits in the salt-forming range, so every other one is a refusal by design.
736
+ #: Every `metal_protic` row, on the same rung scale and below every acid. A separate ladder because a
737
+ #: separate class: these fire for a free s-block metal and for nothing else in the library.
738
+ METAL_PROTIC_LADDER = (
739
+ ('salts:water-oh', 6, 'O'),
740
+ ('salts:alcohol-oh', 6, 'CCO'),
741
+ )
742
+
743
+ #: Nothing here is a salt-forming acid, and no `protic_acid` row may fire on any of it. Every azole people
744
+ #: draw is in the list: only tetrazole sits in the salt-forming range, so every other one is a refusal by
745
+ #: design. Water and the alcohols are here too -- they are `metal_protic`, which is a different question
746
+ #: and a different class, so a row of this table must not call either an acid.
714
747
  NOT_ACIDS = (
715
748
  'c1cc[nH]c1', 'c1cnc[nH]1', 'c1cn[nH]c1', 'c1cn[nH]n1', 'c1c[nH]nn1', 'c1nc[nH]n1',
716
749
  'c1ccc2[nH]nnc2c1', 'c1ccc2[nH]ccc2c1', 'Cn1c(=O)c2[nH]cnc2n(C)c1=O',
@@ -718,6 +751,14 @@ NOT_ACIDS = (
718
751
  'CCO', 'O', 'CO', 'CC(C)(C)O', 'OC1CCCCC1', 'OCC1OC(O)C(O)C(O)C1O',
719
752
  'CC(C)=O', 'CS(C)=O', 'CC(=O)OC', 'COS(C)(=O)=O', 'C1CCOC1', 'c1ccncc1',
720
753
  'c1ccccc1[N+](=O)[O-]', 'C[N+](C)(C)[O-]', 'Clc1ccccc1', 'CCCl',
754
+ 'CSC', 'CCSSCC', 'CSc1ccccc1', 'CC(=O)SC',
755
+ )
756
+
757
+ #: What a `metal_protic` row must not fire on. Every other O-H the table already places -- a phenol and a
758
+ #: carboxylic acid are acids and rank above these -- plus the ethers, which hold no hydrogen at all.
759
+ NOT_METAL_PROTIC = (
760
+ 'Oc1ccccc1', 'CC(=O)O', 'CS(=O)(=O)O', 'ON=O', 'CCOCC', 'C1CCOC1', 'COC', 'C[Si](C)(C)OC',
761
+ 'CCS', 'CC(=O)OC', 'CC(C)=O', 'NO', 'OO',
721
762
  )
722
763
 
723
764
 
@@ -746,6 +787,33 @@ def test_no_acid_row_fires_on_a_non_acid():
746
787
  assert not fired, (spelling, fired)
747
788
 
748
789
 
790
+ def test_the_metal_protic_ladder_is_the_table():
791
+ rows = salts_rows_by_klass()['metal_protic']
792
+ assert [(row.id, row.order) for row in rows] == [(i, o) for i, o, _ in METAL_PROTIC_LADDER]
793
+ acids = salts_rows_by_klass()['protic_acid']
794
+ assert min(row.order for row in rows) > max(row.order for row in acids), \
795
+ 'a metal_protic rung must sit below every acid: the metal spends itself on the acid first'
796
+
797
+
798
+ def test_every_metal_protic_row_fires_on_its_compound():
799
+ rows = {row.id: row for row in salts_rows_by_klass()['metal_protic']}
800
+ for row_id, _, spelling in METAL_PROTIC_LADDER:
801
+ mol = smiles(spelling)
802
+ mol.standardize()
803
+ mol.thiele()
804
+ assert next(rows[row_id].query.get_mapping(mol), None) is not None, row_id
805
+
806
+
807
+ def test_no_metal_protic_row_fires_on_an_acid_or_an_ether():
808
+ rows = salts_rows_by_klass()['metal_protic']
809
+ for spelling in NOT_METAL_PROTIC:
810
+ mol = smiles(spelling)
811
+ mol.standardize()
812
+ mol.thiele()
813
+ fired = [row.id for row in rows if next(row.query.get_mapping(mol), None) is not None]
814
+ assert not fired, (spelling, fired)
815
+
816
+
749
817
  def test_a_nitrophenol_is_a_phenol_and_not_a_nitric_acid():
750
818
  rows = {row.id: row for row in salts_rows_by_klass()['protic_acid']}
751
819
  mol = smiles('c1cc(O)ccc1[N+](=O)[O-]')
@@ -765,6 +833,12 @@ TAGGINGS = (
765
833
  ('CC(=O)Oc1ccccc1C(=O)O.O', {'hydrate'}),
766
834
  ('CCN.Cl', {'acid_salt'}),
767
835
  ('c1ccncc1.OC(=O)C(F)(F)F', {'acid_salt'}),
836
+ ('CCN.CCS', {'acid_salt'}), # a thiol is an acid site, so this is a salt
837
+ ('CCN.Sc1ccccc1', {'acid_salt'}),
838
+ ('CCN.CCOC(=S)S', {'acid_salt'}), # xanthic acid
839
+ ('CCN.CS(=O)O', {'acid_salt'}), # sulfinic: the sulfonic row is z5, this S is z2
840
+ ('CCN.CCO', {'solvate'}), # and an alcohol is still no acid site
841
+ ('CCS.[Na].CCBr', {'metal_salt', 'acid_salt'}), # the thiol is what the lone sodium owes to
768
842
  ('CC(=O)[O-].[Na+]', {'metal_salt', 'ion_pair'}),
769
843
  ('CC(=O)O[Na]', {'metal_salt', 'ion_pair'}),
770
844
  ('CC(=O)O.[Na+]', {'metal_salt', 'charge_unbalanced'}),
@@ -807,6 +881,37 @@ def test_a_tag_does_not_flip_when_classes_widen():
807
881
  assert 'solvate' in narrow and narrow == wide
808
882
 
809
883
 
884
+ def test_a_solvent_tag_needs_the_component_drawn_neutral():
885
+ """`klass` is read off the neutralized probe and the solvent tags are not.
886
+
887
+ Sodium hydroxide keys as water, because a conjugate is not a row and that is what makes the inventory
888
+ small; it is the counterion all the same, and `hydrate` is a claim about solvent of crystallization.
889
+ The roles are untouched -- both components stay parents and nothing is stripped.
890
+ """
891
+ for spelling in ('[OH-].[Na+]', 'CC[O-].[Na+]', 'CC(C)(C)[O-].[K+]', 'C[O-].[Na+]'):
892
+ answer = smiles(spelling).decompose_salts()
893
+ assert 'hydrate' not in answer.tags and 'solvate' not in answer.tags, spelling
894
+ assert {'metal_salt', 'ion_pair'} <= answer.tags, spelling
895
+ assert len(answer.parents) == 2 and not answer.stabilizers, spelling
896
+ # and the drawn-neutral water is still the hydrate it was
897
+ for spelling in ('CC(=O)Oc1ccccc1C(=O)O.O', 'CCCS([O-])(=O)=O.[Na+].O', 'O.[Na]'):
898
+ assert 'hydrate' in smiles(spelling).decompose_salts().tags, spelling
899
+
900
+
901
+ def test_an_attachment_point_is_a_parent_like_any_other():
902
+ """A supported-synthesis drawing keys and desalts like anything else: the `[R]` is skeleton.
903
+
904
+ `[R]` alone is `single` and no more -- it is neither a lone metal nor a recognized solvent, so the
905
+ parent guard has nothing to promote back.
906
+ """
907
+ answer = smiles('[R]CCN.Cl').decompose_salts()
908
+ assert [format(row.molecule, '!s') for row in answer.parents] == ['C(N)C[R]']
909
+ assert [row.klass for row in answer.stabilizers] == ['mineral_acid']
910
+ assert answer.tags == frozenset({'acid_salt'})
911
+ assert 'hydrate' in smiles('[R]CCN.O').decompose_salts().tags
912
+ assert smiles('[R]').decompose_salts().tags == frozenset({'single'})
913
+
914
+
810
915
  def test_the_three_records_the_default_keeps_whole():
811
916
  api = 'CC(=O)Oc1ccccc1C(=O)O' # aspirin: a carboxylic acid site
812
917
  for record, tag in ((f'{api}.Cc1ccccc1', 'solvate'),
@@ -928,6 +1033,25 @@ def test_canonicalize_does_not_undo_the_repair():
928
1033
  assert mol.canonical_bytes == smiles('CC(=O)[O-].[Na+]').canonical_bytes
929
1034
 
930
1035
 
1036
+ def test_a_free_s_block_metal_beside_water_or_an_alcohol_is_the_alcoholate():
1037
+ """Through `standardize()` and through `canonicalize()`, which reaches this stage by running it: a
1038
+ hydroxide's own hydrogen comes back from `calc_implicit` like any other."""
1039
+ for drawn, after in (('CCO.[Na]', 'CC[O-].[Na+]'),
1040
+ ('O.[Na]', '[OH-].[Na+]'),
1041
+ ('CC(C)(C)O.[K]', 'CC(C)(C)[O-].[K+]'),
1042
+ ('CCS.[Na]', 'CC[S-].[Na+]'),
1043
+ ('C[Si](C)(C)O.[Na]', 'C[Si](C)(C)[O-].[Na+]'),
1044
+ ('CCO.[Zn]', 'CCO.[Zn]')): # not the s block: left as drawn
1045
+ for pipeline in ('standardize', 'canonicalize'):
1046
+ mol = smiles(drawn)
1047
+ getattr(mol, pipeline)()
1048
+ assert mol.canonical_bytes == smiles(after).canonical_bytes, (drawn, pipeline)
1049
+ assert not mol.check_valence(), (drawn, pipeline)
1050
+ mol = smiles('O.[Na]')
1051
+ mol.standardize()
1052
+ assert next(atom for atom in mol.atoms() if atom.element == 8).total_h == 1
1053
+
1054
+
931
1055
  def test_the_log_carries_one_stage_name_for_one_call():
932
1056
  mol = smiles('CC(=O)O.[Na]')
933
1057
  mol.standardize()
@@ -949,6 +1073,14 @@ CHARGE_FIXES = (
949
1073
  ('CS(=O)(=O)O.[Na]', 'CS(=O)(=O)[O-].[Na+]'), # rung 1
950
1074
  ('Cl.[Na]', '[Cl-].[Na+]'), # rung 3
951
1075
  ('Oc1ccccc1.[Na]', '[O-]c1ccccc1.[Na+]'), # rung 5
1076
+ ('CCS.[Na]', 'CC[S-].[Na+]'), # rung 5: a thiol, for any metal at all
1077
+ ('CCO.[Na]', 'CC[O-].[Na+]'), # rung 6: only an s-block metal opens this
1078
+ ('O.[Na]', '[OH-].[Na+]'),
1079
+ ('O.O.[Mg]', '[OH-].[OH-].[Mg+2]'), # two equivalents, two sites
1080
+ ('CC(=O)O.CCO.[Na]', 'CC(=O)[O-].CCO.[Na+]'), # rung 4 beats rung 6: the acid spends it
1081
+ ('CCO.[Sc]', None), # d block: an alcohol is no site for it
1082
+ ('CCO.[Al]', None), # p block: the same
1083
+ ('CCO.[Be]', None), # the s-block metal that reduces neither
952
1084
  ('CC(=O)O.[Mg]', None), # case 4: one equivalent, two wanted
953
1085
  ('CC(=O)O.[Zn]', None), # step 1 refused
954
1086
  ('CCCCCC.[Na+]', None), # case 4: nothing to sit on
@@ -1006,6 +1138,39 @@ def test_the_chosen_site_and_the_moved_charge_are_named_in_the_log():
1006
1138
  assert 'salts:carboxylic-oh' in transfer.message
1007
1139
 
1008
1140
 
1141
+ def test_a_metal_protic_site_is_named_in_the_log_like_any_other():
1142
+ _, _, log = _fixed('CCO.[Na]')
1143
+ transfer = next(record for record in log if record.rule == 'salts:charge-transfer')
1144
+ assert 'salts:alcohol-oh' in transfer.message and 'rung 6' in transfer.message
1145
+
1146
+
1147
+ def test_the_alcohol_is_a_site_for_the_s_block_and_for_no_other_metal():
1148
+ """The ruling: a free group 1 or 2 metal does not stand beside a hydroxyl. Beryllium is the one
1149
+ s-block metal outside it, and the d and p blocks are outside it as blocks."""
1150
+ for symbol in ('Li', 'Na', 'K', 'Cs', 'Mg', 'Ca', 'Ba'):
1151
+ # one alcohol per equivalent: the stage is all-or-nothing, so a group 2 metal needs two
1152
+ charge = smiles('[%s]' % symbol).atom(1).valence_electrons
1153
+ mol, written, log = _fixed('.'.join(['CCO'] * charge + ['[%s]' % symbol]))
1154
+ assert written, symbol
1155
+ assert all(record.severity == REPAIRED for record in log), symbol
1156
+ assert sum(atom.charge for atom in mol.atoms() if atom.charge > 0) == charge, symbol
1157
+ for symbol in ('Be', 'Sc', 'Al', 'Zn', 'Fe', 'Ce'):
1158
+ mol, written, log = _fixed('.'.join(['CCO'] * 4 + ['[%s]' % symbol]))
1159
+ assert not written, symbol
1160
+ assert all(record.severity == REFUSED for record in log), symbol
1161
+
1162
+
1163
+ def test_a_thiol_is_an_acid_for_every_metal_and_not_a_metal_protic_site():
1164
+ """The sulfur rows are `protic_acid`, so they need no s-block gate -- what gates them is the same
1165
+ determinate-valence step every acid goes through."""
1166
+ mol, written, log = _fixed('CCS.CCS.CCS.[Al]')
1167
+ assert mol.canonical_bytes == smiles('CC[S-].CC[S-].CC[S-].[Al+3]').canonical_bytes
1168
+ assert all(record.severity == REPAIRED for record in log)
1169
+ # and the alcohol is not, for the same metal and the same count
1170
+ mol, written, log = _fixed('CCO.CCO.CCO.[Al]')
1171
+ assert not written and all(record.severity == REFUSED for record in log)
1172
+
1173
+
1009
1174
  def test_the_ladder_picks_the_more_acidic_of_two_sites():
1010
1175
  # a phenol and a carboxylic acid on one molecule: rung 4 beats rung 5
1011
1176
  mol, written, log = _fixed('OC(=O)c1ccccc1O.[Na]')
@@ -1076,6 +1241,42 @@ def test_a_refused_case_2_leaves_no_hydrogen_behind():
1076
1241
  assert mol.canonical_bytes == smiles('[Al+].[O-]S(=O)(=O)[O-]').canonical_bytes
1077
1242
 
1078
1243
 
1244
+ #: A free metal drawn with a hydrogen, one record per path that would have written its charge: the four
1245
+ #: acidity rungs an alcohol, water, a carboxylic acid and a benzylic alcohol reach, and the case-2 raise.
1246
+ #: `[H-].[Na+].CCO` is the control -- drawn ionically, the hydride is a component and nothing is at risk.
1247
+ HYDRIDE_RECORDS = ('[NaH]', '[NaH].CCO', '[NaH].O', '[NaH].CC(=O)O', '[NaH].c1ccccc1CO', '[KH].CCO',
1248
+ '[AlH2].CCO', '[MgH+].[O-]S(=O)(=O)[O-]')
1249
+
1250
+
1251
+ @mark.parametrize('spelling', HYDRIDE_RECORDS)
1252
+ def test_an_implicit_hydrogen_on_the_free_metal_refuses_the_transfer(spelling):
1253
+ """Charging a free metal drops nothing it was drawn with.
1254
+
1255
+ `[NaH].CCO` is sodium hydride in ethanol AS DRAWN. Sodium ethoxide and H2 is a reaction, not a
1256
+ repair, and the hydride has nowhere to go, so the record is left alone -- the guard `split_salts()`
1257
+ already applies before cutting a bond, on the path that writes a charge without cutting one.
1258
+ """
1259
+ mol = smiles(spelling)
1260
+ metal = next(atom.n for atom in mol.atoms() if atom.is_metal)
1261
+ brutto, hydrogens = mol.brutto, mol.implicit_h_of(metal)
1262
+ log = mol.log
1263
+ mol.standardize()
1264
+ assert mol.brutto == brutto, spelling
1265
+ assert mol.implicit_h_of(metal) == hydrogens, spelling
1266
+ assert mol.canonical_bytes == smiles(spelling).canonical_bytes, spelling
1267
+ assert 'implicit hydrogen' in log.refused()[0], spelling
1268
+
1269
+
1270
+ def test_the_ionically_drawn_hydride_is_not_the_guard_s_business():
1271
+ """`[H-]` is a component and not a count on the metal, so the record standardizes as any other."""
1272
+ mol = smiles('[H-].[Na+].CCO')
1273
+ brutto = mol.brutto
1274
+ mol.standardize()
1275
+ assert mol.brutto == brutto
1276
+ assert mol.canonical_bytes == smiles('[H-].[Na+].CCO').canonical_bytes
1277
+ assert not mol.log.refused()
1278
+
1279
+
1079
1280
  def test_case_2_requires_drawn_anions():
1080
1281
  mol, written, log = _fixed('[Na-]')
1081
1282
  assert mol.canonical_bytes == smiles('[Na-]').canonical_bytes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chython
3
- Version: 3.3
3
+ Version: 3.3.1
4
4
  Summary: Library for processing molecules and reactions in python way
5
5
  Author-email: Ramil Nugmanov <nougmanoff@protonmail.com>
6
6
  License-Expression: LGPL-3.0-or-later
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'chython'
7
- version = '3.3'
7
+ version = '3.3.1'
8
8
  description = 'Library for processing molecules and reactions in python way'
9
9
  authors = [{name = 'Ramil Nugmanov', email = 'nougmanoff@protonmail.com'}]
10
10
  license = 'LGPL-3.0-or-later'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes