From 4ced2b03f8fb2381c1f6ae650960b1044577e133 Mon Sep 17 00:00:00 2001 From: Jackson Burns Date: Sat, 16 Sep 2023 20:10:19 -0400 Subject: [PATCH] build an rmgmolecule package in place, fix conda builds - small updates to rmg-py recipe - removed conda_build.yml action since it will now be done in a private repo - added a recipe for rmgmolecule - add warnings on molecule when running from rmgmolecule that some functionality is not available --- .conda/meta.yaml | 8 +- .github/workflows/conda_build.yml | 58 ------- .rmgmolecule_conda/build.sh | 2 + .rmgmolecule_conda/conda_build_config.yaml | 2 + .rmgmolecule_conda/meta.yaml | 53 +++++++ rmgmolecule_setup.py | 176 +++++++++++++++++++++ rmgpy/molecule/draw.py | 13 +- rmgpy/molecule/fragment.py | 8 +- rmgpy/molecule/inchi.py | 8 +- 9 files changed, 262 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/conda_build.yml create mode 100644 .rmgmolecule_conda/build.sh create mode 100644 .rmgmolecule_conda/conda_build_config.yaml create mode 100644 .rmgmolecule_conda/meta.yaml create mode 100644 rmgmolecule_setup.py diff --git a/.conda/meta.yaml b/.conda/meta.yaml index b1df7678e67..9e74a621fc1 100644 --- a/.conda/meta.yaml +++ b/.conda/meta.yaml @@ -11,7 +11,7 @@ build: requirements: build: - - {{ compiler('c') }} # [unix] + - {{ compiler('c') }} host: - cython >=0.25.2 - lpsolve55 @@ -78,10 +78,8 @@ test: - rmgpy - arkane commands: - - rmg.py examples/rmg/superminimal/input.py # [unix] - - Arkane.py examples/arkane/networks/n-butanol/input.py # [unix] - - python %SCRIPTS%\rmg.py examples\rmg\superminimal\input.py # [win] - - python %SCRIPTS\Arkane.py examples\arkane\networks\n-butanol\input.py # [win] + - python-jl rmg.py examples/rmg/superminimal/input.py + - python arkane.py examples/arkane/networks/n-butanol about: home: https://github.com/ReactionMechanismGenerator/RMG-Py diff --git a/.github/workflows/conda_build.yml b/.github/workflows/conda_build.yml deleted file mode 100644 index 8ddbef08771..00000000000 --- a/.github/workflows/conda_build.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Conda Build - -on: - push: - branches: - - stable -jobs: - build-linux: - runs-on: ubuntu-latest - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - environment-file: environment.yml - python-version: 3.7 - activate-environment: rmg_env - - name: Conda info - run: | - conda info - conda list - - name: Build Binary - env: - CONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} - run: | - conda install -y conda-build - conda install -y anaconda-client - conda config --add channels rmg - conda config --set anaconda_upload yes - conda build --token $CONDA_TOKEN --user rmg .conda - build-osx: - runs-on: macos-latest - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - environment-file: environment.yml - python-version: 3.7 - activate-environment: rmg_env - - name: Conda info - run: | - conda info - conda list - - name: Build Binary - env: - CONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} - run: | - conda install -y conda-build - conda install -y anaconda-client - conda config --add channels rmg - conda config --set anaconda_upload yes - xcrun --show-sdk-path - conda build --token $CONDA_TOKEN --user rmg .conda diff --git a/.rmgmolecule_conda/build.sh b/.rmgmolecule_conda/build.sh new file mode 100644 index 00000000000..b68ece39068 --- /dev/null +++ b/.rmgmolecule_conda/build.sh @@ -0,0 +1,2 @@ +# Install rmgmolecule +python rmgmolecule_setup.py install diff --git a/.rmgmolecule_conda/conda_build_config.yaml b/.rmgmolecule_conda/conda_build_config.yaml new file mode 100644 index 00000000000..83e1bc711e2 --- /dev/null +++ b/.rmgmolecule_conda/conda_build_config.yaml @@ -0,0 +1,2 @@ +numpy: + - 1.19 \ No newline at end of file diff --git a/.rmgmolecule_conda/meta.yaml b/.rmgmolecule_conda/meta.yaml new file mode 100644 index 00000000000..62cb422d878 --- /dev/null +++ b/.rmgmolecule_conda/meta.yaml @@ -0,0 +1,53 @@ +# meta.yaml - package specification for rmgmolecule subpackage +package: + name: rmgmolecule + version: 1.0.0 + +source: + path: ../ + +build: + number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} + +requirements: + build: + - {{ compiler('c') }} # [unix] + host: + - cython >=0.25.2 + - lpsolve55 + - numpy + - openbabel >=3 + - pyrdl + - python==3.7 + - quantities + - rdkit >=2018 + - scipy + - scikit-learn + - setuptools + run: + - cairo + - cairocffi + - cython >=0.25.2 + - gprof2dot + - graphviz + - jinja2 + - jupyter + - lpsolve55 + - {{ pin_compatible('numpy') }} + - openbabel >=3 + - pydot + - pyrdl + - python==3.7 + - quantities + - rdkit >=2018 + - scikit-learn +test: + imports: + - rmgpy.molecule + commands: + - python -c 'from rmgpy.molecule import Molecule; mol=Molecule().from_smiles("CC")' + +about: + home: https://github.com/ReactionMechanismGenerator/RMG-Py + license: MIT + summary: "The ReactionMechanismGenerator Molecule Subpackage" \ No newline at end of file diff --git a/rmgmolecule_setup.py b/rmgmolecule_setup.py new file mode 100644 index 00000000000..8614e22edeb --- /dev/null +++ b/rmgmolecule_setup.py @@ -0,0 +1,176 @@ +import sys +import os +from collections import OrderedDict + +try: + from distutils.core import setup + from distutils.extension import Extension +except ImportError: + print("The distutils package is required to build or install RMG Py.") + raise + +try: + from Cython.Build import cythonize + from Cython.Compiler import Options +except ImportError: + print("Cython (http://www.cython.org/) is required to build or install RMG Py.") + raise + +try: + import numpy +except ImportError: + print("NumPy (http://numpy.scipy.org/) is required to build or install RMG Py.") + raise + +# Create annotated HTML files for each of the Cython modules +Options.annotate = True + +directives = { + # Set input language version to python 3 + "language_level": 3, + # Turn on profiling capacity for all Cython modules + # 'profile': True, + # Embed call signatures in cythonized files - enable when building documentation + # 'embedsignature': True, +} + + +main_ext_modules = [ + # Molecules and molecular representations + Extension( + "rmgpy.molecule.atomtype", + ["rmgpy/molecule/atomtype.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.element", + ["rmgpy/molecule/element.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.graph", + ["rmgpy/molecule/graph.pyx"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.group", + ["rmgpy/molecule/group.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.molecule", + ["rmgpy/molecule/molecule.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.symmetry", + ["rmgpy/molecule/symmetry.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.vf2", + ["rmgpy/molecule/vf2.pyx"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.converter", + ["rmgpy/molecule/converter.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.translator", + ["rmgpy/molecule/translator.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.util", + ["rmgpy/molecule/util.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.inchi", + ["rmgpy/molecule/inchi.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.resonance", + ["rmgpy/molecule/resonance.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.pathfinder", + ["rmgpy/molecule/pathfinder.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.molecule.kekulize", + ["rmgpy/molecule/kekulize.pyx"], + include_dirs=["."], + ), + Extension( + "rmgpy.constants", + ["rmgpy/constants.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.quantity", + ["rmgpy/quantity.py"], + include_dirs=["."], + ), + Extension( + "rmgpy.rmgobject", + ["rmgpy/rmgobject.pyx"], + ), +] + +ext_modules = [] +if "install" in sys.argv: + # This is so users can still do simply `python setup.py install` + ext_modules.extend(main_ext_modules) +if "main" in sys.argv: + # This is for `python setup.py build_ext main` + sys.argv.remove("main") + ext_modules.extend(main_ext_modules) +if "minimal" in sys.argv: + # This starts with the full install list, but removes anything that has a pure python mode + # i.e. in only includes things whose source is .pyx + sys.argv.remove("minimal") + temporary_list = [] + temporary_list.extend(main_ext_modules) + for module in temporary_list: + for source in module.sources: + if os.path.splitext(source)[1] == ".pyx": + ext_modules.append(module) + +# Remove duplicates while preserving order: +ext_modules = list(OrderedDict.fromkeys(ext_modules)) + +scripts = [] + +modules = ["rmgpy.exceptions", "rmgpy.version"] + +__version__ = "1.0.0" + +import logging + +logging.error(ext_modules) +# Initiate the build and/or installation +setup( + name="RMG-Py", + version=__version__, + description="Reaction Mechanism Generator", + author="William H. Green and the RMG Team", + author_email="rmg_dev@mit.edu", + url="http://reactionmechanismgenerator.github.io", + packages=[ + "rmgpy.molecule", + ], + py_modules=modules, + scripts=scripts, + ext_modules=cythonize( + ext_modules, + build_dir="build", + compiler_directives=directives, + ), + include_dirs=[".", numpy.get_include()], +) diff --git a/rmgpy/molecule/draw.py b/rmgpy/molecule/draw.py index 6dd6c8b46b1..73098bfb35d 100644 --- a/rmgpy/molecule/draw.py +++ b/rmgpy/molecule/draw.py @@ -49,6 +49,7 @@ import math import os.path import re +import warnings try: import cairocffi as cairo @@ -61,7 +62,12 @@ from rdkit.Chem import AllChem from rmgpy.molecule.molecule import Atom, Molecule -from rmgpy.qm.molecule import Geometry + +Geometry = None +try: + from rmgpy.qm.molecule import Geometry +except ImportError: + logging.info("Unable to import Geometry rmgpy.qm.molecule - feature disabled.") ################################################################################ @@ -437,6 +443,11 @@ def _generate_coordinates(self): # Generate the RDkit molecule from the RDkit molecule, use geometry # in order to match the atoms in the rdmol with the atoms in the # RMG molecule (which is required to extract coordinates). + if Geometry is None: + raise RuntimeError(""" +Missing rmgpy.qm.molecule.Geometry required for 2D coordinate generation. +Please install the full version of RMG to use this function. + """) self.geometry = Geometry(None, None, self.molecule, None) rdmol, rd_atom_idx = self.geometry.rd_build() diff --git a/rmgpy/molecule/fragment.py b/rmgpy/molecule/fragment.py index 8b30c1e32ed..06e25f73464 100644 --- a/rmgpy/molecule/fragment.py +++ b/rmgpy/molecule/fragment.py @@ -1020,7 +1020,13 @@ def assign_representative_molecule(self): def assign_representative_species(self): - from rmgpy.species import Species + try: + from rmgpy.species import Species + except ImportError as ie: + raise RuntimeError( + "Cannot call Fragment.assign_representative_species() in rmgmolecule installation." + " Please install the full version of RMG." + ) from ie self.assign_representative_molecule() self.species_repr = Species(molecule=[self.mol_repr]) self.symmetry_number = self.get_symmetry_number() diff --git a/rmgpy/molecule/inchi.py b/rmgpy/molecule/inchi.py index e376fdd1850..f0e1d4c82c5 100644 --- a/rmgpy/molecule/inchi.py +++ b/rmgpy/molecule/inchi.py @@ -702,7 +702,13 @@ def _convert_3_atom_2_bond_path(start, mol): with a number of actions that reflect the changes in bond orders and unpaired electrons that the molecule should undergo. """ - from rmgpy.data.kinetics.family import ReactionRecipe + try: + from rmgpy.data.kinetics.family import ReactionRecipe + except ImportError as ie: + raise RuntimeError( + "Cannot call inchi._convert_3_atom_2_bond_path() in rmgmolecule installation." + " Please install the full version of RMG." + ) from ie def is_valid(mol): """Check if total bond order of oxygen atoms is smaller than 4."""