diff --git a/.github/workflows/Sandpit_exs.yml b/.github/workflows/Sandpit_exs.yml index 6d548978f..00e9199fc 100644 --- a/.github/workflows/Sandpit_exs.yml +++ b/.github/workflows/Sandpit_exs.yml @@ -41,9 +41,7 @@ jobs: - name: Install the dev version run: | conda remove --force biosimspace - cd python - python setup.py develop - cd .. + pip install -e . - name: Run tests run: | diff --git a/.github/workflows/devel.yaml b/.github/workflows/devel.yaml index 827c5dbcf..3c1d60859 100644 --- a/.github/workflows/devel.yaml +++ b/.github/workflows/devel.yaml @@ -3,7 +3,7 @@ name: Release Devel on: workflow_dispatch: push: - branches: [ devel ] + branches: [devel] jobs: build: @@ -15,18 +15,16 @@ jobs: matrix: python-version: ["3.10", "3.11", "3.12"] platform: - - { name: "windows", os: "windows-latest", shell: "pwsh" } + - { name: "windows", os: "windows-latest", shell: "bash -l {0}" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } - { name: "macos", os: "macos-latest", shell: "bash -l {0}" } exclude: - # Exclude all but the latest Python from all - # but Linux - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.12" # MacOS can't run 3.12 yet... We want 3.10 and 3.11 - - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } + python-version: "3.12" # MacOS can't run 3.12 yet... We want 3.10 and 3.11 + - platform: { name: "windows", os: "windows-latest", shell: "bash -l {0}" } python-version: "3.10" - - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } + - platform: { name: "windows", os: "windows-latest", shell: "bash -l {0}" } python-version: "3.11" environment: name: biosimspace-build @@ -37,30 +35,44 @@ jobs: SIRE_DONT_PHONEHOME: 1 SIRE_SILENT_PHONEHOME: 1 steps: - - uses: conda-incubator/setup-miniconda@v3 + # + - uses: actions/checkout@v4 with: - auto-update-conda: true - python-version: ${{ matrix.python-version }} - activate-environment: bss_build - miniforge-version: latest -# - - name: Clone the devel branch - run: git clone -b devel https://github.com/openbiosim/biosimspace -# - - name: Setup Conda - run: conda install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser -# - - name: Update Conda recipe - run: python ${{ github.workspace }}/biosimspace/actions/update_recipe.py -# - - name: Prepare build location - run: mkdir ${{ github.workspace }}/build -# - - name: Build Conda package using conda build - run: conda build -c conda-forge -c openbiosim/label/dev ${{ github.workspace }}/biosimspace/recipes/biosimspace -# - - name: Upload Conda package - run: python ${{ github.workspace }}/biosimspace/actions/upload_package.py + fetch-depth: 0 + # + - name: Compute version info + shell: bash + run: python actions/update_recipe.py + # + - name: Create sdist + shell: bash + run: pip install build && python -m build --sdist && mv dist/*.tar.gz biosimspace-source.tar.gz + working-directory: ${{ github.workspace }} + # + - name: Install pixi + uses: prefix-dev/setup-pixi@v0.9.4 + with: + run-install: false + # + - name: Install rattler-build + shell: bash + run: pixi global install rattler-build + # + - name: Write Python variant config + shell: bash + run: printf 'python:\n - "${{ matrix.python-version }}"\n' > "${{ github.workspace }}/python_variant.yaml" + # + - name: Build package using rattler-build + shell: bash + run: rattler-build build --recipe "${{ github.workspace }}/recipes/biosimspace" -c conda-forge -c openbiosim/label/dev --variant-config "${{ github.workspace }}/python_variant.yaml" + # + - name: Install anaconda-client + shell: bash + run: python -m pip install anaconda-client + # + - name: Upload package + shell: bash + run: python actions/upload_package.py env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} ANACONDA_LABEL: dev diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a9d31edf0..ba3478ed2 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -18,13 +18,13 @@ jobs: matrix: python-version: ["3.10", "3.11", "3.12"] platform: - - { name: "windows", os: "windows-latest", shell: "pwsh" } + - { name: "windows", os: "windows-latest", shell: "bash -l {0}" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } - { name: "macos", os: "macos-latest", shell: "bash -l {0}" } exclude: - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.12" # MacOS can't run 3.12 yet... + python-version: "3.12" # MacOS can't run 3.12 yet... environment: name: biosimspace-build defaults: @@ -34,30 +34,46 @@ jobs: SIRE_DONT_PHONEHOME: 1 SIRE_SILENT_PHONEHOME: 1 steps: - - uses: conda-incubator/setup-miniconda@v3 + # + - uses: actions/checkout@v4 with: - auto-update-conda: true - python-version: ${{ matrix.python-version }} - activate-environment: bss_build - miniforge-version: latest -# - - name: Clone the main branch - run: git clone -b main https://github.com/openbiosim/biosimspace -# - - name: Setup Conda - run: conda install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser -# - - name: Update Conda recipe - run: python ${{ github.workspace }}/biosimspace/actions/update_recipe.py -# - - name: Prepare build location - run: mkdir ${{ github.workspace }}/build -# - - name: Build Conda package using conda build - run: conda build -c conda-forge -c openbiosim/label/main ${{ github.workspace }}/biosimspace/recipes/biosimspace -# - - name: Upload Conda package - run: python ${{ github.workspace }}/biosimspace/actions/upload_package.py + ref: main + fetch-depth: 0 + # + - name: Compute version info + shell: bash + run: python actions/update_recipe.py + # + - name: Create sdist + shell: bash + run: pip install build && python -m build --sdist && mv dist/*.tar.gz biosimspace-source.tar.gz + working-directory: ${{ github.workspace }} + # + - name: Install pixi + uses: prefix-dev/setup-pixi@v0.9.4 + with: + run-install: false + # + - name: Install rattler-build + shell: bash + run: pixi global install rattler-build + # + - name: Write Python variant config + shell: bash + run: printf 'python:\n - "${{ matrix.python-version }}"\n' > "${{ github.workspace }}/python_variant.yaml" + # + - name: Build package using rattler-build + shell: bash + run: rattler-build build --recipe "${{ github.workspace }}/recipes/biosimspace" -c conda-forge -c openbiosim/label/main --variant-config "${{ github.workspace }}/python_variant.yaml" + # + - name: Install anaconda-client + shell: bash + run: python -m pip install anaconda-client + if: github.event.inputs.upload_packages == 'true' + # + - name: Upload package + shell: bash + run: python actions/upload_package.py env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} ANACONDA_LABEL: main diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index adf13e94c..8aa08fe8b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -14,21 +14,19 @@ jobs: matrix: python-version: ["3.10", "3.11", "3.12"] platform: - - { name: "windows", os: "windows-latest", shell: "pwsh" } + - { name: "windows", os: "windows-latest", shell: "bash -l {0}" } - { name: "linux", os: "ubuntu-latest", shell: "bash -l {0}" } - { name: "macos", os: "macos-latest", shell: "bash -l {0}" } exclude: - # Exclude all but the latest Python from all - # but Linux - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } python-version: "3.10" - - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } + - platform: { name: "windows", os: "windows-latest", shell: "bash -l {0}" } python-version: "3.10" - platform: { name: "macos", os: "macos-latest", shell: "bash -l {0}" } - python-version: "3.12" # MacOS can't run 3.12 yet... - - platform: { name: "windows", os: "windows-latest", shell: "pwsh" } + python-version: "3.12" # MacOS can't run 3.12 yet... + - platform: { name: "windows", os: "windows-latest", shell: "bash -l {0}" } python-version: "3.11" environment: name: biosimspace-build @@ -38,31 +36,40 @@ jobs: env: SIRE_DONT_PHONEHOME: 1 SIRE_SILENT_PHONEHOME: 1 - REPO: "${{ github.event.pull_request.head.repo.full_name || github.repository }}" steps: - - uses: conda-incubator/setup-miniconda@v3 + # + - uses: actions/checkout@v4 with: - auto-update-conda: true - python-version: ${{ matrix.python-version }} - activate-environment: bss_build - miniforge-version: latest -# - - name: Clone the feature branch - run: git clone -b ${{ github.head_ref }} --single-branch https://github.com/${{ env.REPO }} biosimspace -# - - name: Setup Conda - run: conda install -y -c conda-forge boa anaconda-client packaging pip-requirements-parser -# - - name: Update Conda recipe - run: python ${{ github.workspace }}/biosimspace/actions/update_recipe.py -# - - name: Prepare build location - run: mkdir ${{ github.workspace }}/build -# - - name: Build Conda package using conda build using main channel + fetch-depth: 0 + # + - name: Compute version info + shell: bash + run: python actions/update_recipe.py + # + - name: Create sdist + shell: bash + run: pip install build && python -m build --sdist && mv dist/*.tar.gz biosimspace-source.tar.gz + working-directory: ${{ github.workspace }} + # + - name: Install pixi + uses: prefix-dev/setup-pixi@v0.9.4 + with: + run-install: false + # + - name: Install rattler-build + shell: bash + run: pixi global install rattler-build + # + - name: Write Python variant config + shell: bash + run: printf 'python:\n - "${{ matrix.python-version }}"\n' > "${{ github.workspace }}/python_variant.yaml" + # + - name: Build package using rattler-build (main channel) if: ${{ github.base_ref == 'main' }} - run: conda build -c conda-forge -c openbiosim/label/main ${{ github.workspace }}/biosimspace/recipes/biosimspace -# - - name: Build Conda package using conda build using dev channel + shell: bash + run: rattler-build build --recipe "${{ github.workspace }}/recipes/biosimspace" -c conda-forge -c openbiosim/label/main --variant-config "${{ github.workspace }}/python_variant.yaml" + # + - name: Build package using rattler-build (dev channel) if: ${{ github.base_ref != 'main' }} - run: conda build -c conda-forge -c openbiosim/label/dev ${{ github.workspace }}/biosimspace/recipes/biosimspace + shell: bash + run: rattler-build build --recipe "${{ github.workspace }}/recipes/biosimspace" -c conda-forge -c openbiosim/label/dev --variant-config "${{ github.workspace }}/python_variant.yaml" diff --git a/.gitignore b/.gitignore index cbe9482a2..b5029bd19 100644 --- a/.gitignore +++ b/.gitignore @@ -34,5 +34,5 @@ output.yaml # VSCode config .vscode/ -# Conda recipe (it is auto-generated) -recipes/biosimspace/meta.yaml +# Auto-generate version file. +src/BioSimSpace/_version.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..0043ca491 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +files: ^(src|tests)/ +exclude: ^tests/(input|output)/ + +repos: + # General file quality checks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-added-large-files + args: [--maxkb=1000] # Prevent files larger than 1MB + - id: check-merge-conflict + + # Python formatting and linting + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.4 + hooks: + # Run the formatter + - id: ruff-format + # Run the linter (optional - remove if too strict) + - id: ruff + args: [--fix, --exit-zero] # Auto-fix but don't block commits diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..96737d303 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +graft tests diff --git a/README.rst b/README.rst index 2ded561a6..57905c6f5 100644 --- a/README.rst +++ b/README.rst @@ -93,67 +93,68 @@ need to add them when updating, e.g., for the development package: conda update -c conda-forge -c openbiosim/label/dev biosimspace -Installing from source -^^^^^^^^^^^^^^^^^^^^^^ +Installing from source (standalone) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Alternatively, to install BioSimSpace from source: - -(Before starting, you'll need a working `Git `__ installation.) - -BioSimSpace is built on top of the `Sire `__ -molecular simulation framework. To download and install Sire, follow the -instructions `here `__, making -sure that BioSimSpace's dependencies are installed into the Sire conda -environment at the point at which Sire is installed. - -Next you will need to download BioSimSpace and install it into your Sire -Conda environment. +To install from source using `pixi `__, which will +automatically create an environment with all required dependencies +(including pre-built `Sire `__): .. code-block:: bash git clone https://github.com/openbiosim/biosimspace - cd biosimspace/python - pip install . - -If you plan to develop and want an editable install, use: - -.. code-block:: bash - + cd biosimspace + pixi install + pixi shell pip install -e . -If you want to skip the installation of BioSimSpace dependencies, e.g. if they -are already installed, then you can use: +Installing from source (full OpenBioSim development) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you are developing across the full OpenBioSim stack, first install +`Sire `__ from source by following the +instructions `here `__, then +activate its pixi environment: .. code-block:: bash - BSS_SKIP_DEPENDENCIES=1 pip install -e . + pixi shell --manifest-path /path/to/sire/pixi.toml -e dev -Once finished, you can test the installation by running: +Next, clone and install BioSimSpace: .. code-block:: bash - python + git clone https://github.com/openbiosim/biosimspace + cd biosimspace + pip install -e . -Then try importing the BioSimSpace package: +You may also want to install optional dependencies, such as ``ambertools`` and +``gromacs`` into the environment. + +Once finished, you can test the installation by running: .. code-block:: python import BioSimSpace as BSS -If you don't want to install Sire from source, an alternative is to create a conda -environment containing only the dependencies of BioSimSpace, then install the -latest development code into that. +Development +----------- + +Pre-commit hooks are used to ensure consistent code formatting and linting. +To set up pre-commit in your development environment: .. code-block:: bash - conda create -n openbiosim-dev -c conda-forge -c openbiosim/label/dev biosimspace --only-deps - conda activate openbiosim-dev - git clone https://github.com/openbiosim/biosimspace - cd biosimspace/python - BSS_SKIP_DEPENDENCIES=1 pip install -e . + pixi shell -e dev + pre-commit install + +This will run `ruff `__ formatting and linting +checks automatically on each commit. To run the checks manually against all +files: + +.. code-block:: bash -(You may also want to install optional dependencies, such as ``ambertools`` and -``gromacs`` into your environment.) + pre-commit run --all-files Developers ---------- diff --git a/actions/collect_failed.py b/actions/collect_failed.py index 82226bb7e..5fc5492bf 100644 --- a/actions/collect_failed.py +++ b/actions/collect_failed.py @@ -1,9 +1,9 @@ # Script that collects as much as it can from a failed conda build so that it can # be stored as a GitHub Actions artifact for download and further debugging +import glob import os import sys -import glob import tarfile if "BUILD_DIR" not in os.environ: diff --git a/actions/parse_requirements.py b/actions/parse_requirements.py deleted file mode 100644 index 96b990873..000000000 --- a/actions/parse_requirements.py +++ /dev/null @@ -1,45 +0,0 @@ -def parse_requirements(filename): - """Parse the requirements and return (in conda notation) - the requirements for this system. - """ - try: - from pip_requirements_parser import RequirementsFile - except ImportError as e: - print("\n\n[ERROR] ** You need to install pip-requirements-parser") - print("Run `conda install pip-requirements-parser\n\n") - raise e - - from pkg_resources import evaluate_marker - - reqs = RequirementsFile.from_file(filename).to_dict()["requirements"] - - deps = {} - - for req in reqs: - name = req["name"] - specifier = req["specifier"] - marker = req["marker"] - - if len(specifier) == 0: - specifier = "" - else: - specifier = specifier[0] - - if marker is not None: - # check to see if this line fits this platform - include = evaluate_marker(marker) - else: - include = True - - if include: - deps[name] = specifier - - reqs = list(deps.keys()) - reqs.sort() - - result = [] - - for req in reqs: - result.append(f"{req}{deps[req]}") - - return result diff --git a/actions/update_recipe.py b/actions/update_recipe.py index 52dae3d6b..4f908367f 100644 --- a/actions/update_recipe.py +++ b/actions/update_recipe.py @@ -1,85 +1,58 @@ -import sys -import os -import subprocess +"""Compute git version info for rattler-build. -script = os.path.abspath(sys.argv[0]) +This script computes GIT_DESCRIBE_TAG and GIT_DESCRIBE_NUMBER from the +git history and outputs them in GitHub Actions format for setting +environment variables. -# we want to import the 'get_requirements' package from this directory -sys.path.insert(0, os.path.dirname(script)) +It also writes a _version.py file so that versioneer has a fallback +when .git is not available (e.g., in the tarball used by rattler-build). +""" -from parse_requirements import parse_requirements +import os +import subprocess +import sys -# go up one directories to get the source directory -# (this script is in BioSimSpace/actions/) +script = os.path.abspath(sys.argv[0]) srcdir = os.path.dirname(os.path.dirname(script)) - -condadir = os.path.join(srcdir, "recipes", "biosimspace") - -print(f"conda recipe in {condadir}") - -# Store the name of the recipe and template YAML files. -recipe = os.path.join(condadir, "meta.yaml") - -# If the BSS_TEMPLATE environment variable is set, use that as the template. -if "BSS_TEMPLATE" in os.environ: - template = os.environ["BSS_TEMPLATE"] -else: - template = os.path.join(condadir, "template.yaml") - -# Now parse all of the requirements -run_reqs = parse_requirements(os.path.join(srcdir, "requirements.txt")) -print(run_reqs) -build_reqs = parse_requirements(os.path.join(srcdir, "requirements_build.txt")) -print(build_reqs) - - -def run_cmd(cmd): - p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) - return str(p.stdout.read().decode("utf-8")).lstrip().rstrip() - - gitdir = os.path.join(srcdir, ".git") -# Get the BSS remote. -remote = run_cmd( - f"git --git-dir={gitdir} --work-tree={srcdir} config --get remote.origin.url" -) -remote += ".git" -print(remote) - -# Get the BSS branch. -branch = run_cmd( - f"git --git-dir={gitdir} --work-tree={srcdir} rev-parse --abbrev-ref HEAD" -) -print(branch) - -lines = open(template, "r").readlines() - -def dep_lines(deps): - lines = [] - - for dep in deps: - lines.append(f" - {dep}\n") - - return "".join(lines) +def run_cmd(cmd): + p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, _ = p.communicate() + return stdout.decode("utf-8").strip() -run_reqs = dep_lines(run_reqs) +# Get the full git describe output (e.g., "2024.1.0-5-gabcdef" or "2024.1.0") +describe = run_cmd(f"git --git-dir={gitdir} --work-tree={srcdir} describe --tags") -if len(build_reqs) > 0: - build_reqs = f" build:\n{dep_lines(build_reqs)}" +if "-" in describe: + # Format: tag-number-hash (e.g., "2024.1.0-5-gabcdef") + parts = describe.rsplit("-", 2) + tag = parts[0] + number = parts[1] + rev = parts[2] # e.g., "gabcdef" + version = f"{tag}+{number}.{rev}" else: - build_reqs = "" - -with open(recipe, "w") as FILE: - for line in lines: - if line.find("BSS_BUILD_REQUIREMENTS") != -1: - line = build_reqs - elif line.find("BSS_RUN_REQUIREMENTS") != -1: - line = run_reqs - else: - line = line.replace("BSS_REMOTE", remote) - line = line.replace("BSS_BRANCH", branch) - - FILE.write(line) + # Exactly on a tag + tag = describe + number = "0" + version = tag + +print(f"GIT_DESCRIBE_TAG={tag}") +print(f"GIT_DESCRIBE_NUMBER={number}") +print(f"Version={version}") + +# Write to GITHUB_ENV if running in GitHub Actions +github_env = os.environ.get("GITHUB_ENV") +if github_env: + with open(github_env, "a") as f: + f.write(f"GIT_DESCRIBE_TAG={tag}\n") + f.write(f"GIT_DESCRIBE_NUMBER={number}\n") + print("Exported to GITHUB_ENV") + +# Write _version.py for versioningit fallback (when .git is not available) +version_file = os.path.join(srcdir, "src", "BioSimSpace", "_version.py") +with open(version_file, "w") as f: + f.write(f'__version__ = "{version}"\n') +print(f"Wrote {version_file}") diff --git a/actions/upload_package.py b/actions/upload_package.py index 6baf7249c..b252fe363 100644 --- a/actions/upload_package.py +++ b/actions/upload_package.py @@ -1,16 +1,18 @@ +"""Upload built packages to the openbiosim Anaconda Cloud channel.""" + +import glob import os +import subprocess import sys -import glob script = os.path.abspath(sys.argv[0]) -# go up one directories to get the source directory -# (this script is in Sire/actions/) +# Go up one directory to get the source directory. srcdir = os.path.dirname(os.path.dirname(script)) print(f"BioSimSpace source is in {srcdir}\n") -# Get the anaconda token to authorise uploads +# Get the anaconda token to authorise uploads. if "ANACONDA_TOKEN" in os.environ: conda_token = os.environ["ANACONDA_TOKEN"] else: @@ -22,54 +24,43 @@ else: conda_label = "dev" -# get the root conda directory -conda = os.environ["CONDA"] +# Search for rattler-build output first. +packages = glob.glob(os.path.join("output", "**", "*.conda"), recursive=True) -# Set the path to the conda-bld directory. -conda_bld = os.path.join(conda, "envs", "bss_build", "conda-bld") +# Fall back to conda-bld output. +if not packages: + if "CONDA" in os.environ: + conda = os.environ["CONDA"] + conda_bld = os.path.join(conda, "envs", "bss_build", "conda-bld") + packages = glob.glob( + os.path.join(conda_bld, "**", "biosimspace-*.tar.bz2"), recursive=True + ) -print(f"conda_bld = {conda_bld}") - -# Find the packages to upload -bss_pkg = glob.glob(os.path.join(conda_bld, "*-*", "biosimspace-*.tar.bz2")) - -if len(bss_pkg) == 0: +if not packages: print("No BioSimSpace packages to upload?") sys.exit(-1) -packages = bss_pkg - -print(f"Uploading packages:") -print(" * ", "\n * ".join(packages)) +print("Uploading packages:") +for pkg in packages: + print(f" * {pkg}") -packages = " ".join(packages) - - -def run_cmd(cmd): - import subprocess - - p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) - return str(p.stdout.read().decode("utf-8")).lstrip().rstrip() - - -gitdir = os.path.join(srcdir, ".git") - -tag = run_cmd(f"git --git-dir={gitdir} --work-tree={srcdir} tag --contains") +packages_str = " ".join(packages) # Upload the packages to the openbiosim channel on Anaconda Cloud. -cmd = f"anaconda --token {conda_token} upload --user openbiosim --label {conda_label} --force {packages}" +cmd = f"anaconda --token {conda_token} upload --user openbiosim --label {conda_label} --force {packages_str}" print(f"\nUpload command:\n\n{cmd}\n") -# Label release packages with main and dev so that dev is at least as new as -# main. Only need to uncomment the libcpuid and fkcombu package uploads when -# there new versions are released. if conda_token == "TEST": print("Not uploading as the ANACONDA_TOKEN is not set!") sys.exit(-1) -output = run_cmd(cmd) -print(output) +def run_cmd(cmd): + p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) + return str(p.stdout.read().decode("utf-8")).lstrip().rstrip() + +output = run_cmd(cmd) +print(output) print("Package uploaded!") diff --git a/doc/source/contributing/codestyle.rst b/doc/source/contributing/codestyle.rst index 2cda443be..395437844 100644 --- a/doc/source/contributing/codestyle.rst +++ b/doc/source/contributing/codestyle.rst @@ -53,10 +53,10 @@ and now has a fully `PEP8-compliant `__ API. We indent to move BioSimSpace towards using Python compliant API too, while preserving backwards compatibility.) -We use `black `__ to autoformat our -Python code. Please use this if you plan on submitting code. They are easy to -configure and use via your IDE (or from the command-line) and help ensure a -consistent code style and minimise diffs during pull requests. +We use `ruff `__ to format and lint our Python +code. This is run automatically via `pre-commit `__ +hooks when you commit changes. See the :doc:`development` guide for setup +instructions. Modules ------- diff --git a/doc/source/contributing/development.rst b/doc/source/contributing/development.rst index fa5cab327..b987d86cf 100644 --- a/doc/source/contributing/development.rst +++ b/doc/source/contributing/development.rst @@ -185,18 +185,31 @@ Now create and switch to a feature branch. This should be prefixed with git checkout -b feature-process While working on your feature branch you won't want to continually re-install -in order to make the changes active. To avoid this, you can either make use -of ``PYTHONPATH``, e.g. +in order to make the changes active. To avoid this, install the package in +editable mode: .. code-block:: bash - PYTHONPATH=$HOME/Code/BioSimSpace/python python script.py + pip install -e . -or use the ``develop`` argument when running the ``setup.py`` script, i.e. +Pre-commit hooks +---------------- + +Pre-commit hooks are used to ensure consistent code formatting and linting. +To set up pre-commit in your development environment: + +.. code-block:: bash + + pixi shell -e dev + pre-commit install + +This will run `ruff `__ formatting and linting +checks automatically on each commit. To run the checks manually against all +files: .. code-block:: bash - python setup.py develop + pre-commit run --all-files Testing ------- @@ -418,7 +431,7 @@ committing. When happy, commit your changes, e.g. .. code-block:: bash - git commit python/BioSimSpace/Feature/new_feature.py test/Feature/test_feature \ + git commit src/BioSimSpace/Feature/new_feature.py test/Feature/test_feature \ -m "Implementation and test for new feature." Remember that it is better to make small changes and commit frequently. diff --git a/doc/source/guides/protocols.rst b/doc/source/guides/protocols.rst index b877b2109..6b87430f5 100644 --- a/doc/source/guides/protocols.rst +++ b/doc/source/guides/protocols.rst @@ -82,7 +82,7 @@ In particular: * Protocols are used to define the way in which a :ref:`molecular parameterisation ` is performed. The :class:`BioSimSpace.Parameters ` - package comes with its own set of `protocols `__, + package comes with its own set of `protocols `__, which can be customised by the user. To do so, either override the ``run`` method of an existing protocol, or define an entirely new protocol that inherits from the base class (you would need to do this if, for example, @@ -103,4 +103,4 @@ In particular: :class:`BioSimSpace.Process.Gromacs `, when a metadynamics protocol is chosen. Modifications for specific metadynamics protocols, e.g. adding support for new collective variables, needs to - be implemented in the ``createConfig`` method of the `BioSimSpace.Process.Plumed `__ class. + be implemented in the ``createConfig`` method of the `BioSimSpace.Process.Plumed `__ class. diff --git a/doc/source/install.rst b/doc/source/install.rst index 586a3019f..1b693b788 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -205,61 +205,50 @@ to learn how to use :mod:`BioSimSpace` or the The following documents a full installation of BioSimSpace from source. Before starting, you'll need a working `Git `__ installation. -BioSimSpace is built on top of the `Sire `__ -molecular simulation framework. To download and install Sire, follow the -instructions `here `__, making -sure that BioSimSpace's dependencies are installed into the Sire conda -environment at the point at which Sire is installed. +Installing from source (standalone) +------------------------------------ -Next you will need to download BioSimSpace and install it into your Sire -Conda environment. +To install from source using `pixi `__, which will +automatically create an environment with all required dependencies +(including pre-built `Sire `__): .. code-block:: bash git clone https://github.com/openbiosim/biosimspace - cd biosimspace/python - pip install . - -If you plan to develop and want an editable install, use: - -.. code-block:: bash - + cd biosimspace + pixi install + pixi shell pip install -e . -If you want to skip the installation of BioSimSpace dependencies, e.g. if they -are already installed, then you can use: +Installing from source (full OpenBioSim development) +------------------------------------------------------ + +If you are developing across the full OpenBioSim stack, first install +`Sire `__ from source by following the +instructions `here `__, then +activate its pixi environment: .. code-block:: bash - BSS_SKIP_DEPENDENCIES=1 pip install -e . + pixi shell --manifest-path /path/to/sire/pixi.toml -e dev -Once finished, you can test the installation by running: +Next, clone and install BioSimSpace: .. code-block:: bash - python + git clone https://github.com/openbiosim/biosimspace + cd biosimspace + pip install -e . -Then try importing the BioSimSpace package: +You may also want to install optional dependencies, such as ``ambertools`` and +``gromacs`` into the environment. + +Once finished, you can test the installation by running: .. code-block:: python import BioSimSpace as BSS -If you don't want to install Sire from source, an alternative is to create a conda -environment containing only the dependencies of BioSimSpace, then install the -latest development code into that. - -.. code-block:: bash - - conda create -n openbiosim-dev -c conda-forge -c openbiosim/label/dev biosimspace --only-deps - conda activate openbiosim-dev - git clone https://github.com/openbiosim/biosimspace - cd biosimspace/python - BSS_SKIP_DEPENDENCIES=1 pip install -e . - -(You may also want to install optional dependencies, such as ``ambertools`` and -``gromacs`` into your environment.) - 5. Common issues ================ diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 000000000..d6243a7f3 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,66 @@ +[workspace] +name = "biosimspace" +channels = ["conda-forge", "openbiosim/label/dev"] +platforms = ["linux-64", "linux-aarch64", "osx-arm64", "win-64"] + +[dependencies] +python = ">=3.10" +configargparse = "*" +ipywidgets = "*" +kcombu_bss = "*" +lazy_import = "*" +loguru = "*" +lomap2 = "*" +networkx = "*" +nglview = "*" +openff-interchange-base = "*" +openff-toolkit-base = "*" +openmmtools = ">=0.21.5" +parmed = "*" +pyarrow = "*" +py3dmol = "*" +pydot = "*" +pygtail = "*" +pyyaml = "*" +rdkit = "*" + +# Optional but useful for full BioSimSpace functionality +[target.linux-64.dependencies] +sire = "*" +ambertools = ">=22" +gromacs = "*" +alchemlyb = "*" +mdtraj = "*" +mdanalysis = "*" + + +[target.linux-aarch64.dependencies] +# sire and ambertools not available as conda packages on linux-aarch64; +# build sire from source first, then pip install -e . for BioSimSpace +gromacs = "*" + +[target.osx-arm64.dependencies] +sire = "*" +ambertools = ">=22" +alchemlyb = "*" +mdtraj = "*" +mdanalysis = "*" + +[target.win-64.dependencies] +sire = "*" +alchemlyb = "*" +mdtraj = "*" +mdanalysis = "*" + +[feature.test.dependencies] +pytest = "*" + +[feature.lint.dependencies] +pre-commit = "*" +rattler-build = "*" +ruff = "*" + +[environments] +default = [] +test = ["test"] +dev = ["test", "lint"] diff --git a/pyproject.toml b/pyproject.toml index eb4df1ee7..18782f394 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,48 @@ +[build-system] +requires = ["setuptools", "versioningit"] +build-backend = "setuptools.build_meta" + +[project] +name = "BioSimSpace" +authors = [ + { name = "Lester Hedges", email = "lester@openbiosim.org" }, + { name = "Christopher Woods" }, + { name = "Antonia Mey" }, +] +description = "BioSimSpace: Making biomolecular simulation a breeze." +readme = "README.rst" +requires-python = ">=3.10" +license = {text = "GPL-3.0-or-later"} +dynamic = ["version"] + +[tool.setuptools] +license-files = ["LICENSE"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +"BioSimSpace.Metadynamics" = ["_aux/*"] + +[project.urls] +homepage = "https://biosimspace.openbiosim.org" +repository = "https://github.com/OpenBioSim/biosimspace" +documentation = "https://biosimspace.openbiosim.org" + +[tool.versioningit.format] +distance = "{base_version}+{distance}.{vcs}{rev}" +dirty = "{base_version}+{distance}.{vcs}{rev}.dirty" +distance-dirty = "{base_version}+{distance}.{vcs}{rev}.dirty" + +[tool.versioningit.write] +file = "src/BioSimSpace/_version.py" + [tool.pytest.ini_options] # Ensure that test/Sandpit/Exscientia could have the same name as the tests in test addopts = "--import-mode=importlib" + +[tool.ruff.lint] +ignore = ["E402"] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["F841"] diff --git a/python/.gitattributes b/python/.gitattributes deleted file mode 100644 index da4d6a745..000000000 --- a/python/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -BioSimSpace/_version.py export-subst diff --git a/python/BioSimSpace/_version.py b/python/BioSimSpace/_version.py deleted file mode 100644 index 7b3deef35..000000000 --- a/python/BioSimSpace/_version.py +++ /dev/null @@ -1,716 +0,0 @@ -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. -# Generated by versioneer-0.29 -# https://github.com/python-versioneer/python-versioneer - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys -from typing import Any, Callable, Dict, List, Optional, Tuple -import functools - - -def get_keywords() -> Dict[str, str]: - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - VCS: str - style: str - tag_prefix: str - parentdir_prefix: str - versionfile_source: str - verbose: bool - - -def get_config() -> VersioneerConfig: - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "" - cfg.parentdir_prefix = "BioSimSpace-" - cfg.versionfile_source = "BioSimSpace/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} - - -def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator - """Create decorator to mark a method as the handler of a VCS.""" - - def decorate(f: Callable) -> Callable: - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - - return decorate - - -def run_command( - commands: List[str], - args: List[str], - cwd: Optional[str] = None, - verbose: bool = False, - hide_stderr: bool = False, - env: Optional[Dict[str, str]] = None, -) -> Tuple[Optional[str], Optional[int]]: - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs: Dict[str, Any] = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - try: - dispcmd = str([command] + args) - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen( - [command] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - **popen_kwargs, - ) - break - except OSError as e: - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, process.returncode - return stdout, process.returncode - - -def versions_from_parentdir( - parentdir_prefix: str, - root: str, - verbose: bool, -) -> Dict[str, Any]: - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords: Dict[str, str] = {} - try: - with open(versionfile_abs, "r") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords( - keywords: Dict[str, str], - tag_prefix: str, - verbose: bool, -) -> Dict[str, Any]: - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r"\d", r)} - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r"\d", r): - continue - if verbose: - print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs( - tag_prefix: str, root: str, verbose: bool, runner: Callable = run_command -) -> Dict[str, Any]: - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - f"{tag_prefix}[[:digit:]]*", - ], - cwd=root, - ) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces: Dict[str, Any] = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) - pieces["distance"] = len(out.split()) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces: Dict[str, Any]) -> str: - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces: Dict[str, Any]) -> str: - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces: Dict[str, Any]) -> str: - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces: Dict[str, Any]) -> str: - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) - else: - rendered += ".post0.dev%d" % (pieces["distance"]) - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = "0.post0.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces: Dict[str, Any]) -> str: - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces: Dict[str, Any]) -> str: - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } - - -def get_versions() -> Dict[str, Any]: - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for _ in cfg.versionfile_source.split("/"): - root = os.path.dirname(root) - except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } diff --git a/python/MANIFEST.in b/python/MANIFEST.in deleted file mode 100644 index c11c59084..000000000 --- a/python/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include versioneer.py -include BioSimSpace/_version.py -include BioSimSpace/Metadynamics/_aux/* diff --git a/python/setup.cfg b/python/setup.cfg deleted file mode 100644 index 9975abf56..000000000 --- a/python/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[versioneer] -VCS = git -style = pep440 -versionfile_source = BioSimSpace/_version.py -versionfile_build = BioSimSpace/_version.py -tag_prefix = -parentdir_prefix = BioSimSpace- diff --git a/python/setup.py b/python/setup.py deleted file mode 100644 index c382b7c52..000000000 --- a/python/setup.py +++ /dev/null @@ -1,243 +0,0 @@ -import os -import sys -import platform - -from setuptools import setup, find_packages - -import versioneer - -# A list of authors and their email addresses. - -# Allow setting on the command line because setting -# environment variables on Windows is painful! -if "BSS_SKIP_DEPENDENCIES=1" in sys.argv: - os.environ["BSS_SKIP_DEPENDENCIES"] = "1" - sys.argv.remove("BSS_SKIP_DEPENDENCIES=1") - -if "BSS_CONDA_INSTALL=1" in sys.argv: - os.environ["BSS_CONDA_INSTALL"] = "1" - sys.argv.remove("BSS_CONDA_INSTALL=1") - -authors = ( - "Lester Hedges , " - "Antonia Mey = (3, 11): - import tomllib -else: - try: - import tomli as tomllib - except ImportError: - have_tomllib = False - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - VCS: str - style: str - tag_prefix: str - versionfile_source: str - versionfile_build: Optional[str] - parentdir_prefix: Optional[str] - verbose: Optional[bool] - - -def get_root() -> str: - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - pyproject_toml = os.path.join(root, "pyproject.toml") - versioneer_py = os.path.join(root, "versioneer.py") - if not ( - os.path.exists(setup_py) - or os.path.exists(pyproject_toml) - or os.path.exists(versioneer_py) - ): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - pyproject_toml = os.path.join(root, "pyproject.toml") - versioneer_py = os.path.join(root, "versioneer.py") - if not ( - os.path.exists(setup_py) - or os.path.exists(pyproject_toml) - or os.path.exists(versioneer_py) - ): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - my_path = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(my_path)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir and "VERSIONEER_PEP518" not in globals(): - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(my_path), versioneer_py) - ) - except NameError: - pass - return root - - -def get_config_from_root(root: str) -> VersioneerConfig: - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise OSError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - root_pth = Path(root) - pyproject_toml = root_pth / "pyproject.toml" - setup_cfg = root_pth / "setup.cfg" - section: Union[Dict[str, Any], configparser.SectionProxy, None] = None - if pyproject_toml.exists() and have_tomllib: - try: - with open(pyproject_toml, "rb") as fobj: - pp = tomllib.load(fobj) - section = pp["tool"]["versioneer"] - except (tomllib.TOMLDecodeError, KeyError) as e: - print(f"Failed to load config from {pyproject_toml}: {e}") - print("Try to load it from setup.cfg") - if not section: - parser = configparser.ConfigParser() - with open(setup_cfg) as cfg_file: - parser.read_file(cfg_file) - parser.get("versioneer", "VCS") # raise error if missing - - section = parser["versioneer"] - - # `cast`` really shouldn't be used, but its simplest for the - # common VersioneerConfig users at the moment. We verify against - # `None` values elsewhere where it matters - - cfg = VersioneerConfig() - cfg.VCS = section["VCS"] - cfg.style = section.get("style", "") - cfg.versionfile_source = cast(str, section.get("versionfile_source")) - cfg.versionfile_build = section.get("versionfile_build") - cfg.tag_prefix = cast(str, section.get("tag_prefix")) - if cfg.tag_prefix in ("''", '""', None): - cfg.tag_prefix = "" - cfg.parentdir_prefix = section.get("parentdir_prefix") - if isinstance(section, configparser.SectionProxy): - # Make sure configparser translates to bool - cfg.verbose = section.getboolean("verbose") - else: - cfg.verbose = section.get("verbose") - - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} - - -def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator - """Create decorator to mark a method as the handler of a VCS.""" - - def decorate(f: Callable) -> Callable: - """Store f in HANDLERS[vcs][method].""" - HANDLERS.setdefault(vcs, {})[method] = f - return f - - return decorate - - -def run_command( - commands: List[str], - args: List[str], - cwd: Optional[str] = None, - verbose: bool = False, - hide_stderr: bool = False, - env: Optional[Dict[str, str]] = None, -) -> Tuple[Optional[str], Optional[int]]: - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs: Dict[str, Any] = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - try: - dispcmd = str([command] + args) - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen( - [command] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - **popen_kwargs, - ) - break - except OSError as e: - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, process.returncode - return stdout, process.returncode - - -LONG_VERSION_PY[ - "git" -] = r''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. -# Generated by versioneer-0.29 -# https://github.com/python-versioneer/python-versioneer - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys -from typing import Any, Callable, Dict, List, Optional, Tuple -import functools - - -def get_keywords() -> Dict[str, str]: - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - VCS: str - style: str - tag_prefix: str - parentdir_prefix: str - versionfile_source: str - verbose: bool - - -def get_config() -> VersioneerConfig: - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} - - -def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator - """Create decorator to mark a method as the handler of a VCS.""" - def decorate(f: Callable) -> Callable: - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command( - commands: List[str], - args: List[str], - cwd: Optional[str] = None, - verbose: bool = False, - hide_stderr: bool = False, - env: Optional[Dict[str, str]] = None, -) -> Tuple[Optional[str], Optional[int]]: - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs: Dict[str, Any] = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - try: - dispcmd = str([command] + args) - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen([command] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None), **popen_kwargs) - break - except OSError as e: - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, process.returncode - return stdout, process.returncode - - -def versions_from_parentdir( - parentdir_prefix: str, - root: str, - verbose: bool, -) -> Dict[str, Any]: - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords: Dict[str, str] = {} - try: - with open(versionfile_abs, "r") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords( - keywords: Dict[str, str], - tag_prefix: str, - verbose: bool, -) -> Dict[str, Any]: - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r'\d', r)} - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r'\d', r): - continue - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs( - tag_prefix: str, - root: str, - verbose: bool, - runner: Callable = run_command -) -> Dict[str, Any]: - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=not verbose) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner(GITS, [ - "describe", "--tags", "--dirty", "--always", "--long", - "--match", f"{tag_prefix}[[:digit:]]*" - ], cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces: Dict[str, Any] = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], - cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) - pieces["distance"] = len(out.split()) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces: Dict[str, Any]) -> str: - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces: Dict[str, Any]) -> str: - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces: Dict[str, Any]) -> str: - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces: Dict[str, Any]) -> str: - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += ".post%%d.dev%%d" %% (post_version + 1, pieces["distance"]) - else: - rendered += ".post0.dev%%d" %% (pieces["distance"]) - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = "0.post0.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces: Dict[str, Any]) -> str: - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces: Dict[str, Any]) -> str: - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions() -> Dict[str, Any]: - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for _ in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords: Dict[str, str] = {} - try: - with open(versionfile_abs, "r") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords( - keywords: Dict[str, str], - tag_prefix: str, - verbose: bool, -) -> Dict[str, Any]: - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r"\d", r)} - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r"\d", r): - continue - if verbose: - print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs( - tag_prefix: str, root: str, verbose: bool, runner: Callable = run_command -) -> Dict[str, Any]: - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - f"{tag_prefix}[[:digit:]]*", - ], - cwd=root, - ) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces: Dict[str, Any] = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) - pieces["distance"] = len(out.split()) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(versionfile_source: str, ipy: Optional[str]) -> None: - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [versionfile_source] - if ipy: - files.append(ipy) - if "VERSIONEER_PEP518" not in globals(): - try: - my_path = __file__ - if my_path.endswith((".pyc", ".pyo")): - my_path = os.path.splitext(my_path)[0] + ".py" - versioneer_file = os.path.relpath(my_path) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - with open(".gitattributes", "r") as fobj: - for line in fobj: - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - break - except OSError: - pass - if not present: - with open(".gitattributes", "a+") as fobj: - fobj.write(f"{versionfile_source} export-subst\n") - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir( - parentdir_prefix: str, - root: str, - verbose: bool, -) -> Dict[str, Any]: - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.29) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) -""" - - -def versions_from_file(filename: str) -> Dict[str, Any]: - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except OSError: - raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S - ) - if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S - ) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename: str, versions: Dict[str, Any]) -> None: - """Write the given version number to the given _version.py file.""" - contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces: Dict[str, Any]) -> str: - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces: Dict[str, Any]) -> str: - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces: Dict[str, Any]) -> str: - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces: Dict[str, Any]) -> str: - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) - else: - rendered += ".post0.dev%d" % (pieces["distance"]) - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = "0.post0.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces: Dict[str, Any]) -> str: - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces: Dict[str, Any]) -> str: - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces: Dict[str, Any]) -> str: - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose: bool = False) -> Dict[str, Any]: - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or bool(cfg.verbose) # `bool()` used to avoid `None` - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } - - -def get_version() -> str: - """Get the short version string for this project.""" - return get_versions()["version"] - - -def get_cmdclass(cmdclass: Optional[Dict[str, Any]] = None): - """Get the custom setuptools subclasses used by Versioneer. - - If the package uses a different cmdclass (e.g. one from numpy), it - should be provide as an argument. - """ - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/python-versioneer/python-versioneer/issues/52 - - cmds = {} if cmdclass is None else cmdclass.copy() - - # we add "version" to setuptools - from setuptools import Command - - class cmd_version(Command): - description = "report generated version string" - user_options: List[Tuple[str, str, str]] = [] - boolean_options: List[str] = [] - - def initialize_options(self) -> None: - pass - - def finalize_options(self) -> None: - pass - - def run(self) -> None: - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - - cmds["version"] = cmd_version - - # we override "build_py" in setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - - # pip install -e . and setuptool/editable_wheel will invoke build_py - # but the build_py command is not expected to copy any files. - - # we override different "build_py" commands for both environments - if "build_py" in cmds: - _build_py: Any = cmds["build_py"] - else: - from setuptools.command.build_py import build_py as _build_py - - class cmd_build_py(_build_py): - def run(self) -> None: - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_py.run(self) - if getattr(self, "editable_mode", False): - # During editable installs `.py` and data files are - # not copied to build_lib - return - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - cmds["build_py"] = cmd_build_py - - if "build_ext" in cmds: - _build_ext: Any = cmds["build_ext"] - else: - from setuptools.command.build_ext import build_ext as _build_ext - - class cmd_build_ext(_build_ext): - def run(self) -> None: - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_ext.run(self) - if self.inplace: - # build_ext --inplace will only build extensions in - # build/lib<..> dir with no _version.py to write to. - # As in place builds will already have a _version.py - # in the module dir, we do not need to write one. - return - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if not cfg.versionfile_build: - return - target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) - if not os.path.exists(target_versionfile): - print( - f"Warning: {target_versionfile} does not exist, skipping " - "version update. This can happen if you are running build_ext " - "without first running build_py." - ) - return - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - cmds["build_ext"] = cmd_build_ext - - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe # type: ignore - - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self) -> None: - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if "py2exe" in sys.modules: # py2exe enabled? - try: - from py2exe.setuptools_buildexe import py2exe as _py2exe # type: ignore - except ImportError: - from py2exe.distutils_buildexe import py2exe as _py2exe # type: ignore - - class cmd_py2exe(_py2exe): - def run(self) -> None: - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - cmds["py2exe"] = cmd_py2exe - - # sdist farms its file list building out to egg_info - if "egg_info" in cmds: - _egg_info: Any = cmds["egg_info"] - else: - from setuptools.command.egg_info import egg_info as _egg_info - - class cmd_egg_info(_egg_info): - def find_sources(self) -> None: - # egg_info.find_sources builds the manifest list and writes it - # in one shot - super().find_sources() - - # Modify the filelist and normalize it - root = get_root() - cfg = get_config_from_root(root) - self.filelist.append("versioneer.py") - if cfg.versionfile_source: - # There are rare cases where versionfile_source might not be - # included by default, so we must be explicit - self.filelist.append(cfg.versionfile_source) - self.filelist.sort() - self.filelist.remove_duplicates() - - # The write method is hidden in the manifest_maker instance that - # generated the filelist and was thrown away - # We will instead replicate their final normalization (to unicode, - # and POSIX-style paths) - from setuptools import unicode_utils - - normalized = [ - unicode_utils.filesys_decode(f).replace(os.sep, "/") - for f in self.filelist.files - ] - - manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") - with open(manifest_filename, "w") as fobj: - fobj.write("\n".join(normalized)) - - cmds["egg_info"] = cmd_egg_info - - # we override different "sdist" commands for both environments - if "sdist" in cmds: - _sdist: Any = cmds["sdist"] - else: - from setuptools.command.sdist import sdist as _sdist - - class cmd_sdist(_sdist): - def run(self) -> None: - versions = get_versions() - self._versioneer_generated_versions = versions - # unless we update this, the command will keep using the old - # version - self.distribution.metadata.version = versions["version"] - return _sdist.run(self) - - def make_release_tree(self, base_dir: str, files: List[str]) -> None: - root = get_root() - cfg = get_config_from_root(root) - _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) - print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - - cmds["sdist"] = cmd_sdist - - return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -OLD_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - -INIT_PY_SNIPPET = """ -from . import {0} -__version__ = {0}.get_versions()['version'] -""" - - -def do_setup() -> int: - """Do main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: - if isinstance(e, (OSError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") - maybe_ipy: Optional[str] = ipy - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except OSError: - old = "" - module = os.path.splitext(os.path.basename(cfg.versionfile_source))[0] - snippet = INIT_PY_SNIPPET.format(module) - if OLD_SNIPPET in old: - print(" replacing boilerplate in %s" % ipy) - with open(ipy, "w") as f: - f.write(old.replace(OLD_SNIPPET, snippet)) - elif snippet not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(snippet) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - maybe_ipy = None - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(cfg.versionfile_source, maybe_ipy) - return 0 - - -def scan_setup_py() -> int: - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - - -def setup_command() -> NoReturn: - """Set up Versioneer and exit with appropriate error code.""" - errors = do_setup() - errors += scan_setup_py() - sys.exit(1 if errors else 0) - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - setup_command() diff --git a/recipes/biosimspace/bld.bat b/recipes/biosimspace/bld.bat deleted file mode 100644 index 25bad57d3..000000000 --- a/recipes/biosimspace/bld.bat +++ /dev/null @@ -1,3 +0,0 @@ - -cd python -python setup.py BSS_CONDA_INSTALL=1 install diff --git a/recipes/biosimspace/build.sh b/recipes/biosimspace/build.sh deleted file mode 100644 index 905db3950..000000000 --- a/recipes/biosimspace/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# Build script for BioSimSpace Conda installation. - -cd python && BSS_CONDA_INSTALL=True python setup.py install --single-version-externally-managed --record=record.txt diff --git a/recipes/biosimspace/recipe.yaml b/recipes/biosimspace/recipe.yaml new file mode 100644 index 000000000..1fefa4cd9 --- /dev/null +++ b/recipes/biosimspace/recipe.yaml @@ -0,0 +1,78 @@ +context: + name: biosimspace + +package: + name: ${{ name }} + version: ${{ env.get('GIT_DESCRIBE_TAG', default='PR') }} + +source: + path: ../../biosimspace-source.tar.gz + +build: + number: ${{ env.get('GIT_DESCRIBE_NUMBER', default='0') }} + script: python -m pip install . --no-deps --ignore-installed -vv + +requirements: + host: + - pip + - python + - setuptools + - versioningit + run: + - configargparse + - ipywidgets + - kcombu_bss + - lazy_import + - loguru + - lomap2 + - networkx + - nglview + - openff-interchange-base + - openff-toolkit-base + - parmed + - pyarrow + - py3dmol + - pydot + - pygtail + - python + - pyyaml + - rdkit + - sire + - if: not aarch64 + then: + - alchemlyb + - mdanalysis + - mdtraj + +tests: + - python: + imports: + - BioSimSpace + - script: + - if: unix + then: PYTHONPATH=. pytest -vvv --color=yes --import-mode=importlib ./tests + else: set "PYTHONPATH=." && pytest -vvv --color=yes --import-mode=importlib ./tests + files: + source: + - tests/ + requirements: + run: + - pytest + - requests + - if: linux and x86_64 + then: + - ambertools + - gromacs + +about: + homepage: https://biosimspace.openbiosim.org + license: GPL-3.0-or-later + license_file: LICENSE + summary: "An interoperable Python framework for biomolecular simulation." + repository: https://github.com/openbiosim/biosimspace + documentation: https://biosimspace.openbiosim.org + +extra: + recipe-maintainers: + - lohedges + - chryswoods diff --git a/recipes/biosimspace/template.yaml b/recipes/biosimspace/template.yaml deleted file mode 100644 index f75856df2..000000000 --- a/recipes/biosimspace/template.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{% set name = "biosimspace" %} - -package: - name: {{ name }} - version: {{ environ.get('GIT_DESCRIBE_TAG', 'PR') }} - -source: - git_url: BSS_REMOTE - git_tag: BSS_BRANCH - -build: - number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} - -requirements: - build: - BSS_BUILD_REQUIREMENTS - host: - - python - BSS_RUN_REQUIREMENTS - run: - - python - BSS_RUN_REQUIREMENTS - -test: - script_env: - - SIRE_DONT_PHONEHOME - - SIRE_SILENT_PHONEHOME - requires: - - pytest <8 - - black 25 # [linux and x86_64 and py==312] - - pytest-black # [linux and x86_64 and py==312] - - ambertools # [linux and x86_64] - - gromacs # [linux and x86_64] - - requests - imports: - - BioSimSpace - source_files: - - python/BioSimSpace # [linux and x86_64 and py==312] - - tests - commands: - - pytest -vvv --color=yes --black python/BioSimSpace # [linux and x86_64 and py==312] - - pytest -vvv --color=yes --import-mode=importlib tests - -about: - home: https://biosimspace.openbiosim.org - license: GPL-3.0-or-later - license_file: '{{ environ["RECIPE_DIR"] }}/LICENSE' - summary: "An interoperable Python framework for biomolecular simulation." - dev_url: https://github.com/openbiosim/biosimspace - doc_url: https://biosimspace.openbiosim.org - description: | - BioSimSpace is an interoperable Python framework for - biomolecular simulation. With it you can: - - * Write robust and portable biomolecular workflow components - that work on different hardware, with different software - packages, and that can be run in different ways, e.g. - command-line, Jupyter. - * Interact with molecular-simulation processes in real time. - - To install: - - `conda install -c conda-forge -c openbiosim biosimspace` - - To install the development version: - - `conda install -c conda-forge -c openbiosim/label/dev biosimspace` - - When updating the development version it is generally advised to - update Sire at the same time: - - `conda install -c conda-forge -c openbiosim/label/dev biosimspace sire` - -extra: - recipe-maintainers: - - lohedges - - chryswoods diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c91298385..000000000 --- a/requirements.txt +++ /dev/null @@ -1,32 +0,0 @@ -# BioSimSpace runtime requirements. - -# main -#sire~=2025.3.0 - -# devel -sire==2025.4.0.dev - -configargparse -ipywidgets -kcombu_bss -lazy_import -loguru -lomap2 -networkx -nglview -openff-interchange-base -openff-toolkit-base -parmed -pyarrow -py3dmol -pydot -pygtail -pyyaml -rdkit - -# The below are packages that aren't available on all -# platforms/OSs and so need to be conditionally included - -alchemlyb ; platform_machine != "aarch64" # Needs pymbar, not on Linux/aarch64 -mdanalysis ; platform_machine != "aarch64" # not on Linux/aarch64 -mdtraj ; platform_machine != "aarch64" # not on Linux/aarch64 diff --git a/requirements_build.txt b/requirements_build.txt deleted file mode 100644 index bdf50b42c..000000000 --- a/requirements_build.txt +++ /dev/null @@ -1 +0,0 @@ -# BioSimSpace build requirements. diff --git a/python/BioSimSpace/Align/__init__.py b/src/BioSimSpace/Align/__init__.py similarity index 100% rename from python/BioSimSpace/Align/__init__.py rename to src/BioSimSpace/Align/__init__.py index ae4e2fa0b..ca6643b45 100644 --- a/python/BioSimSpace/Align/__init__.py +++ b/src/BioSimSpace/Align/__init__.py @@ -45,5 +45,5 @@ _sr.use_new_api() del _sr -from ._align import * from . import _squash +from ._align import * diff --git a/python/BioSimSpace/Align/_align.py b/src/BioSimSpace/Align/_align.py similarity index 99% rename from python/BioSimSpace/Align/_align.py rename to src/BioSimSpace/Align/_align.py index 31b692883..b1008d7c5 100644 --- a/python/BioSimSpace/Align/_align.py +++ b/src/BioSimSpace/Align/_align.py @@ -33,11 +33,10 @@ "merge", ] +import warnings as _warnings from typing import Any, Collection, Optional -from .._Utils import _try_import, _have_imported - -import warnings as _warnings +from .._Utils import _have_imported, _try_import # Suppress duplicate to-Python converted warnings. # Both Sire and RDKit register the same converter. @@ -47,10 +46,8 @@ if _have_imported(_rdkit): from rdkit import Chem as _Chem - from rdkit.Chem import rdFMCS as _rdFMCS from rdkit import RDLogger as _RDLogger - from rdkit.Chem import Draw - from rdkit.Chem import AllChem + from rdkit.Chem import rdFMCS as _rdFMCS # Disable RDKit warnings. _RDLogger.DisableLog("rdApp.*") @@ -61,7 +58,6 @@ from sire.legacy import Base as _SireBase - from .. import Units as _Units # lomap depends on RDKit and networkx @@ -170,14 +166,14 @@ def generateNetwork( perturbation between molecules along an edge is likely to be more accurate. """ - from .._Utils import _assert_imported - from .._Exceptions import AlignmentError as _AlignmentError - from .._SireWrappers import Molecule as _Molecule import csv as _csv import os as _os - from .. import _is_notebook, _isVerbose + from .. import IO as _IO - from .. import _Utils + from .. import _is_notebook, _isVerbose, _Utils + from .._Exceptions import AlignmentError as _AlignmentError + from .._SireWrappers import Molecule as _Molecule + from .._Utils import _assert_imported # Adapted from code by Jenke Scheen (@JenkeScheen). @@ -268,9 +264,9 @@ def generateNetwork( ) # Make sure that the ligands are in the names list. - if not records[0] in names: + if records[0] not in names: raise ValueError(f"Ligand '{records[0]}' not in 'names' list!") - if not records[1] in names: + if records[1] not in names: raise ValueError(f"Ligand '{records[1]}' not in 'names' list!") else: @@ -278,7 +274,7 @@ def generateNetwork( # Validate the number of edges parameter. if n_edges_forced is not None: - if not type(n_edges_forced) is int: + if type(n_edges_forced) is not int: raise TypeError("'n_edges_forced' must be of type 'int'") n_edges_fully_connected = int((len(molecules) ** 2 - len(molecules)) / 2) + 1 @@ -473,7 +469,7 @@ def generateNetwork( # Update the list while checking that the inverse edge is not already in # the network. - if not (mol1, mol0) in edges: + if (mol1, mol0) not in edges: edges_excluded.append((mol0, mol1, score)) # If the user has specified a forced number of edges, adjust the network @@ -904,12 +900,14 @@ def _matchAtoms( property_map0={}, property_map1={}, ): - from .._SireWrappers import Molecule as _Molecule import sys as _sys + + from sire.legacy import Mol as _SireMol from sire.legacy import Units as _SireUnits + from .. import Convert as _Convert - from sire.legacy import Mol as _SireMol from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from .._SireWrappers import Molecule as _Molecule # A list of supported scoring functions. scoring_functions = ["RMSD", "RMSDALIGN", "RMSDFLEXALIGN"] @@ -932,7 +930,7 @@ def _matchAtoms( # Strip underscores and whitespace, then convert to upper case. _scoring_function = scoring_function.replace("_", "").upper() _scoring_function = _scoring_function.replace(" ", "").upper() - if not _scoring_function in scoring_functions: + if _scoring_function not in scoring_functions: raise ValueError( "Unsupported scoring function '%s'. Options are: %s" % (scoring_function, scoring_functions) @@ -944,7 +942,7 @@ def _matchAtoms( "https://pdbj.org/kcombu" ) - if not type(matches) is int: + if type(matches) is not int: raise TypeError("'matches' must be of type 'int'") else: if matches < 0: @@ -964,7 +962,7 @@ def _matchAtoms( if not isinstance(complete_rings_only, bool): raise TypeError("'complete_rings_only' must be of type 'bool'") - if not type(max_scoring_matches) is int: + if type(max_scoring_matches) is not int: raise TypeError("'max_scoring_matches' must be of type 'int'") if max_scoring_matches <= 0: @@ -1165,14 +1163,14 @@ def _kartograf_map(molecule0, molecule1, kartograf_kwargs): # Try to import kartograf. try: + from kartograf import ( + KartografAtomMapper, + ) + from kartograf import SmallMoleculeComponent as _SmallMoleculeComponent from kartograf.atom_aligner import align_mol_shape as _align_mol_shape from kartograf.atom_mapping_scorer import ( MappingRMSDScorer as _MappingRMSDScorer, ) - from kartograf import ( - KartografAtomMapper, - SmallMoleculeComponent as _SmallMoleculeComponent, - ) except ImportError: raise ImportError( "Unable to import Kartograf. Make sure Kartograf is installed properly to use this function." @@ -1438,7 +1436,6 @@ def _roiMatch( # In the case when we are not at the last residue of interest, # we need to map the atoms to the next ROI. if res_idx != roi[-1]: - # If the next ROI residue index in the ROI list is next to # the current ROI index, after_roi atom index list will be empty # i.e. if we're currently at residue 10 and the next ROI is 11, @@ -1604,10 +1601,11 @@ def rmsdAlign( def _rmsdAlign(molecule0, molecule1, mapping=None, property_map0={}, property_map1={}): - from .._Exceptions import AlignmentError as _AlignmentError + from sire.legacy import Mol as _SireMol + from .. import _isVerbose + from .._Exceptions import AlignmentError as _AlignmentError from .._SireWrappers import Molecule as _Molecule - from sire.legacy import Mol as _SireMol if not isinstance(molecule0, _Molecule): raise TypeError( @@ -1789,13 +1787,14 @@ def _flexAlign( property_map1, ): # Check that we found fkcombu in the PATH. + import os as _os import subprocess as _subprocess + + from .. import IO as _IO + from .. import _Utils from .._Exceptions import AlignmentError as _AlignmentError - from .._SireWrappers import Molecule as _Molecule - import os as _os from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from .. import _Utils - from .. import IO as _IO + from .._SireWrappers import Molecule as _Molecule if fkcombu_exe is None: if _fkcombu_exe is None: @@ -2114,8 +2113,8 @@ def merge( >>> import BioSimSpace as BSS >>> molecule0 = BSS.Align.merge(molecule0, molecule1) """ - from ._merge import merge as _merge from .._SireWrappers import Molecule as _Molecule + from ._merge import merge as _merge if not isinstance(molecule0, _Molecule): raise TypeError( @@ -2231,16 +2230,16 @@ def viewMapping( show_adjacent_residues : bool, optional default=False If set to True, will show neighouring residues to the ROI region. """ - from .._Utils import _assert_imported from .. import Convert as _Convert from .. import _is_notebook from .._SireWrappers import Molecule as _Molecule + from .._Utils import _assert_imported # Only draw within a notebook. if not _is_notebook: return None else: - from IPython.display import display, Image + from IPython.display import Image, display _assert_imported(_rdkit) @@ -2265,7 +2264,7 @@ def viewMapping( if isinstance(pixels, float): pixels = int(pixels) - if not type(pixels) is int: + if type(pixels) is not int: raise TypeError("'pixels' must be of type 'int'") if pixels <= 0: raise ValueError("pixels' must be > 0!") @@ -2451,8 +2450,7 @@ def _draw_molecules( # Adapted from GUFE: https://github.com/OpenFreeEnergy/gufe # Licensed under the MIT license. - from rdkit.Chem import Draw - from rdkit.Chem import AllChem + from rdkit.Chem import AllChem, Draw # input standardization: if atom_mapping is None: @@ -2634,14 +2632,14 @@ def _score_rdkit_mappings( mapping, scores : ([dict], list) The ranked mappings and corresponding scores. """ - from .._Exceptions import AlignmentError as _AlignmentError - from .._SireWrappers import Molecule as _Molecule from sire.legacy import Maths as _SireMaths from sire.legacy import Mol as _SireMol + from .. import _isVerbose + from .._Exceptions import AlignmentError as _AlignmentError + from .._SireWrappers import Molecule as _Molecule # Adapted from FESetup: https://github.com/CCPBioSim/fesetup - # Make sure to re-map the coordinates property in both molecules, otherwise # the move and align functions from Sire will not work. prop0 = property_map0.get("coordinates", "coordinates") @@ -2716,7 +2714,7 @@ def _score_rdkit_mappings( } # This is a new mapping: - if not mapping in mappings: + if mapping not in mappings: # Check that the mapping contains the pre-match. is_valid = True for idx0, idx1 in prematch.items(): @@ -2871,11 +2869,12 @@ def _score_sire_mappings( mapping, scores : ([dict], list) The ranked mappings and corresponding scores. """ - from .._Exceptions import AlignmentError as _AlignmentError - from .._SireWrappers import Molecule as _Molecule from sire.legacy import Maths as _SireMaths from sire.legacy import Mol as _SireMol + from .. import _isVerbose + from .._Exceptions import AlignmentError as _AlignmentError + from .._SireWrappers import Molecule as _Molecule # Make sure to re-map the coordinates property in both molecules, otherwise # the move and align functions from Sire will not work. diff --git a/python/BioSimSpace/Align/_merge.py b/src/BioSimSpace/Align/_merge.py similarity index 99% rename from python/BioSimSpace/Align/_merge.py rename to src/BioSimSpace/Align/_merge.py index 49158ebb7..835286fb2 100644 --- a/python/BioSimSpace/Align/_merge.py +++ b/src/BioSimSpace/Align/_merge.py @@ -90,13 +90,14 @@ def merge( The merged molecule. """ from sire.legacy import CAS as _SireCAS - from sire.legacy import Mol as _SireMol - from sire.legacy import Base as _SireBase from sire.legacy import MM as _SireMM - from .._SireWrappers import Molecule as _Molecule - from .._Exceptions import IncompatibleError as _IncompatibleError + from sire.legacy import Base as _SireBase + from sire.legacy import Mol as _SireMol from sire.legacy import Units as _SireUnits + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule + # Validate input. if not isinstance(molecule0, _Molecule): @@ -336,7 +337,7 @@ def merge( # lambda = 0 for prop in props0: - if not prop in ignored_props: + if prop not in ignored_props: # This is a perturbable property. if prop in shared_props: name = f"{prop}0" @@ -356,7 +357,7 @@ def merge( # lambda = 1 for prop in props1: - if not prop in ignored_props: + if prop not in ignored_props: # This is a perturbable property. if prop in shared_props: name = f"{prop}1" @@ -1421,8 +1422,9 @@ def _removeDummies(molecule, is_lambda1): """ from sire.legacy import IO as _SireIO from sire.legacy import Mol as _SireMol - from .._SireWrappers import Molecule as _Molecule + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule if not molecule._is_perturbable: raise _IncompatibleError("'molecule' is not a perturbable molecule") diff --git a/python/BioSimSpace/Align/_squash.py b/src/BioSimSpace/Align/_squash.py similarity index 99% rename from python/BioSimSpace/Align/_squash.py rename to src/BioSimSpace/Align/_squash.py index 88d77fabe..5e2aef1ff 100644 --- a/python/BioSimSpace/Align/_squash.py +++ b/src/BioSimSpace/Align/_squash.py @@ -128,12 +128,14 @@ def _squash_molecule(molecule, explicit_dummies=False): system : BioSimSpace._SireWrappers.System The output squashed system. """ + import os as _os + import shutil as _shutil import tempfile - from ..IO import readMolecules as _readMolecules, saveMolecules as _saveMolecules - from ._merge import _removeDummies + from .._SireWrappers import Molecule as _Molecule - import shutil as _shutil - import os as _os + from ..IO import readMolecules as _readMolecules + from ..IO import saveMolecules as _saveMolecules + from ._merge import _removeDummies if not molecule.isPerturbable(): return molecule @@ -326,9 +328,10 @@ def _unsquash_molecule(molecule, squashed_molecules, explicit_dummies=False): molecule : BioSimSpace._SireWrappers.Molecule The output updated merged molecule. """ - from .._SireWrappers import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from .._SireWrappers import Molecule as _Molecule + # Get the common core atoms atom_mapping0_common = _squashed_atom_mapping( molecule, @@ -483,9 +486,10 @@ def _squashed_atom_mapping(system, is_lambda1=False, environment=True, **kwargs) mapping : dict(int, int) The corresponding atom mapping. """ - from .._SireWrappers import Molecule as _Molecule import numpy as _np + from .._SireWrappers import Molecule as _Molecule + if isinstance(system, _Molecule): return _squashed_atom_mapping( system.toSystem(), is_lambda1=is_lambda1, environment=environment, **kwargs diff --git a/python/BioSimSpace/Box/__init__.py b/src/BioSimSpace/Box/__init__.py similarity index 100% rename from python/BioSimSpace/Box/__init__.py rename to src/BioSimSpace/Box/__init__.py diff --git a/python/BioSimSpace/Box/_box.py b/src/BioSimSpace/Box/_box.py similarity index 99% rename from python/BioSimSpace/Box/_box.py rename to src/BioSimSpace/Box/_box.py index 83c61ab8e..1d7a6c61a 100644 --- a/python/BioSimSpace/Box/_box.py +++ b/src/BioSimSpace/Box/_box.py @@ -89,8 +89,8 @@ def cubic(image_distance): angles : [:class:`Angle `] The box vector angles: yz, xz, and xy. """ - from ..Types import Length as _Length from ..Types import Angle as _Angle + from ..Types import Length as _Length # Validate arguments. @@ -125,9 +125,10 @@ def rhombicDodecahedronSquare(image_distance): angles : [:class:`Angle `] The box vector angles: yz, xz, and xy. """ - from ..Types import Length as _Length from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length + # Validate arguments. if not isinstance(image_distance, _Length): @@ -164,9 +165,10 @@ def rhombicDodecahedronHexagon(image_distance): angles : [:class:`Angle `] The box vector angles: yz, xz, and xy. """ - from ..Types import Length as _Length from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length + # Validate arguments. if not isinstance(image_distance, _Length): @@ -203,9 +205,10 @@ def truncatedOctahedron(image_distance): angles : [:class:`Angle `] The box vector angles: yz, xz, and xy. """ - from ..Types import Length as _Length from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length + # Validate arguments. if not isinstance(image_distance, _Length): @@ -238,10 +241,11 @@ def _get_box_parameters(triclinic_box): box : [:class:`Length `] The box vector magnitudes. """ - from ..Types import Length as _Length - from ..Types import Angle as _Angle from sire.legacy.Maths import Vector as _Vector + from ..Types import Angle as _Angle + from ..Types import Length as _Length + box = [ _Length(triclinic_box.vector0().magnitude(), "angstrom"), _Length(triclinic_box.vector1().magnitude(), "angstrom"), diff --git a/python/BioSimSpace/Convert/__init__.py b/src/BioSimSpace/Convert/__init__.py similarity index 100% rename from python/BioSimSpace/Convert/__init__.py rename to src/BioSimSpace/Convert/__init__.py diff --git a/python/BioSimSpace/Convert/_convert.py b/src/BioSimSpace/Convert/_convert.py similarity index 99% rename from python/BioSimSpace/Convert/_convert.py rename to src/BioSimSpace/Convert/_convert.py index 57521eb69..c71ead665 100644 --- a/python/BioSimSpace/Convert/_convert.py +++ b/src/BioSimSpace/Convert/_convert.py @@ -73,6 +73,7 @@ def smiles( A BioSimSpace molecule. """ from sire import smiles as _sire_smiles + from .. import _SireWrappers from .._Exceptions import ConversionError as _ConversionError @@ -158,16 +159,17 @@ def to(obj, format="biosimspace", property_map={}, **kwargs): converted_obj : The object in the converted format. """ - from .._Exceptions import ConversionError as _ConversionError - from sire import convert as _sire_convert - from rdkit.Chem.rdchem import Mol as _RDMol - from .._Utils import _have_imported - import sire.system as _NewSireSystem - from .. import _SireWrappers import sire.legacy.Base as _SireBase import sire.legacy.Mol as _SireMol import sire.legacy.System as _SireSystem import sire.legacy.Vol as _SireVol + import sire.system as _NewSireSystem + from rdkit.Chem.rdchem import Mol as _RDMol + from sire import convert as _sire_convert + + from .. import _SireWrappers + from .._Exceptions import ConversionError as _ConversionError + from .._Utils import _have_imported # Validate the input. @@ -177,7 +179,7 @@ def to(obj, format="biosimspace", property_map={}, **kwargs): # Convert to lower case and strip whitespace. format = format.lower().replace(" ", "") - if not format in supportedFormats(): + if format not in supportedFormats(): raise ValueError( f"Unsupported format '{format}', options are: {', '.join(supportedFormats())}." ) @@ -610,10 +612,11 @@ def _to_rdkit(molecule, work_dir=_os.getcwd(), direct=True, property_map={}): rdmol : rdkit.Chem.rdchem.Mol The molecule in RDKit format. """ - from .._Exceptions import ConversionError as _ConversionError import rdkit.Chem as _Chem + from .. import IO as _IO from .. import _SireWrappers + from .._Exceptions import ConversionError as _ConversionError if not isinstance(molecule, _SireWrappers.Molecule): raise TypeError( diff --git a/python/BioSimSpace/FreeEnergy/__init__.py b/src/BioSimSpace/FreeEnergy/__init__.py similarity index 100% rename from python/BioSimSpace/FreeEnergy/__init__.py rename to src/BioSimSpace/FreeEnergy/__init__.py index a71dee795..a62edca30 100644 --- a/python/BioSimSpace/FreeEnergy/__init__.py +++ b/src/BioSimSpace/FreeEnergy/__init__.py @@ -47,6 +47,6 @@ _sr.use_new_api() del _sr +from ._atm import * from ._relative import * from ._utils import * -from ._atm import * diff --git a/python/BioSimSpace/FreeEnergy/_atm.py b/src/BioSimSpace/FreeEnergy/_atm.py similarity index 99% rename from python/BioSimSpace/FreeEnergy/_atm.py rename to src/BioSimSpace/FreeEnergy/_atm.py index bf245bc99..b1f126f28 100644 --- a/python/BioSimSpace/FreeEnergy/_atm.py +++ b/src/BioSimSpace/FreeEnergy/_atm.py @@ -25,11 +25,8 @@ __all__ = ["ATMSetup", "ATM"] -from ..Notebook import View as _View from .. import _is_notebook - -if _is_notebook: - from IPython.display import FileLink as _FileLink +from ..Notebook import View as _View class ATMSetup: @@ -81,8 +78,8 @@ def __init__( If passing a pre-prepared system, the index of the free ligand molecule in the system (Default 2). """ - from .._SireWrappers import System as _System from .._SireWrappers import Molecule as _Molecule + from .._SireWrappers import System as _System # make sure that either system or protein, ligand_bound and ligand_free are given if system is None and not all( @@ -245,8 +242,8 @@ def _getLigandFree(self): def _setDisplacement(self, displacement): """Set the displacement of the free ligand along the normal vector.""" - from ..Types import Vector as _Vector from ..Types import Length as _Length + from ..Types import Vector as _Vector if isinstance(displacement, str): try: @@ -601,13 +598,14 @@ def _makeSystemFromThree(protein, ligand_bound, ligand_free, displacement): from ..Types import Vector as _Vector def _findTranslationVector(system, displacement, protein, ligand): + import warnings as _warnings + + from sire.legacy.Maths import Vector - from .._SireWrappers import System as _System - from ..Types import Length as _Length from .._SireWrappers import Molecule as _Molecule - import warnings as _warnings + from .._SireWrappers import System as _System from ..Types import Coordinate as _Coordinate - from sire.legacy.Maths import Vector + from ..Types import Length as _Length if not isinstance(system, _System): raise TypeError("system must be a BioSimSpace system") @@ -1012,10 +1010,11 @@ def viewRigidCores( ligand_free_rigid_core : list The indices for the rigid core atoms of the free ligand. """ - from .._SireWrappers import Molecule as _Molecule import json as _json import math as _math + from .._SireWrappers import Molecule as _Molecule + def move_to_origin(lig): from ..Types import Coordinate as _Coordinate @@ -1411,9 +1410,8 @@ def getData(self, name="data", file_link=False, work_dir=None): output : str, IPython.display.FileLink A path, or file link, to an archive of the process input. """ - from IPython.display import FileLink as _FileLink - import pathlib as _pathlib import os as _os + import pathlib as _pathlib import zipfile as _zipfile if self._work_dir is None: @@ -1457,6 +1455,8 @@ def getData(self, name="data", file_link=False, work_dir=None): # Return a link to the archive. if _is_notebook: if file_link: + from IPython.display import FileLink as _FileLink + # Create a FileLink to the archive. f_link = _FileLink(zipname) @@ -1483,12 +1483,13 @@ def _inititalise_runner(self, system): system : :class:`System ` The molecular system. """ - from ..Process import ProcessRunner as _ProcessRunner - from ..Process import OpenMM as _OpenMM - import os as _os import copy as _copy + import os as _os import shutil as _shutil + from ..Process import OpenMM as _OpenMM + from ..Process import ProcessRunner as _ProcessRunner + # This protocol will have to be minimal - cannot guess rigid core atoms if self._protocol is None: raise RuntimeError("No protocol has been set - cannot run simulations.") @@ -1717,8 +1718,8 @@ def __init__(self, handle, property_map={}, is_lambda1=False): super().__init__(handle, property_map, is_lambda1) def _create_view(self, system=None, view=None, gui=True, **kwargs): - from sire.legacy import IO as _SireIO + from .. import _isVerbose if system is None and view is None: diff --git a/python/BioSimSpace/FreeEnergy/_ddg.py b/src/BioSimSpace/FreeEnergy/_ddg.py similarity index 99% rename from python/BioSimSpace/FreeEnergy/_ddg.py rename to src/BioSimSpace/FreeEnergy/_ddg.py index 0ae746494..f81842ace 100644 --- a/python/BioSimSpace/FreeEnergy/_ddg.py +++ b/src/BioSimSpace/FreeEnergy/_ddg.py @@ -43,8 +43,8 @@ def _compute_kappa_hessian(ln_z, ln_q, factor, n): def _compute_kappa(ln_z, ln_q, factor, n): - import scipy.special as _special import numpy as _numpy + import scipy.special as _special ln_z = _numpy.insert(ln_z, 0, 0.0) @@ -103,8 +103,9 @@ def _estimate_f_i(ln_q, n_k): Returns: The estimated reduced free energies and their estimated variance. """ - import warnings as _warnings import functools as _functools + import warnings as _warnings + import numpy as _numpy import scipy.optimize as _optimize @@ -239,8 +240,8 @@ def analyse_UWHAM(work_dir, ignore_lower, ignore_upper, inflection_indices=None) ddg_total_error : :class:`BioSimSpace.Types.Energy` The error in the free energy. """ - import pandas as _pd import numpy as _numpy + import pandas as _pd # NOTE: This code is not designed to work with repex # It always assumes that each window is at the same temperature @@ -373,13 +374,15 @@ def analyse_MBAR(work_dir): Analyse the MBAR-compatible outputs. Adapted version of BioSimSpace _analyse_internal function """ - import numpy as _numpy - import pandas as _pd import os as _os import pathlib as _pathlib - from ._relative import Relative as _Relative + + import numpy as _numpy + import pandas as _pd from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol + from .. import Units as _Units + from ._relative import Relative as _Relative try: from alchemlyb.estimators import AutoMBAR as _AutoMBAR diff --git a/python/BioSimSpace/FreeEnergy/_relative.py b/src/BioSimSpace/FreeEnergy/_relative.py similarity index 97% rename from python/BioSimSpace/FreeEnergy/_relative.py rename to src/BioSimSpace/FreeEnergy/_relative.py index 3919d5efd..98801998a 100644 --- a/python/BioSimSpace/FreeEnergy/_relative.py +++ b/src/BioSimSpace/FreeEnergy/_relative.py @@ -42,39 +42,12 @@ _logger = _logging.getLogger("pymbar") _logger.setLevel(_logging.ERROR) - # Handle alchemlyb MBAR API changes. - try: - from alchemlyb.estimators import AutoMBAR as _AutoMBAR - except ImportError: - from alchemlyb.estimators import MBAR as _AutoMBAR - from alchemlyb.estimators import TI as _TI - from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol - from alchemlyb.parsing.amber import extract_dHdl as _amber_extract_dHdl - from alchemlyb.parsing.amber import extract_u_nk as _amber_extract_u_nk - from alchemlyb.parsing.gmx import extract_dHdl as _gmx_extract_dHdl - from alchemlyb.parsing.gmx import extract_u_nk as _gmx_extract_u_nk - from alchemlyb.preprocessing.subsampling import ( - equilibrium_detection as _equilibrium_detection, - ) - from alchemlyb.preprocessing.subsampling import ( - statistical_inefficiency as _statistical_inefficiency, - ) - from alchemlyb.preprocessing.subsampling import slicing as _slicing - from alchemlyb.preprocessing.subsampling import decorrelate_u_nk, decorrelate_dhdl - from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol - from alchemlyb.postprocessors.units import kJ2kcal as _kJ2kcal - from alchemlyb.postprocessors.units import R_kJmol as _R_kJmol - from sire.legacy.Base import getBinDir as _getBinDir from sire.legacy.Base import getShareDir as _getShareDir - from .. import _is_notebook from .._Exceptions import MissingSoftwareError as _MissingSoftwareError -if _is_notebook: - from IPython.display import FileLink as _FileLink - # Check that the analyse_freenrg script exists. if _sys.platform != "win32": _analyse_freenrg = _os.path.join(_getBinDir(), "analyse_freenrg") @@ -157,9 +130,9 @@ def __init__( Additional keyword arguments to pass to the underlying Process objects. """ - from .._SireWrappers import System as _System - from .. import _Utils from .. import Protocol as _Protocol + from .. import _Utils + from .._SireWrappers import System as _System # Validate the input. @@ -353,10 +326,10 @@ def getData(self, name="data", file_link=False, work_dir=None): output : str, IPython.display.FileLink A path, or file link, to an archive of the process input. """ + import pathlib as _pathlib import zipfile as _zipfile + from .._Utils import cd as _cd - import pathlib as _pathlib - from IPython.display import FileLink as _FileLink if self._work_dir is None: raise ValueError("'work_dir' must be set!") @@ -399,6 +372,8 @@ def getData(self, name="data", file_link=False, work_dir=None): # Return a link to the archive. if _is_notebook: if file_link: + from IPython.display import FileLink as _FileLink + # Create a FileLink to the archive. f_link = _FileLink(zipname) @@ -447,6 +422,7 @@ def analyse(work_dir, estimator="MBAR", method="alchemlyb", **kwargs): """ import pathlib as _pathlib import warnings as _warnings + from .._Exceptions import AnalysisError as _AnalysisError from .._Utils import _assert_imported @@ -478,7 +454,7 @@ def analyse(work_dir, estimator="MBAR", method="alchemlyb", **kwargs): if data and engine == "AMBER": if method != "ALCHEMLYB": raise _AnalysisError( - f"AMBER can only use the 'alchemlyb' analysis method." + "AMBER can only use the 'alchemlyb' analysis method." ) if data and engine == "SOMD" and estimator == "TI" and method == "native": raise _AnalysisError( @@ -487,7 +463,7 @@ def analyse(work_dir, estimator="MBAR", method="alchemlyb", **kwargs): if data and engine == "SOMD2": if method != "ALCHEMLYB": raise _AnalysisError( - f"SOMD2 can only use the 'alchemlyb' analysis method." + "SOMD2 can only use the 'alchemlyb' analysis method." ) if data and engine == "GROMACS" and method == "native": _warnings.warn( @@ -525,9 +501,10 @@ def checkOverlap(overlap, threshold=0.03): The number of off-diagonals that are less than the threshold value. """ - import numpy as _np import warnings as _warnings + import numpy as _np + if not isinstance(overlap, _np.matrix): raise TypeError("'overlap' must be of type 'numpy.matrix'.") @@ -582,6 +559,7 @@ def difference(pmf, pmf_ref=None): The relative free-energy difference and its associated error. """ import math as _math + from .. import Types as _Types from .. import Units as _Units @@ -693,13 +671,15 @@ def _get_data(files, temperatures, engine, estimator): data : list(pandas.DataFrame) A list of dataframes containing the data for each lambda window. """ - from alchemlyb.parsing.gmx import extract_u_nk as _gmx_extract_u_nk - from alchemlyb.parsing.amber import extract_dHdl as _amber_extract_dHdl import pathlib as _pathlib - from .._Exceptions import AnalysisError as _AnalysisError + + from alchemlyb.parsing.amber import extract_dHdl as _amber_extract_dHdl + from alchemlyb.parsing.amber import extract_u_nk as _amber_extract_u_nk from alchemlyb.parsing.gmx import extract_dHdl as _gmx_extract_dHdl + from alchemlyb.parsing.gmx import extract_u_nk as _gmx_extract_u_nk + from .. import _isVerbose - from alchemlyb.parsing.amber import extract_u_nk as _amber_extract_u_nk + from .._Exceptions import AnalysisError as _AnalysisError if not isinstance(files, (tuple, list)): raise TypeError("'files' must be of type 'list' or 'tuple'.") @@ -714,7 +694,7 @@ def _get_data(files, temperatures, engine, estimator): if not isinstance(engine, str): raise TypeError("'engine' must be of type 'str'.") engine = engine.replace(" ", "").upper() - if not engine in Relative._engines_analysis: + if engine not in Relative._engines_analysis: raise ValueError( f"Unsupported engine '{engine}'. Options are: {', '.join(Relative._engines_analysis)}" ) @@ -722,7 +702,7 @@ def _get_data(files, temperatures, engine, estimator): if not isinstance(estimator, str): raise TypeError("'estimator' must be of type 'str'.") estimator = estimator.replace(" ", "").upper() - if not estimator in ["MBAR", "TI"]: + if estimator not in ["MBAR", "TI"]: raise ValueError("'estimator' must be either 'MBAR' or 'TI'.") if estimator == "MBAR": @@ -857,10 +837,11 @@ def _somd_extract(simfile, T=None, estimator="MBAR"): frame (n) for MBAR, or dH/dl as a function of time for this lambda window for TI. """ - from alchemlyb.postprocessors.units import R_kJmol as _R_kJmol - import pandas as _pd import pathlib as _pathlib + import numpy as _np + import pandas as _pd + from alchemlyb.postprocessors.units import R_kJmol as _R_kJmol from alchemlyb.postprocessors.units import kJ2kcal as _kJ2kcal if not isinstance(simfile, _pathlib.Path): @@ -931,17 +912,17 @@ def _somd_extract(simfile, T=None, estimator="MBAR"): if not found_lambda: raise ValueError( - f"The lambda window was not detected in the SOMD output file: {file}" + f"The lambda window was not detected in the SOMD output file: {simfile}" ) if not found_array: raise ValueError( - f"The lambda array was not detected in the SOMD output file: {file}" + f"The lambda array was not detected in the SOMD output file: {simfile}" ) if not found_time: raise ValueError( - f"The simulation time was not detected in the SOMD output file: {file}" + f"The simulation time was not detected in the SOMD output file: {simfile}" ) # TODO: get header from the file instead of like this. @@ -959,7 +940,6 @@ def _somd_extract(simfile, T=None, estimator="MBAR"): ) time_step = sim_length / len(file_df["step"]) - time_rows = _np.arange(0, len(file_df["step"]), 1) time = _np.arange(0, sim_length, time_step) # For MBAR, results in list of lists where each list is the 0 to 1 @@ -1026,8 +1006,9 @@ def _somd2_extract(parquet_file, T=None, estimator="MBAR"): window for TI. """ import json as _json - import pandas as _pd import pathlib as _pathlib + + import pandas as _pd import pyarrow.parquet as _pq if not isinstance(parquet_file, _pathlib.Path): @@ -1159,12 +1140,13 @@ def _preprocess_data(data, estimator, **kwargs): Dataframe of dHdl or u_nk data processed using automated equilibration detection followed by statistical inefficiency. """ + import warnings as _warnings + + import pandas as _pd from alchemlyb.preprocessing.subsampling import ( - decorrelate_u_nk, decorrelate_dhdl, + decorrelate_u_nk, ) - import pandas as _pd - import warnings as _warnings from alchemlyb.preprocessing.subsampling import slicing as _slicing if not isinstance(data, (list, _pd.DataFrame)): @@ -1172,7 +1154,7 @@ def _preprocess_data(data, estimator, **kwargs): if not isinstance(estimator, str): raise TypeError("'estimator' must be of type 'str'.") - if not estimator.replace(" ", "").upper() in ["MBAR", "TI"]: + if estimator.replace(" ", "").upper() not in ["MBAR", "TI"]: raise ValueError("'estimator' must be either 'MBAR' or 'TI'.") # Assign defaults in case not passed via kwargs. @@ -1292,15 +1274,21 @@ def _analyse_internal(files, temperatures, lambdas, engine, estimator, **kwargs) window. Returns None if overlap isn't supported for the chosen estimator or engine. """ - from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol - from alchemlyb.estimators import TI as _TI - import numpy as _np import pathlib as _pathlib import warnings as _warnings - from .._Exceptions import AnalysisError as _AnalysisError + + import numpy as _np + + try: + from alchemlyb.estimators import AutoMBAR as _AutoMBAR + except ImportError: + from alchemlyb.estimators import MBAR as _AutoMBAR + from alchemlyb.estimators import TI as _TI + from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol + from .. import Units as _Units - from alchemlyb.estimators import MBAR as _AutoMBAR from .. import _isVerbose + from .._Exceptions import AnalysisError as _AnalysisError if not isinstance(files, (tuple, list)): raise TypeError("'files' must be of type 'list' or 'tuple'.") @@ -1319,7 +1307,7 @@ def _analyse_internal(files, temperatures, lambdas, engine, estimator, **kwargs) if not isinstance(engine, str): raise TypeError("'engine' must be of type 'str'.") - if not engine.replace(" ", "").upper() in Relative._engines_analysis: + if engine.replace(" ", "").upper() not in Relative._engines_analysis: raise ValueError( f"Unsupported engine '{engine}'. Options are: {', '.join(Relative._engines_analysis)}" ) @@ -1327,7 +1315,7 @@ def _analyse_internal(files, temperatures, lambdas, engine, estimator, **kwargs) if not isinstance(estimator, str): raise TypeError("'estimator' must be of type 'str'.") estimator = estimator.replace(" ", "").upper() - if not estimator in ["MBAR", "TI"]: + if estimator not in ["MBAR", "TI"]: raise ValueError("'estimator' must be either 'MBAR' or 'TI'.") if estimator == "MBAR": @@ -1450,8 +1438,8 @@ def _analyse_amber(work_dir=None, estimator="MBAR", method="alchemlyb", **kwargs For MBAR, this returns the overlap matrix for the overlap between each lambda window. For TI, this returns None. """ - import re as _re import pathlib as _pathlib + import re as _re if not isinstance(work_dir, str): raise TypeError("'work_dir' must be of type 'str'.") @@ -1541,13 +1529,13 @@ def _analyse_gromacs(work_dir=None, estimator="MBAR", method="alchemlyb", **kwar each lambda window. For TI, this returns None. """ import math as _math - import subprocess as _subprocess - from .. import _Utils import pathlib as _pathlib + import subprocess as _subprocess import warnings as _warnings - from .._Exceptions import AnalysisError as _AnalysisError + from .. import Units as _Units - from .. import _gmx_exe + from .. import _gmx_exe, _Utils + from .._Exceptions import AnalysisError as _AnalysisError if not isinstance(work_dir, str): raise TypeError("'work_dir' must be of type 'str'.") @@ -1556,7 +1544,7 @@ def _analyse_gromacs(work_dir=None, estimator="MBAR", method="alchemlyb", **kwar if not isinstance(estimator, str): raise TypeError("'estimator' must be of type 'str'.") - if not estimator.replace(" ", "").upper() in ["MBAR", "TI"]: + if estimator.replace(" ", "").upper() not in ["MBAR", "TI"]: raise ValueError("'estimator' must be either 'MBAR' or 'TI'.") if not isinstance(method, str): @@ -1723,13 +1711,15 @@ def _analyse_somd(work_dir=None, estimator="MBAR", method="alchemlyb", **kwargs) For MBAR, this returns the overlap matrix for the overlap between each lambda window. For TI, this returns None. """ - import subprocess as _subprocess - from .. import _Utils - import numpy as _np import pathlib as _pathlib - from .._Exceptions import AnalysisError as _AnalysisError + import subprocess as _subprocess import warnings as _warnings + + import numpy as _np + + from .. import _Utils from .. import Units as _Units + from .._Exceptions import AnalysisError as _AnalysisError if not isinstance(work_dir, str): raise TypeError("'work_dir' must be of type 'str'.") @@ -1745,7 +1735,7 @@ def _analyse_somd(work_dir=None, estimator="MBAR", method="alchemlyb", **kwargs) if not isinstance(method, str): raise TypeError("'method' must be of type 'str'.") method = method.replace(" ", "").upper() - if not method in ["ALCHEMLYB", "NATIVE"]: + if method not in ["ALCHEMLYB", "NATIVE"]: raise ValueError("'method' must be either 'alchemlyb' or 'native'.") if method == "ALCHEMLYB": @@ -1830,7 +1820,7 @@ def _analyse_somd(work_dir=None, estimator="MBAR", method="alchemlyb", **kwargs) % (_analyse_freenrg, work_dir, work_dir) ) proc = _subprocess.run( - _Util.command_split(command), + _Utils.command_split(command), shell=False, stdout=_subprocess.PIPE, stderr=_subprocess.PIPE, @@ -1918,10 +1908,11 @@ def _analyse_somd2(work_dir=None, estimator="MBAR", method="alchemlyb", **kwargs For MBAR, this returns the overlap matrix for the overlap between each lambda window. For TI, this returns None. """ - import pyarrow.parquet as _pq import json as _json import pathlib as _pathlib + import pyarrow.parquet as _pq + if not isinstance(work_dir, str): raise TypeError("'work_dir' must be of type 'str'.") if not _os.path.isdir(work_dir): @@ -2048,9 +2039,10 @@ def _initialise_runner(self, system): system : :class:`System ` The molecular system. """ + import copy as _copy import shutil as _shutil + from .. import Process as _Process - import copy as _copy # Initialise list to store the processe processes = [] diff --git a/python/BioSimSpace/FreeEnergy/_utils.py b/src/BioSimSpace/FreeEnergy/_utils.py similarity index 100% rename from python/BioSimSpace/FreeEnergy/_utils.py rename to src/BioSimSpace/FreeEnergy/_utils.py diff --git a/python/BioSimSpace/Gateway/__init__.py b/src/BioSimSpace/Gateway/__init__.py similarity index 100% rename from python/BioSimSpace/Gateway/__init__.py rename to src/BioSimSpace/Gateway/__init__.py index d6476fd23..3493ffe6c 100644 --- a/python/BioSimSpace/Gateway/__init__.py +++ b/src/BioSimSpace/Gateway/__init__.py @@ -54,8 +54,8 @@ """ from ._node import * -from ._resources import * from ._requirements import * +from ._resources import * # Create and initialise the hardware resource manager. ResourceManager = ResourceManager() diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py b/src/BioSimSpace/Gateway/_node.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py rename to src/BioSimSpace/Gateway/_node.py index b6afdef8c..66d6f45a2 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py +++ b/src/BioSimSpace/Gateway/_node.py @@ -26,26 +26,18 @@ __all__ = ["Node"] -from .._Utils import _try_import - import configargparse as _argparse +from .._Utils import _try_import + _yaml = _try_import("yaml") from .. import _is_notebook -# Enable Jupyter widgets. -if _is_notebook: - from IPython.display import FileLink as _FileLink - - import ipywidgets as _widgets - import zipfile as _zipfile - - from ._requirements import Area as _Area -from ._requirements import Float as _Float from ._requirements import Charge as _Charge from ._requirements import Energy as _Energy +from ._requirements import Float as _Float from ._requirements import Length as _Length from ._requirements import Mass as _Mass from ._requirements import Pressure as _Pressure @@ -106,14 +98,16 @@ def bind_node(cls, node): def __call__(self, parser, namespace, values, option_string=None): """Export the CWL wrapper.""" + import os as _os + import sys as _sys + + import __main__ + from ._requirements import Boolean as _Boolean - from ._requirements import FileSet as _FileSet from ._requirements import File as _File + from ._requirements import FileSet as _FileSet from ._requirements import Integer as _Integer - import sys as _sys from ._requirements import String as _String - import __main__ - import os as _os if values == False: parser.exit() @@ -132,7 +126,6 @@ def __call__(self, parser, namespace, values, option_string=None): exe = _sys.executable # Store the absolute path of the node. - import __main__ node = _os.path.abspath(__main__.__file__) @@ -292,9 +285,10 @@ def __init__(self, description, name=None): The name of the node. """ import collections as _collections - import __main__ import os as _os + import __main__ + if not isinstance(description, str): raise TypeError("The 'description' keyword must be of type 'str'.") @@ -425,9 +419,10 @@ def addInput(self, name, input): input : :class:`Requirement ` The input requirement object. """ - from ._requirements import Requirement as _Requirement import warnings as _warnings + from ._requirements import Requirement as _Requirement + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -595,12 +590,13 @@ def _addInputJupyter(self, name, input, reset=False): reset : bool Whether to reset the widget data. """ + import ipywidgets as _widgets + + from ..Types._type import Type as _Type from ._requirements import Boolean as _Boolean from ._requirements import File as _File - from ._requirements import Integer as _Integer - import ipywidgets as _widgets from ._requirements import FileSet as _FileSet - from ..Types._type import Type as _Type + from ._requirements import Integer as _Integer from ._requirements import String as _String # Create a widget button to indicate whether the requirement value @@ -953,9 +949,10 @@ def addOutput(self, name, output): output : :class:`Requirement ` The output requirement object. """ - from ._requirements import Requirement as _Requirement import warnings as _warnings + from ._requirements import Requirement as _Requirement + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -986,11 +983,12 @@ def setOutput(self, name, value): value : The value of the output. """ - from ._requirements import FileSet as _FileSet - from ._requirements import File as _File + import os as _os import shutil as _shutil import warnings as _warnings - import os as _os + + from ._requirements import File as _File + from ._requirements import FileSet as _FileSet try: # Enforce strict naming for all file-based outputs. This ensures @@ -1134,7 +1132,7 @@ def addAuthor(self, name=None, email=None, affiliation=None): self._authors = [{"name": name, "email": email, "affiliation": affiliation}] else: author = {"name": name, "email": email, "affiliation": affiliation} - if not author in self._authors: + if author not in self._authors: self._authors.append(author) def getAuthors(self): @@ -1263,6 +1261,7 @@ def showControls(self): def _validateInput(self): """Validate the parsed inputs.""" import sys as _sys + from .. import setVerbose # Knime. @@ -1314,7 +1313,7 @@ def _validateInput(self): if value is True: self._strict_file_naming = True else: - if not key in ["config", "export_cwl"]: + if key not in ["config", "export_cwl"]: self._inputs[key].setValue(value, name=key) def validate(self, file_prefix="output"): @@ -1335,12 +1334,12 @@ def validate(self, file_prefix="output"): validated output, else the name of a YAML file containing the node output. """ - from ._requirements import FileSet as _FileSet - from ._requirements import File as _File - import zipfile as _zipfile - import sys as _sys - from IPython.display import FileLink as _FileLink import os as _os + import sys as _sys + import zipfile as _zipfile + + from ._requirements import File as _File + from ._requirements import FileSet as _FileSet if not isinstance(file_prefix, str): raise TypeError("The 'file_prefix' keyword must be of type 'str'.") @@ -1371,6 +1370,8 @@ def validate(self, file_prefix="output"): # Create a compressed archive containing all file output for the node. if self._is_notebook: + from IPython.display import FileLink as _FileLink + # There are files. if len(file_outputs) > 0: # Create the archive name. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py b/src/BioSimSpace/Gateway/_requirements.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py rename to src/BioSimSpace/Gateway/_requirements.py index 7af15b219..0ca478fb0 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py +++ b/src/BioSimSpace/Gateway/_requirements.py @@ -2020,12 +2020,12 @@ def _unarchive(name): files : [ str ] A list of file names. """ - import zipfile as _zipfile - import shutil as _shutil - import os as _os import bz2 as _bz2 import gzip as _gzip + import os as _os + import shutil as _shutil import tarfile as _tarfile + import zipfile as _zipfile # Get the directory name. dir = _os.path.dirname(name) diff --git a/python/BioSimSpace/Gateway/_resources.py b/src/BioSimSpace/Gateway/_resources.py similarity index 97% rename from python/BioSimSpace/Gateway/_resources.py rename to src/BioSimSpace/Gateway/_resources.py index 1ce0b14c7..4af26a3c4 100644 --- a/python/BioSimSpace/Gateway/_resources.py +++ b/src/BioSimSpace/Gateway/_resources.py @@ -99,7 +99,7 @@ def setNodes(self, nodes): The number of nodes. """ - if not type(nodes) is int: + if type(nodes) is not int: raise TypeError("'nodes' must be of type 'int'.") if nodes < 0: @@ -130,7 +130,7 @@ def setCPUs(self, cpus): The number of cpus. """ - if not type(cpus) is int: + if type(cpus) is not int: raise TypeError("'cpus' must be of type 'int'.") if cpus < 0: @@ -161,7 +161,7 @@ def setGPUs(self, gpus): The number of GPUs. """ - if not type(gpus) is int: + if type(gpus) is not int: raise TypeError("'gpus' must be of type 'int'.") if gpus < 0: diff --git a/python/BioSimSpace/IO/__init__.py b/src/BioSimSpace/IO/__init__.py similarity index 100% rename from python/BioSimSpace/IO/__init__.py rename to src/BioSimSpace/IO/__init__.py index 00865a000..56f5abd5d 100644 --- a/python/BioSimSpace/IO/__init__.py +++ b/src/BioSimSpace/IO/__init__.py @@ -45,5 +45,5 @@ _sr.use_new_api() del _sr -from ._io import * from ._file_cache import * +from ._io import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py b/src/BioSimSpace/IO/_file_cache.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py rename to src/BioSimSpace/IO/_file_cache.py index 0d6d19671..7671bd8dd 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py +++ b/src/BioSimSpace/IO/_file_cache.py @@ -162,6 +162,7 @@ def _check_cache( """ import os as _os import shutil as _shutil + from .._SireWrappers import System as _System # Validate input. @@ -204,7 +205,7 @@ def _check_cache( # Get the existing file path and MD5 hash from the cache. try: - (prev_system, path, original_hash) = _cache[key] + prev_system, path, original_hash = _cache[key] except: return False @@ -293,6 +294,7 @@ def _update_cache( Whether to skip water molecules when comparing systems. """ import os as _os + from .._SireWrappers import System as _System # Validate input. diff --git a/python/BioSimSpace/IO/_io.py b/src/BioSimSpace/IO/_io.py similarity index 99% rename from python/BioSimSpace/IO/_io.py rename to src/BioSimSpace/IO/_io.py index 79b6f32c6..d13496dda 100644 --- a/python/BioSimSpace/IO/_io.py +++ b/src/BioSimSpace/IO/_io.py @@ -37,7 +37,6 @@ from collections import OrderedDict as _OrderedDict - # Flag that we've not yet raised a warning about GROMACS not being installed. _has_gmx_warned = False @@ -230,12 +229,12 @@ def readPDB(id, pdb4amber=False, work_dir=None, show_warnings=False, property_ma >>> import BioSimSpace as BSS >>> system = BSS.IO.readPDB("file.pdb", pdb4amber=True) """ + import os as _os import subprocess as _subprocess - from .._SireWrappers import System as _System + + from .. import _amber_home, _Utils from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from .. import _amber_home - import os as _os - from .. import _Utils + from .._SireWrappers import System as _System if not isinstance(id, str): raise TypeError("'id' must be of type 'str'") @@ -408,14 +407,14 @@ def readMolecules( >>> import BioSimSpace as BSS >>> system = BSS.IO.readMolecules(["mol.gro87", "mol.grotop"], property_map={"GROMACS_PATH" : "/path/to/gromacs/topology"}) """ - from .. import _gmx_path - from .._SireWrappers import System as _System + import os as _os + import warnings as _warnings from glob import glob as _glob + from sire.legacy import Base as _SireBase - import warnings as _warnings - import os as _os - from .. import _Utils - from .. import _isVerbose + + from .. import _gmx_path, _isVerbose, _Utils + from .._SireWrappers import System as _System global _has_gmx_warned if _gmx_path is None and not _has_gmx_warned: @@ -655,17 +654,16 @@ def saveMolecules( >>> system = BSS.IO.readMolecules(files, property_map={"charge" : "my-charge"}) >>> BSS.IO.saveMolecules("test", system, ["gro87", "grotop"], property_map={"charge" : "my-charge"}) """ - from .. import _gmx_path - from ._file_cache import _cache_active - from .._SireWrappers import System as _System - from .._SireWrappers import Molecules as _Molecules - from ._file_cache import _update_cache - from sire.legacy import Base as _SireBase - import warnings as _warnings import os as _os + import warnings as _warnings + + from sire.legacy import Base as _SireBase + + from .. import _gmx_path, _isVerbose from .._SireWrappers import Molecule as _Molecule - from .. import _isVerbose - from ._file_cache import _check_cache + from .._SireWrappers import Molecules as _Molecules + from .._SireWrappers import System as _System + from ._file_cache import _cache_active, _check_cache, _update_cache global _has_gmx_warned if _gmx_path is None and not _has_gmx_warned: @@ -908,9 +906,9 @@ def savePerturbableSystem(filebase, system, save_velocities=True, property_map={ values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .._SireWrappers import System as _System from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Molecules as _Molecules + from .._SireWrappers import System as _System # Check that the filebase is a string. if not isinstance(filebase, str): @@ -1014,9 +1012,10 @@ def readPerturbableSystem(top0, coords0, top1, coords1, property_map={}): system : :class:`System ` A molecular system. """ + from sire.legacy import Base as _SireBase + from .. import _isVerbose from .._SireWrappers import Molecule as _Molecule - from sire.legacy import Base as _SireBase if not isinstance(top0, str): raise TypeError("'top0' must be of type 'str'.") diff --git a/python/BioSimSpace/MD/__init__.py b/src/BioSimSpace/MD/__init__.py similarity index 100% rename from python/BioSimSpace/MD/__init__.py rename to src/BioSimSpace/MD/__init__.py diff --git a/python/BioSimSpace/MD/_md.py b/src/BioSimSpace/MD/_md.py similarity index 98% rename from python/BioSimSpace/MD/_md.py rename to src/BioSimSpace/MD/_md.py index 3a4ac7913..0662b8077 100644 --- a/python/BioSimSpace/MD/_md.py +++ b/src/BioSimSpace/MD/_md.py @@ -27,7 +27,7 @@ __all__ = ["run"] -from .. import _amber_home, _gmx_exe +from .. import _gmx_exe # A dictionary mapping MD engines to their executable names and GPU support. # engine, exe, gpu @@ -39,7 +39,7 @@ "sander": False, }, "GROMACS": {"gmx": True, "gmx_mpi": True}, - "NAMD": {"namd2": False}, + "NAMD": {"namd3": True, "namd2": False}, "OPENMM": {"sire_python": True}, "SOMD": {"somd": True}, } @@ -115,20 +115,20 @@ def _find_md_engines(system, protocol, engine="AUTO", gpu_support=False): engines, exes : [ str ], [ str ] Lists containing the supported MD engines and executables. """ - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from sire.legacy import Base as _SireBase import os as _os - from .. import _gmx_exe + + from sire.legacy import Base as _SireBase + from .. import Protocol as _Protocol + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError # The input has already been validated in the run method, so no need # to re-validate here. - # Get the file format of the molecular system. fileformat = system.fileFormat() # Make sure that this format is supported. - if not fileformat in _file_extensions: + if fileformat not in _file_extensions: raise ValueError( "Cannot find an MD engine that supports format: %s" % fileformat ) @@ -300,10 +300,10 @@ def run( process : :class:`Process ` A process to run the molecular dynamics protocol. """ - from .._SireWrappers import System as _System - from .._Exceptions import IncompatibleError as _IncompatibleError from .. import Process as _Process from .. import Protocol as _Protocol + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import System as _System # Check that the system is valid. if not isinstance(system, _System): @@ -347,7 +347,7 @@ def run( raise TypeError("'work_dir' must be of type 'str'") if seed is not None: - if not type(seed) is int: + if type(seed) is not int: raise TypeError("'seed' must be of type 'int'") if not isinstance(property_map, dict): diff --git a/python/BioSimSpace/MD/_utils.py b/src/BioSimSpace/MD/_utils.py similarity index 100% rename from python/BioSimSpace/MD/_utils.py rename to src/BioSimSpace/MD/_utils.py diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/__init__.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/__init__.py similarity index 100% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/__init__.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/__init__.py diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_collective_variable.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_collective_variable.py similarity index 100% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_collective_variable.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_collective_variable.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py index e6c0a3204..5d0235071 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py +++ b/src/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py @@ -27,8 +27,8 @@ __all__ = ["Distance"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Distance(_CollectiveVariable): diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py similarity index 99% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py index 538ec00e8..49b21dc2e 100644 --- a/python/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py +++ b/src/BioSimSpace/Metadynamics/CollectiveVariable/_funnel.py @@ -27,10 +27,10 @@ __all__ = ["Funnel", "makeFunnel", "viewFunnel"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable +from ...Types import Length as _Length from .._bound import Bound as _Bound from .._grid import Grid as _Grid -from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Funnel(_CollectiveVariable): @@ -519,6 +519,7 @@ def getCorrection( The funnel correction. """ import math as _math + from ...Types import Energy as _Energy from ...Types import Volume as _Volume @@ -746,14 +747,14 @@ def makeFunnel( atoms1 : [int] A list of atom indices that define the inflection point of the funnel. """ + from sire.legacy.Maths import Vector as _SireVector + from ..._Exceptions import IncompatibleError as _IncompatibleError from ..._SireWrappers import Molecule as _Molecule - from sire.legacy.Maths import Vector as _SireVector from ..._SireWrappers import System as _System from ...Types import Coordinate as _Coordinate # Validate the input. - # System. if not isinstance(system, _System): raise TypeError("'system' must be of type 'BioSimSpace._SireWrappers.System'.") @@ -1017,14 +1018,14 @@ def viewFunnel(system, collective_variable, property_map={}): view : :class:`View ` A view object showing the system and funnel. """ - from ..._SireWrappers import Molecule as _Molecule - from ... import _is_notebook + import sire.legacy.Mol as _SireMol from sire.legacy.Maths import Vector as _SireVector + + from ... import _is_notebook + from ..._SireWrappers import Molecule as _Molecule from ..._SireWrappers import System as _System - import sire.legacy.Mol as _SireMol # The following is adapted from funnel_maker.py by Dominykas Lukauskis. - # Don't do anything if this isn't called from within a notebook. if not _is_notebook: return None diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py similarity index 99% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py index e649c105f..ae59b3be3 100644 --- a/python/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py +++ b/src/BioSimSpace/Metadynamics/CollectiveVariable/_rmsd.py @@ -27,8 +27,8 @@ __all__ = ["RMSD"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class RMSD(_CollectiveVariable): @@ -102,14 +102,15 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ..._Exceptions import IncompatibleError as _IncompatibleError - from ..._SireWrappers import Atom as _Atom - from sire.mol import selection_to_atoms as _selection_to_atoms from sire.legacy import IO as _SireIO - from ..._SireWrappers import System as _System - from ..._SireWrappers import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from sire.mol import selection_to_atoms as _selection_to_atoms + from ... import _isVerbose + from ..._Exceptions import IncompatibleError as _IncompatibleError + from ..._SireWrappers import Atom as _Atom + from ..._SireWrappers import Molecule as _Molecule + from ..._SireWrappers import System as _System # Call the base class constructor. super().__init__() @@ -334,7 +335,7 @@ def __init__( # Also strip any TER records. self._reference_pdb = [] for line, idx in zip(lines[1:-2], abs_atom_indices): - if not "TER" in line: + if "TER" not in line: self._reference_pdb.append(line[:6] + str(idx).rjust(5) + line[11:]) self._reference_pdb.append(lines[-1]) @@ -579,10 +580,12 @@ def _compute_initial_rmsd( The initial value of the RMSD. """ from math import sqrt as _sqrt - from ...Align import rmsdAlign as _rmsdAlign - from ..._SireWrappers import System as _System + from sire.legacy import Mol as _SireMol + from ..._SireWrappers import System as _System + from ...Align import rmsdAlign as _rmsdAlign + # Note that we need to do this manually, since Sire.Mol.Evaluator doesn't # work correctly for molecules with different numbers of coordinate groups. @@ -675,7 +678,7 @@ def _compute_initial_rmsd( i.value(): i.value() for i in align_indices[ref._sire_object.number()] } - except Exception as e: + except Exception: pass if len(align_mapping) > 0: @@ -696,7 +699,7 @@ def _compute_initial_rmsd( try: rmsd_mapping = {i: i for i in rmsd_indices[ref._sire_object.number()]} - except Exception as e: + except Exception: pass if len(rmsd_mapping) > 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py index 5442cc58b..2c26bc9f5 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py +++ b/src/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py @@ -27,8 +27,8 @@ __all__ = ["Torsion"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Angle as _Angle +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Torsion(_CollectiveVariable): @@ -231,9 +231,9 @@ def getPeriodicBoundaries(self): def _validate(self): """Internal function to check that the object is in a consistent state.""" - from math import pi as _pi from math import ceil as _ceil from math import isclose as _isclose + from math import pi as _pi if self._lower_bound is not None: if not isinstance(self._lower_bound.getValue(), _Angle): diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_utils.py b/src/BioSimSpace/Metadynamics/CollectiveVariable/_utils.py similarity index 100% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_utils.py rename to src/BioSimSpace/Metadynamics/CollectiveVariable/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py b/src/BioSimSpace/Metadynamics/__init__.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py rename to src/BioSimSpace/Metadynamics/__init__.py index 0ab6d284f..3e692922a 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py +++ b/src/BioSimSpace/Metadynamics/__init__.py @@ -47,10 +47,9 @@ _sr.use_new_api() del _sr +from . import CollectiveVariable from ._bound import * from ._grid import * from ._metadynamics import * from ._restraint import * from ._utils import * - -from . import CollectiveVariable diff --git a/python/BioSimSpace/Metadynamics/_aux/ProjectionOnAxis.cpp b/src/BioSimSpace/Metadynamics/_aux/ProjectionOnAxis.cpp similarity index 100% rename from python/BioSimSpace/Metadynamics/_aux/ProjectionOnAxis.cpp rename to src/BioSimSpace/Metadynamics/_aux/ProjectionOnAxis.cpp diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py b/src/BioSimSpace/Metadynamics/_aux/metadynamics.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py rename to src/BioSimSpace/Metadynamics/_aux/metadynamics.py index 25aca07ef..e6f283d58 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py +++ b/src/BioSimSpace/Metadynamics/_aux/metadynamics.py @@ -31,7 +31,7 @@ from collections import namedtuple try: - import numpy as np + pass except: pass @@ -108,9 +108,9 @@ def __init__( the directory to which biases should be written, and from which biases written by other processes should be loaded """ - from openmm import unit import numpy as np import openmm as mm + from openmm import unit if not unit.is_quantity(temperature): temperature = temperature * unit.kelvin @@ -200,8 +200,8 @@ def step(self, simulation, steps): steps : int the number of time steps to integrate """ - from openmm import unit import numpy as np + from openmm import unit stepsToGo = steps while stepsToGo > 0: @@ -251,8 +251,8 @@ def getCollectiveVariables(self, simulation): def getHillHeight(self, simulation): """Get the current height of the Gaussian hill in kJ/mol.""" - from openmm import unit import numpy as np + from openmm import unit energy = simulation.context.getState( getEnergy=True, groups={31} @@ -266,9 +266,10 @@ def getHillHeight(self, simulation): def _addGaussian(self, position, height, context): """Add a Gaussian to the bias function.""" - from openmm import unit from functools import reduce + import numpy as np + from openmm import unit # Compute a Gaussian along each axis. @@ -305,8 +306,9 @@ def _addGaussian(self, position, height, context): def _syncWithDisk(self): """Save biases to disk, and check for updated files created by other processes.""" - import re import os + import re + import numpy as np if self.biasDir is None: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py b/src/BioSimSpace/Metadynamics/_bound.py similarity index 98% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py rename to src/BioSimSpace/Metadynamics/_bound.py index 02e40df37..45cb5428f 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py +++ b/src/BioSimSpace/Metadynamics/_bound.py @@ -98,7 +98,7 @@ def setValue(self, value): """ from ..Types._type import Type as _Type - if not isinstance(value, (float, _Type)) and not type(value) is int: + if not isinstance(value, (float, _Type)) and type(value) is not int: raise TypeError( "'value' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Metadynamics/_grid.py b/src/BioSimSpace/Metadynamics/_grid.py similarity index 97% rename from python/BioSimSpace/Metadynamics/_grid.py rename to src/BioSimSpace/Metadynamics/_grid.py index cbd460878..db378c3ef 100644 --- a/python/BioSimSpace/Metadynamics/_grid.py +++ b/src/BioSimSpace/Metadynamics/_grid.py @@ -94,7 +94,7 @@ def setMinimum(self, minimum): """ from ..Types._type import Type as _Type - if not isinstance(minimum, (float, _Type)) and not type(minimum) is int: + if not isinstance(minimum, (float, _Type)) and type(minimum) is not int: raise TypeError( "'minimum' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) @@ -130,7 +130,7 @@ def setMaximum(self, maximum): """ from ..Types._type import Type as _Type - if not isinstance(maximum, (float, _Type)) and not type(maximum) is int: + if not isinstance(maximum, (float, _Type)) and type(maximum) is not int: raise TypeError( "'maximum' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py b/src/BioSimSpace/Metadynamics/_metadynamics.py similarity index 97% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py rename to src/BioSimSpace/Metadynamics/_metadynamics.py index e1105d9fc..fdb073051 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py +++ b/src/BioSimSpace/Metadynamics/_metadynamics.py @@ -28,7 +28,7 @@ # Import common objects from BioSimSpace.MD._md -from ..MD._md import _file_extensions, _md_engines, _find_md_engines +from ..MD._md import _find_md_engines def run( @@ -89,10 +89,9 @@ def run( process : :class:`Process ` A process to run the molecular dynamics protocol. """ + from .. import Process as _Process from .. import Protocol as _Protocol from .._SireWrappers import System as _System - from .. import Process as _Process - from ..MD._md import _find_md_engines # Check that the system is valid. if not isinstance(system, _System): @@ -124,7 +123,7 @@ def run( raise TypeError("'work_dir' must be of type 'str'") if seed is not None: - if not type(seed) is int: + if type(seed) is not int: raise TypeError("'seed' must be of type 'int'") if not isinstance(property_map, dict): diff --git a/python/BioSimSpace/Metadynamics/_restraint.py b/src/BioSimSpace/Metadynamics/_restraint.py similarity index 98% rename from python/BioSimSpace/Metadynamics/_restraint.py rename to src/BioSimSpace/Metadynamics/_restraint.py index 137ddfcc0..646258c1f 100644 --- a/python/BioSimSpace/Metadynamics/_restraint.py +++ b/src/BioSimSpace/Metadynamics/_restraint.py @@ -91,7 +91,7 @@ def setValue(self, value): """ from ..Types._type import Type as _Type - if not isinstance(value, (float, _Type)) and not type(value) is int: + if not isinstance(value, (float, _Type)) and type(value) is not int: raise TypeError( "'value' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Metadynamics/_utils.py b/src/BioSimSpace/Metadynamics/_utils.py similarity index 100% rename from python/BioSimSpace/Metadynamics/_utils.py rename to src/BioSimSpace/Metadynamics/_utils.py diff --git a/python/BioSimSpace/Node/__init__.py b/src/BioSimSpace/Node/__init__.py similarity index 100% rename from python/BioSimSpace/Node/__init__.py rename to src/BioSimSpace/Node/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Node/_node.py b/src/BioSimSpace/Node/_node.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Node/_node.py rename to src/BioSimSpace/Node/_node.py index 9bd3809fe..d1595a538 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Node/_node.py +++ b/src/BioSimSpace/Node/_node.py @@ -1,8 +1,7 @@ -from .._Utils import _try_import - - import os as _os +from .._Utils import _try_import + _yaml = _try_import("yaml") @@ -35,10 +34,12 @@ def help(name): name : str The name of the node. """ - from .. import _Utils import subprocess as _subprocess + from sire.legacy import Base as _SireBase + from .. import _Utils + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -91,10 +92,12 @@ def run(name, args={}, work_dir=None): output : dict A dictionary containing the output of the node. """ - from .. import _Utils import subprocess as _subprocess + from sire.legacy import Base as _SireBase + from .. import _Utils + # Validate the input. if not isinstance(name, str): diff --git a/python/BioSimSpace/Notebook/__init__.py b/src/BioSimSpace/Notebook/__init__.py similarity index 100% rename from python/BioSimSpace/Notebook/__init__.py rename to src/BioSimSpace/Notebook/__init__.py diff --git a/python/BioSimSpace/Notebook/_plot.py b/src/BioSimSpace/Notebook/_plot.py similarity index 99% rename from python/BioSimSpace/Notebook/_plot.py rename to src/BioSimSpace/Notebook/_plot.py index 208d9e5eb..c7697ca70 100644 --- a/python/BioSimSpace/Notebook/_plot.py +++ b/src/BioSimSpace/Notebook/_plot.py @@ -41,8 +41,8 @@ if _display is not None: _has_display = True try: - import matplotlib.pyplot as _plt import matplotlib.colors as _colors + import matplotlib.pyplot as _plt _has_matplotlib = True except ImportError: @@ -50,8 +50,8 @@ else: if _is_notebook: try: - import matplotlib.pyplot as _plt import matplotlib.colors as _colors + import matplotlib.pyplot as _plt _has_matplotlib = True except ImportError: @@ -119,9 +119,10 @@ def plot( logy : bool Whether the y axis is logarithmic. """ - from ..Types._type import Type as _Type from warnings import warn as _warn + from .. import _is_interactive + from ..Types._type import Type as _Type # Make sure were running interactively. if not _is_interactive: @@ -355,16 +356,15 @@ def plotContour(x, y, z, xlabel=None, ylabel=None, zlabel=None): zlabel : str The z axis label string. """ - import numpy as _np from warnings import warn as _warn - from ..Types._type import Type as _Type - from .. import _is_interactive import numpy as _np import scipy.interpolate as _interp - from mpl_toolkits.axes_grid1 import make_axes_locatable as _make_axes_locatable + from .. import _is_interactive + from ..Types._type import Type as _Type + # Make sure were running interactively. if not _is_interactive: _warn("You can only use BioSimSpace.Notebook.plot when running interactively.") @@ -501,7 +501,7 @@ def plotContour(x, y, z, xlabel=None, ylabel=None, zlabel=None): # Convert to two-dimensional arrays. We don't assume the data is on a grid, # so we interpolate the z values. try: - (X, Y) = _np.meshgrid( + X, Y = _np.meshgrid( _np.linspace(_np.min(x), _np.max(x), 1000), _np.linspace(_np.min(y), _np.max(y), 1000), ) @@ -561,9 +561,11 @@ def plotOverlapMatrix( matrix. This is used for both the continuous and discrete color bars. Can not contain more than 3 elements. """ - import numpy as _np - import matplotlib.colors as _colors from warnings import warn as _warn + + import matplotlib.colors as _colors + import numpy as _np + from .. import _is_interactive # Make sure were running interactively. diff --git a/python/BioSimSpace/Notebook/_view.py b/src/BioSimSpace/Notebook/_view.py similarity index 99% rename from python/BioSimSpace/Notebook/_view.py rename to src/BioSimSpace/Notebook/_view.py index fe5e1355b..e6ba6ca1f 100644 --- a/python/BioSimSpace/Notebook/_view.py +++ b/src/BioSimSpace/Notebook/_view.py @@ -55,12 +55,13 @@ def __init__(self, handle, property_map={}, is_lambda1=False): perturbable molecules. By default, the state at lambda = 0 is used. """ - from .. import IO as _IO + import tempfile as _tempfile import warnings as _warnings - from .._SireWrappers import System as _System + + from .. import IO as _IO from .. import _is_notebook + from .._SireWrappers import System as _System from ..Process._process import Process as _Process - import tempfile as _tempfile # Make sure we're running inside a Jupyter notebook. if not _is_notebook: @@ -179,9 +180,10 @@ def molecules(self, indices=None, gui=True): gui : bool Whether to display the gui. """ - from .. import _is_notebook - from sire.legacy import System as _SireSystem from sire.legacy import Mol as _SireMol + from sire.legacy import System as _SireSystem + + from .. import _is_notebook # Make sure we're running inside a Jupyter notebook. if not _is_notebook: @@ -253,16 +255,17 @@ def molecule(self, index=0, gui=True): gui : bool Whether to display the gui. """ - from .. import _is_notebook - from sire.legacy import System as _SireSystem from sire.legacy import Mol as _SireMol + from sire.legacy import System as _SireSystem + + from .. import _is_notebook # Make sure we're running inside a Jupyter notebook. if not _is_notebook: return None # Check that the index is an integer. - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") # Get the latest system from the process. @@ -326,7 +329,7 @@ def reload(self, index=None, gui=True): index = self._num_views - 1 # Check that the index is an integer. - elif not type(index) is int: + elif type(index) is not int: raise TypeError("'index' must be of type 'int'") # Make sure the view index is valid. @@ -363,9 +366,10 @@ def savePDB(self, file, index=None): index : int The view index. """ - from .. import _is_notebook import shutil as _shutil + from .. import _is_notebook + # Make sure we're running inside a Jupyter notebook. if not _is_notebook: return None @@ -375,7 +379,7 @@ def savePDB(self, file, index=None): index = self._num_views - 1 # Check that the index is an integer. - elif not type(index) is int: + elif type(index) is not int: raise TypeError("'index' must be of type 'int'") # Make sure the view index is valid. @@ -418,9 +422,10 @@ def _create_view(self, system=None, view=None, gui=True): gui : bool Whether to display the gui. """ - from .. import _isVerbose from sire.legacy import IO as _SireIO + from .. import _isVerbose + if system is None and view is None: raise ValueError("Both 'system' and 'view' cannot be 'None'.") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py b/src/BioSimSpace/Parameters/_Protocol/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py rename to src/BioSimSpace/Parameters/_Protocol/__init__.py index 1484d54df..485711d31 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py +++ b/src/BioSimSpace/Parameters/_Protocol/__init__.py @@ -24,6 +24,6 @@ Author: Lester Hedges . """ -from ._protocol import Protocol as _Protocol from ._amber import * from ._openforcefield import * +from ._protocol import Protocol as _Protocol diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py b/src/BioSimSpace/Parameters/_Protocol/_amber.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py rename to src/BioSimSpace/Parameters/_Protocol/_amber.py index c03db4e36..c2a77cb50 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py +++ b/src/BioSimSpace/Parameters/_Protocol/_amber.py @@ -34,11 +34,11 @@ import os as _os import subprocess as _subprocess -from ..._Utils import _try_import, _have_imported - # Temporarily redirect stderr to suppress import warnings. import sys as _sys +from ..._Utils import _have_imported, _try_import + _orig_stderr = _sys.stderr _sys.stderr = open(_os.devnull, "w") @@ -54,10 +54,8 @@ del _sys, _orig_stderr -from ... import _amber_home -from ... import _Utils +from ... import _amber_home, _Utils from ...Types import Length as _Length - from . import _protocol # Set the tLEaP cmd directory. @@ -297,13 +295,14 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ + import queue as _queue + + from ... import IO as _IO + from ... import _gmx_exe, _isVerbose from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..._Exceptions import ThirdPartyError as _ThirdPartyError - from ... import _gmx_exe, _isVerbose - import queue as _queue from ..._SireWrappers import Molecule as _Molecule from ...Convert import smiles as _smiles - from ... import IO as _IO if not isinstance(molecule, (_Molecule, str)): raise TypeError( @@ -427,11 +426,12 @@ def _run_tleap(self, molecule, work_dir): work_dir : str The working directory. """ - from ... import _isVerbose from sire.legacy import IO as _SireIO + + from ... import IO as _IO + from ... import _isVerbose from ..._Exceptions import ParameterisationError as _ParameterisationError from ..._SireWrappers import Molecule as _Molecule - from ... import IO as _IO # Write the system to a PDB file. try: @@ -566,10 +566,10 @@ def _run_pdb2gmx(self, molecule, work_dir): work_dir : str The working directory. """ - from ... import _gmx_exe, _isVerbose - from ..._Exceptions import ParameterisationError as _ParameterisationError from ... import IO as _IO + from ... import _gmx_exe, _isVerbose from ..._Exceptions import IncompatibleError as _IncompatibleError + from ..._Exceptions import ParameterisationError as _ParameterisationError # A list of supported force fields, mapping to their GROMACS ID string. # GROMACS supports a sub-set of the AMBER force fields. @@ -661,9 +661,10 @@ def _get_disulphide_bonds( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Mol as _SireMol import warnings as _warnings + from sire.legacy import Mol as _SireMol + if not isinstance(molecule, _SireMol.Molecule): raise TypeError("'molecule' must be of type 'Sire.Mol.Molecule'") @@ -767,8 +768,9 @@ def _generate_bond_records(molecule, bonds): bond_records : [str] A list of LEaP formatted bond records. """ - from ..._SireWrappers import Atom as _Atom import warnings as _warnings + + from ..._SireWrappers import Atom as _Atom from ..._SireWrappers import Molecule as _Molecule if bonds is None: @@ -914,7 +916,7 @@ def __init__( raise TypeError("'version' must be of type 'int'.") # Check that the version is valid. - if not version in [1, 2]: + if version not in [1, 2]: raise ValueError("Unsupported version: options are 1 or 2.") if not isinstance(charge_method, str): @@ -924,7 +926,7 @@ def __init__( charge_method = charge_method.replace(" ", "").upper() # Check that the charge method is valid. - if not charge_method in self._charge_methods: + if charge_method not in self._charge_methods: raise ValueError( "Unsupported charge method: '%s'. Supported methods are: %s" % (charge_method, self._charge_methods) @@ -991,15 +993,16 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ + import queue as _queue import warnings as _warnings - from ..._Exceptions import ThirdPartyError as _ThirdPartyError + + from ... import IO as _IO from ... import _isVerbose - import queue as _queue from ..._Exceptions import ParameterisationError as _ParameterisationError - from ...Parameters._utils import formalCharge as _formalCharge + from ..._Exceptions import ThirdPartyError as _ThirdPartyError from ..._SireWrappers import Molecule as _Molecule from ...Convert import smiles as _smiles - from ... import IO as _IO + from ...Parameters._utils import formalCharge as _formalCharge if not isinstance(molecule, (_Molecule, str)): raise TypeError( diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py b/src/BioSimSpace/Parameters/_Protocol/_openforcefield.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py rename to src/BioSimSpace/Parameters/_Protocol/_openforcefield.py index 55eb19d67..dcf80a344 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py +++ b/src/BioSimSpace/Parameters/_Protocol/_openforcefield.py @@ -31,13 +31,11 @@ __all__ = ["OpenForceField"] -from ..._Utils import _try_import, _have_imported - import os as _os - - import warnings as _warnings +from ..._Utils import _have_imported, _try_import + # Suppress duplicate to-Python converted warnings. # Both Sire and RDKit register the same converter. with _warnings.catch_warnings(): @@ -193,15 +191,15 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ - from ..._Exceptions import ConversionError as _ConversionError - from ... import _isVerbose - from ... import _Utils + import queue as _queue + + from ... import IO as _IO from ... import Convert as _Convert + from ... import _isVerbose, _Utils + from ..._Exceptions import ConversionError as _ConversionError + from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..._Exceptions import ThirdPartyError as _ThirdPartyError - from ... import IO as _IO - import queue as _queue from ..._SireWrappers import Molecule as _Molecule - from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError if not isinstance(molecule, (_Molecule, str)): raise TypeError( diff --git a/python/BioSimSpace/Parameters/_Protocol/_protocol.py b/src/BioSimSpace/Parameters/_Protocol/_protocol.py similarity index 100% rename from python/BioSimSpace/Parameters/_Protocol/_protocol.py rename to src/BioSimSpace/Parameters/_Protocol/_protocol.py diff --git a/python/BioSimSpace/Parameters/__init__.py b/src/BioSimSpace/Parameters/__init__.py similarity index 100% rename from python/BioSimSpace/Parameters/__init__.py rename to src/BioSimSpace/Parameters/__init__.py diff --git a/python/BioSimSpace/Parameters/_parameters.py b/src/BioSimSpace/Parameters/_parameters.py similarity index 99% rename from python/BioSimSpace/Parameters/_parameters.py rename to src/BioSimSpace/Parameters/_parameters.py index 846debdfa..361e2a6ad 100644 --- a/python/BioSimSpace/Parameters/_parameters.py +++ b/src/BioSimSpace/Parameters/_parameters.py @@ -48,10 +48,8 @@ } from .. import _isVerbose - +from .._Utils import _have_imported, _try_import from ..Types import Length as _Length -from .._Utils import _try_import, _have_imported - from . import _Protocol @@ -205,9 +203,9 @@ def _parameterise_amber_protein( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from .. import _amber_home, _gmx_exe, _gmx_path + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from ._process import Process as _Process if not isinstance(forcefield, str): raise TypeError("'forcefield' must be of type 'str'.") @@ -316,10 +314,10 @@ def gaff( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process + from .. import _amber_home from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..Types import Charge as _Charge - from .. import _amber_home + from ._process import Process as _Process if _amber_home is None: raise _MissingSoftwareError( @@ -416,10 +414,10 @@ def gaff2( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process + from .. import _amber_home from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..Types import Charge as _Charge - from .. import _amber_home + from ._process import Process as _Process if _amber_home is None: raise _MissingSoftwareError( @@ -844,9 +842,9 @@ def _validate( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ..Solvent import waterModels as _waterModels - from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Atom as _Atom + from .._SireWrappers import Molecule as _Molecule + from ..Solvent import waterModels as _waterModels if molecule is not None: if not isinstance(molecule, (_Molecule, str)): @@ -1139,8 +1137,8 @@ def _function( _openforcefields = _try_import("openforcefields") if _have_imported(_openforcefields): - from glob import glob as _glob import os as _os + from glob import glob as _glob _openff_dirs = _openforcefields.get_forcefield_dirs_paths() _open_forcefields = [] diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py b/src/BioSimSpace/Parameters/_process.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py rename to src/BioSimSpace/Parameters/_process.py index c857504be..dc71d20d1 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py +++ b/src/BioSimSpace/Parameters/_process.py @@ -32,9 +32,8 @@ from .. import _is_notebook - if _is_notebook: - from IPython.display import FileLink as _FileLink + pass def _wrap_protocol(protocol_function, process): @@ -91,12 +90,13 @@ def __init__(self, molecule, protocol, work_dir=None, auto_start=False): auto_start : bool Whether to automatically start the process. """ - from .. import _Utils - import warnings as _warnings + import os as _os import sys as _sys + import warnings as _warnings + + from .. import _Utils from .._SireWrappers import Molecule as _Molecule from . import _Protocol - import os as _os # Validate arguments. @@ -159,8 +159,8 @@ def __init__(self, molecule, protocol, work_dir=None, auto_start=False): def start(self): """Start the process.""" - import threading as _threading import queue as _queue + import threading as _threading # Flag that the process has been started. if self._is_started: @@ -190,8 +190,8 @@ def getMolecule(self): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ - from .._Exceptions import ParameterisationError as _ParameterisationError from .. import _isVerbose + from .._Exceptions import ParameterisationError as _ParameterisationError # Start the process, if it's not already started. if not self._is_started: @@ -268,9 +268,10 @@ def getOutput(self, filename=None, file_link=False): file_link : str, IPython.lib.display.FileLink The name of, or link to, a zipfile containing the output. """ - import zipfile as _zipfile import glob as _glob import os as _os + import zipfile as _zipfile + from IPython.display import FileLink as _FileLink if self._zipfile is None or filename is not None: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py b/src/BioSimSpace/Parameters/_utils.py similarity index 98% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py rename to src/BioSimSpace/Parameters/_utils.py index 5a4e5fc22..931b1dd76 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py +++ b/src/BioSimSpace/Parameters/_utils.py @@ -49,12 +49,12 @@ def formalCharge(molecule, property_map={}): formal_charge : :class:`Charge ` The total formal charge on the molecule. """ - from .. import IO as _IO import tempfile as _tempfile - from ..Units.Charge import electron_charge as _electron_charge + + from .. import IO as _IO + from .. import _isVerbose, _Utils from .._SireWrappers import Molecule as _Molecule - from .. import _Utils - from .. import _isVerbose + from ..Units.Charge import electron_charge as _electron_charge if not isinstance(molecule, _Molecule): raise TypeError( diff --git a/python/BioSimSpace/Process/__init__.py b/src/BioSimSpace/Process/__init__.py similarity index 100% rename from python/BioSimSpace/Process/__init__.py rename to src/BioSimSpace/Process/__init__.py diff --git a/python/BioSimSpace/Process/_amber.py b/src/BioSimSpace/Process/_amber.py similarity index 99% rename from python/BioSimSpace/Process/_amber.py rename to src/BioSimSpace/Process/_amber.py index 2c2f0e5ca..a087be8a8 100644 --- a/python/BioSimSpace/Process/_amber.py +++ b/src/BioSimSpace/Process/_amber.py @@ -111,8 +111,9 @@ def __init__( Additional keyword arguments. """ import os as _os - from ..Protocol._free_energy_mixin import _FreeEnergyMixin + from .._Config import Amber as _AmberConfig + from ..Protocol._free_energy_mixin import _FreeEnergyMixin # Call the base class constructor. super().__init__( @@ -241,16 +242,16 @@ def __init__( def _setup(self, **kwargs): """Setup the input files and working directory ready for simulation.""" - from .. import IO as _IO - import shutil as _shutil - from ..Align._squash import _squash import os as _os - from .. import _isVerbose + import shutil as _shutil + + from .. import IO as _IO from .. import Protocol as _Protocol + from .. import _isVerbose + from ..Align._squash import _squash from ..Protocol._free_energy_mixin import _FreeEnergyMixin # Create the input files... - # Create a copy of the system. system = self._system.copy() reference_system = self._reference_system.copy() @@ -382,8 +383,9 @@ def _setup(self, **kwargs): def _generate_config(self): """Generate AMBER configuration file strings.""" - import shutil as _shutil import os as _os + import shutil as _shutil + from .. import Protocol as _Protocol from .._Config import Amber as _AmberConfig from ._plumed import Plumed as _Plumed @@ -485,8 +487,10 @@ def start(self): process : :class:`Process.Amber ` The process object. """ - from sire.legacy import Base as _SireBase import timeit as _timeit + + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -540,15 +544,17 @@ def getSystem(self, block="AUTO"): system : :class:`System ` The latest molecular system. """ - from .._SireWrappers import System as _System - from sire.legacy import Mol as _SireMol + import os as _os import shutil as _shutil - from ..Align._squash import _unsquash + import tempfile as _tempfile + import warnings as _warnings + from sire.legacy import IO as _SireIO - import os as _os + from sire.legacy import Mol as _SireMol + + from .._SireWrappers import System as _System + from ..Align._squash import _unsquash from ..Protocol._free_energy_mixin import _FreeEnergyMixin - import warnings as _warnings - import tempfile as _tempfile # Wait for the process to finish. if block is True: @@ -681,9 +687,10 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): trajectory : :class:`Trajectory ` The latest trajectory object. """ - from .. import Trajectory as _Trajectory import warnings as _warnings + from .. import Trajectory as _Trajectory + if not isinstance(backend, str): raise TypeError("'backend' must be of type 'str'") @@ -722,13 +729,14 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from ..Align._squash import _unsquash from sire.legacy import IO as _SireIO - from .. import Trajectory as _Trajectory - from .. import Protocol as _Protocol from sire.legacy import Mol as _SireMol - if not type(index) is int: + from .. import Protocol as _Protocol + from .. import Trajectory as _Trajectory + from ..Align._squash import _unsquash + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = int( @@ -859,7 +867,7 @@ def getRecordKey(self, record, region=0, soft_core=False): cleaned_record = record.strip().upper() # Make sure the record exists in the key mapping. - if not cleaned_record in self._stdout_key[idx].values(): + if cleaned_record not in self._stdout_key[idx].values(): raise ValueError(f"No key found for record '{record}'") return list(self._stdout_key[idx].keys())[ @@ -2624,9 +2632,10 @@ def stdout(self, n=10): n : int The number of lines to print. """ + import re as _re + from .. import Protocol as _Protocol from ..Protocol._free_energy_mixin import _FreeEnergyMixin - import re as _re # Ensure that the number of lines is positive. if n < 0: @@ -2771,7 +2780,7 @@ def kill(self): """Kill the running process.""" # Kill the process. - if not self._process is None and self._process.is_running(): + if self._process is not None and self._process.is_running(): self._process.kill() def _get_stdout_record( @@ -2807,9 +2816,10 @@ def _get_stdout_record( record : The matching stdout record. """ - from ..Types._type import Type as _Type import warnings as _warnings + from ..Types._type import Type as _Type + # Update the standard output dictionary. self.stdout(0) @@ -2911,9 +2921,10 @@ def _findExe(is_gpu=False, is_free_energy=False, is_vacuum=False): exe : str The path to the executable. """ + import os as _os + from .. import _amber_home from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - import os as _os if not isinstance(is_gpu, bool): raise TypeError("'is_gpu' must be of type 'bool'.") @@ -2934,9 +2945,7 @@ def _findExe(is_gpu=False, is_free_energy=False, is_vacuum=False): # Search for the executable. - import os as _os import pathlib as _pathlib - from glob import glob as _glob # Get the current path. diff --git a/python/BioSimSpace/Process/_atm.py b/src/BioSimSpace/Process/_atm.py similarity index 98% rename from python/BioSimSpace/Process/_atm.py rename to src/BioSimSpace/Process/_atm.py index 3c61e6b84..7198d4bdf 100644 --- a/python/BioSimSpace/Process/_atm.py +++ b/src/BioSimSpace/Process/_atm.py @@ -205,15 +205,16 @@ def _generate_config_minimisation(self): self.addToConfig( "\n# Run a single simulation step to allow us to get the system and energy." ) - self.addToConfig(f"simulation.step(1)") + self.addToConfig("simulation.step(1)") # Flag that this isn't a custom protocol. self._protocol._setCustomised(False) def _generate_config_equilibration(self): - from ._atm_utils import _ATMUtils import math as _math + from ._atm_utils import _ATMUtils + util = _ATMUtils(self._protocol) # Clear the existing configuration list. self._config = [] @@ -327,10 +328,10 @@ def _generate_config_equilibration(self): self.addToConfig(f"start_temperature = {temperature}") self.addToConfig(f"for x in range(0, {temp_cycles}):") self.addToConfig(f" temperature = {temperature} + x*{delta_temp}") - self.addToConfig(f" integrator.setTemperature(temperature*kelvin)") + self.addToConfig(" integrator.setTemperature(temperature*kelvin)") if is_constant_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(100)") else: @@ -343,17 +344,18 @@ def _generate_config_equilibration(self): self.addToConfig(f"start_temperature = {temperature}") self.addToConfig(f"for x in range(0, {steps}):") self.addToConfig(f" temperature = {temperature} + x*{delta_temp}") - self.addToConfig(f" integrator.setTemperature(temperature*kelvin)") + self.addToConfig(" integrator.setTemperature(temperature*kelvin)") if is_constant_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(1)") def _generate_config_annealing(self): - from ._atm_utils import _ATMUtils import math as _math + from ._atm_utils import _ATMUtils + self._protocol._set_current_index(0) util = _ATMUtils(self._protocol) # Clear the existing configuration list. @@ -487,9 +489,10 @@ def _generate_config_annealing(self): self.addToConfig(annealing_protocol) def _generate_config_production(self): + import math as _math + from .._Exceptions import IncompatibleError as _IncompatibleError from ._atm_utils import _ATMUtils - import math as _math self._protocol.set_current_index(0) analysis_method = self._protocol.getAnalysisMethod() @@ -693,10 +696,11 @@ def _generate_config_single_point_testing(self): # Designed as a hidden method - uses a production protocol to # calculate single point energies for each lambda window # quite hacky, but not designed to be exposed to the user anyway - from .._Exceptions import IncompatibleError as _IncompatibleError - from ._atm_utils import _ATMUtils import math as _math + from .. import Protocol as _Protocol + from .._Exceptions import IncompatibleError as _IncompatibleError + from ._atm_utils import _ATMUtils self._protocol.set_current_index(0) if not isinstance(self._protocol, _Protocol.ATMProduction): diff --git a/python/BioSimSpace/Process/_atm_utils.py b/src/BioSimSpace/Process/_atm_utils.py similarity index 99% rename from python/BioSimSpace/Process/_atm_utils.py rename to src/BioSimSpace/Process/_atm_utils.py index 08311fa5f..11e5ca7e6 100644 --- a/python/BioSimSpace/Process/_atm_utils.py +++ b/src/BioSimSpace/Process/_atm_utils.py @@ -611,7 +611,7 @@ def createLoopWithReporting( output += "# Reporting for MBAR:\n" # round master lambda to 4 d.p. to avoid floating point errors output += f"master_lambda_list = {[round(i,4) for i in self.protocol._get_lambda_values()]}\n" - output += f"master_lambda = master_lambda_list[window_index]\n" + output += "master_lambda = master_lambda_list[window_index]\n" output += "if is_restart:\n" output += " try:\n" @@ -631,7 +631,7 @@ def createLoopWithReporting( output += "# Timestep in ps\n" output += f"timestep = {timestep}\n" output += f"inflex_point = {inflex_point}\n" - output += f"for x in range(0, numcycles):\n" + output += "for x in range(0, numcycles):\n" output += f" simulation.step({steps_per_cycle})\n" output += f" steps_so_far += {steps_per_cycle}\n" output += " time = steps_so_far * timestep\n" @@ -680,7 +680,7 @@ def createLoopWithReporting( output += " simulation.context.setParameter('Direction',direction)\n" output += f" simulation.saveState('{name}.xml')\n" output += " #now dump data to a csv file\n" - output += f" df = pd.DataFrame(energies)\n" + output += " df = pd.DataFrame(energies)\n" output += " df.set_index(['time', 'fep-lambda'], inplace=True)\n" output += " df.to_csv(f'energies_{master_lambda}.csv')\n" output += "#Dump final data to csv file\n" @@ -726,7 +726,7 @@ def createSoftcorePertELoop( output += " result['pert_en'] = []\n" output += " result['metad_offset'] = []\n" - output += f"for x in range(0, numcycles):\n" + output += "for x in range(0, numcycles):\n" output += f" simulation.step({steps_per_cycle})\n" output += ( " state = simulation.context.getState(getEnergy = True, groups = -1)\n" @@ -811,7 +811,7 @@ def createReportingBoth( output += "# Reporting for MBAR:\n" # round master lambda to 4 d.p. to avoid floating point errors output += f"master_lambda_list = {[round(i,4) for i in self.protocol._get_lambda_values()]}\n" - output += f"master_lambda = master_lambda_list[window_index]\n" + output += "master_lambda = master_lambda_list[window_index]\n" output += "if is_restart:\n" output += " try:\n" output += " MBAR_df = pd.read_csv(f'energies_{master_lambda}.csv')\n" @@ -830,7 +830,7 @@ def createReportingBoth( output += f"inflex_point = {inflex_point}\n" output += "# Now run the simulation.\n" - output += f"for x in range(0, numcycles):\n" + output += "for x in range(0, numcycles):\n" output += f" simulation.step({steps_per_cycle})\n" output += f" steps_so_far += {steps_per_cycle}\n" output += " time = steps_so_far * timestep\n" diff --git a/python/BioSimSpace/Process/_gromacs.py b/src/BioSimSpace/Process/_gromacs.py similarity index 99% rename from python/BioSimSpace/Process/_gromacs.py rename to src/BioSimSpace/Process/_gromacs.py index 7c42dab70..49f7d36d4 100644 --- a/python/BioSimSpace/Process/_gromacs.py +++ b/src/BioSimSpace/Process/_gromacs.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -119,6 +118,7 @@ def __init__( Additional keyword arguments. """ import os as _os + from .. import _gmx_exe from .._Exceptions import MissingSoftwareError as _MissingSoftwareError @@ -218,13 +218,13 @@ def __init__( def _setup(self, **kwargs): """Setup the input files and working directory ready for simulation.""" - from ..Protocol._free_energy_mixin import _FreeEnergyMixin - from .. import IO as _IO import os as _os + + from .. import IO as _IO from .. import Protocol as _Protocol + from ..Protocol._free_energy_mixin import _FreeEnergyMixin # Create the input files... - # Create a copy of the system. system = self._system.copy() @@ -307,16 +307,18 @@ def _setup(self, **kwargs): def _generate_config(self): """Generate GROMACS configuration file strings.""" import os as _os - from .. import Protocol as _Protocol + import shutil as _shutil + import warnings as _warnings + from sire.legacy import IO as _SireIO - from ._plumed import Plumed as _Plumed from sire.legacy import Maths as _SireMaths - import warnings as _warnings + from sire.legacy import Vol as _SireVol + + from .. import Protocol as _Protocol + from .. import _gmx_version from .._Config import Gromacs as _GromacsConfig from ..Protocol._position_restraint_mixin import _PositionRestraintMixin - import shutil as _shutil - from .. import _gmx_version - from sire.legacy import Vol as _SireVol + from ._plumed import Plumed as _Plumed # Check whether the system contains periodic box information. space_prop = self._property_map.get("space", "space") @@ -514,9 +516,10 @@ def _generate_binary_run_file( **kwargs : dict Additional keyword arguments. """ - from .. import _Utils - import subprocess as _subprocess import os as _os + import subprocess as _subprocess + + from .. import _Utils if not isinstance(mdp_file, str): raise ValueError("'mdp_file' must be of type 'str'.") @@ -733,9 +736,11 @@ def start(self): A handle to the GROMACS process. """ import timeit as _timeit - from .. import _Utils + from sire.legacy import Base as _SireBase + from .. import _Utils + # The process is currently queued. if self.isQueued(): return @@ -795,9 +800,10 @@ def getSystem(self, block="AUTO"): system : :class:`System ` The latest molecular system. """ - from .. import Units as _Units import warnings as _warnings + from .. import Protocol as _Protocol + from .. import Units as _Units # Wait for the process to finish. if block is True: @@ -856,6 +862,7 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): The latest trajectory object. """ import warnings as _warnings + from .. import Trajectory as _Trajectory if not isinstance(backend, str): @@ -906,7 +913,7 @@ def getFrame(self, index): """ import warnings as _warnings - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -1074,8 +1081,8 @@ def getTime(self, time_series=False, block="AUTO"): time : :class:`Time ` The current simulation time in nanoseconds. """ - from .. import Units as _Units from .. import Protocol as _Protocol + from .. import Units as _Units if isinstance(self._protocol, _Protocol.Minimisation): return None @@ -2075,13 +2082,15 @@ def stdout(self, n=10): def _add_position_restraints(self): """Helper function to add position restraints.""" - from ..Protocol._free_energy_mixin import _FreeEnergyMixin import os as _os + from sire.legacy import IO as _SireIO from sire.legacy import Base as _SireBase - from .. import _isVerbose from sire.legacy import Units as _SireUnits + from .. import _isVerbose + from ..Protocol._free_energy_mixin import _FreeEnergyMixin + # Get the restraint type. restraint = self._protocol.getRestraint() @@ -2171,7 +2180,7 @@ def _add_position_restraints(self): # Store the atom index if it hasn't already been recorded. for atom_idx in atom_idxs: - if not atom_idx in restrained_atoms: + if atom_idx not in restrained_atoms: restrained_atoms.append(atom_idx) # Write the position restraint file for this molecule. @@ -2259,7 +2268,7 @@ def _add_position_restraints(self): mol_type = sys_idx_moltypes[mol_idx] # Append this atom if it's not already been recorded. - if not atom_idx in mol_atoms[mol_type]: + if atom_idx not in mol_atoms[mol_type]: mol_atoms[mol_type].append(atom_idx) except Exception as e: @@ -2330,9 +2339,10 @@ def _add_position_restraints(self): def _initialise_energy_dict(self): """Helper function to intialise the energy dictionary.""" - from .. import _Utils import subprocess as _subprocess + from .. import _Utils + # Grab the available energy terms command = f"{self._exe} energy -f {self._energy_file}" proc = _subprocess.run( @@ -2440,8 +2450,9 @@ def _parse_energy_units(text): The order that the energy unit is printed will obey the order obtained from :meth:`~BioSimSpace.Process.Gromacs._parse_energy_terms`. """ - from .. import Types as _Types import warnings as _warnings + + from .. import Types as _Types from .. import Units as _Units section = text.split("---")[-1] @@ -2519,12 +2530,14 @@ def _sanitise_energy_term(key): def _update_energy_dict(self): """Internal function to update the energy dictionary with the latest data.""" - from tempfile import TemporaryDirectory as _TemporaryDirectory - from .. import _Utils - from pathlib import Path as _Path import subprocess as _subprocess + from pathlib import Path as _Path + from tempfile import TemporaryDirectory as _TemporaryDirectory + import numpy as _np + from .. import _Utils + if len(self._energy_dict) == 0: self._initialise_energy_dict() @@ -2587,6 +2600,7 @@ def _get_energy_record(self, key, time_series=False, unit=None): The matching stdout record. """ import warnings as _warnings + from ..Types._type import Type as _Type # No data! @@ -2638,12 +2652,14 @@ def _getFinalFrame(self): system : :class:`System ` The molecular system from the final frame. """ - from .. import IO as _IO import os as _os - from .. import _Utils - from sire.legacy import IO as _SireIO import warnings as _warnings + from sire.legacy import IO as _SireIO + + from .. import IO as _IO + from .. import _Utils + # Grab the last frame from the GRO file. with _Utils.cd(self._work_dir): # Do we need to get coordinates for the lambda=1 state. @@ -2708,7 +2724,7 @@ def _getFinalFrame(self): # If this is a vacuum simulation, then translate the centre of mass # of the system back to the origin. - if not space_prop in old_system._sire_object.property_keys(): + if space_prop not in old_system._sire_object.property_keys(): com = new_system._getCenterOfMass() old_system.translate([-x for x in com]) @@ -2730,13 +2746,15 @@ def _getFrame(self, time): system : :class:`System ` The molecular system from the closest trajectory frame. """ - from .. import IO as _IO import os as _os - from .. import _Utils + import subprocess as _subprocess + import warnings as _warnings + from sire.legacy import IO as _SireIO + + from .. import IO as _IO from .. import Types as _Types - import warnings as _warnings - import subprocess as _subprocess + from .. import _Utils if not isinstance(time, _Types.Time): raise TypeError("'time' must be of type 'BioSimSpace.Types.Time'") @@ -2832,7 +2850,7 @@ def _getFrame(self, time): # If this is a vacuum simulation, then translate the centre of mass # of the system back to the origin. - if not space_prop in old_system._sire_object.property_keys(): + if space_prop not in old_system._sire_object.property_keys(): com = new_system._getCenterOfMass() old_system.translate([-x for x in com]) @@ -2860,9 +2878,9 @@ def _find_trajectory_file(self): traj_file : str The path to the trajectory file. """ - import warnings as _warnings import glob as _glob import os as _os + import warnings as _warnings # Check that the current trajectory file is found. if not _os.path.isfile(self._traj_file): diff --git a/python/BioSimSpace/Process/_namd.py b/src/BioSimSpace/Process/_namd.py similarity index 99% rename from python/BioSimSpace/Process/_namd.py rename to src/BioSimSpace/Process/_namd.py index 3967c736b..a4e780451 100644 --- a/python/BioSimSpace/Process/_namd.py +++ b/src/BioSimSpace/Process/_namd.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -87,10 +86,12 @@ def __init__( kwargs : dict Additional keyword arguments. """ - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from sire.legacy import Base as _SireBase import os as _os + from sire.legacy import Base as _SireBase + + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + # Call the base class constructor. super().__init__( system, @@ -111,9 +112,17 @@ def __init__( # If the path to the executable wasn't specified, then search # for it in $PATH. if exe is None: - try: - self._exe = _SireBase.findExe("namd2").absolute_file_path() - except: + exes = ["namd3", "namd2"] + exe_found = False + for e in exes: + try: + self._exe = _SireBase.findExe(e).absolute_file_path() + exe_found = True + break + except: + pass + + if not exe_found: raise _MissingSoftwareError( "'BioSimSpace.Process.Namd' is not supported. " "Please install NAMD (http://www.ks.uiuc.edu/Research/namd)." @@ -155,14 +164,15 @@ def __init__( def _setup(self): """Setup the input files and working directory ready for simulation.""" - from .. import Protocol as _Protocol + import os as _os + from sire.legacy import IO as _SireIO + from .. import IO as _IO + from .. import Protocol as _Protocol from .. import _isVerbose - import os as _os # Create the input files... - # Create a copy of the system. system = self._system.copy() @@ -277,14 +287,16 @@ def _setup(self): def _generate_config(self): """Generate NAMD configuration file strings.""" + import math as _math + import os as _os + import warnings as _warnings + + from sire.legacy import IO as _SireIO from sire.legacy.Maths import Vector as _Vector + from .. import Protocol as _Protocol - from sire.legacy import IO as _SireIO - from ..Protocol._position_restraint_mixin import _PositionRestraintMixin - import math as _math from .._Exceptions import IncompatibleError as _IncompatibleError - import warnings as _warnings - import os as _os + from ..Protocol._position_restraint_mixin import _PositionRestraintMixin # Clear the existing configuration list. self._config = [] @@ -658,7 +670,9 @@ def start(self): The process object. """ import timeit as _timeit + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -713,10 +727,12 @@ def getSystem(self, block="AUTO"): system : :class:`System ` The latest molecular system. """ + import os as _os import warnings as _warnings - from .. import IO as _IO + from sire.legacy import IO as _SireIO - import os as _os + + from .. import IO as _IO # Wait for the process to finish. if block is True: @@ -858,6 +874,7 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): The latest trajectory object. """ import warnings as _warnings + from .. import Trajectory as _Trajectory if not isinstance(backend, str): @@ -898,10 +915,11 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory from sire.legacy import IO as _SireIO - if not type(index) is int: + from .. import Trajectory as _Trajectory + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -2164,6 +2182,7 @@ def _createRestrainedSystem(self, system, restraint): The molecular system with an added 'restrained' property. """ from sire.legacy import Mol as _SireMol + from .. import _isVerbose # Get the force constant value in the default units. This is @@ -2285,6 +2304,7 @@ def _get_stdout_record(self, key, time_series=False, unit=None): The matching stdout record. """ import warnings as _warnings + from ..Types._type import Type as _Type # No data! diff --git a/python/BioSimSpace/Process/_openmm.py b/src/BioSimSpace/Process/_openmm.py similarity index 99% rename from python/BioSimSpace/Process/_openmm.py rename to src/BioSimSpace/Process/_openmm.py index 8da39dbb9..30d54f1cf 100644 --- a/python/BioSimSpace/Process/_openmm.py +++ b/src/BioSimSpace/Process/_openmm.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -55,8 +54,8 @@ def __new__( property_map={}, **kwargs, ): - from ._atm import OpenMMATM from ..Protocol._atm import _ATM + from ._atm import OpenMMATM # would like to use issubclass but _Protocol._ATM is not exposed if isinstance(protocol, _ATM): @@ -123,6 +122,7 @@ def __init__( """ import os as _os import sys as _sys + from sire.legacy import Base as _SireBase # Call the base class constructor. @@ -242,9 +242,10 @@ def __repr__(self): def _setup(self): """Setup the input files and working directory ready for simulation.""" import os as _os + + from .. import IO as _IO from .. import Protocol as _Protocol from .. import _isVerbose - from .. import IO as _IO # Create a copy of the system. system = self._system.copy() @@ -317,14 +318,15 @@ def _setup(self): def _generate_config(self): """Generate OpenMM Python script file strings.""" + import math as _math + import os as _os import shutil as _shutil import warnings as _warnings - import os as _os - import math as _math - from ..Metadynamics import CollectiveVariable as _CollectiveVariable + + from .. import Protocol as _Protocol from .._Exceptions import IncompatibleError as _IncompatibleError + from ..Metadynamics import CollectiveVariable as _CollectiveVariable from ._plumed import Plumed as _Plumed - from .. import Protocol as _Protocol # Clear the existing configuration list. self._config = [] @@ -412,7 +414,7 @@ def _generate_config(self): self.addToConfig( "\n# Run a single simulation step to allow us to get the system and energy." ) - self.addToConfig(f"simulation.step(1)") + self.addToConfig("simulation.step(1)") elif isinstance(self._protocol, _Protocol.Equilibration): # Write the OpenMM import statements and monkey-patches. @@ -567,11 +569,11 @@ def _generate_config(self): f" temperature = {temperature} + x*{delta_temp}" ) self.addToConfig( - f" integrator.setTemperature(temperature*kelvin)" + " integrator.setTemperature(temperature*kelvin)" ) if is_const_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(100)") else: @@ -587,11 +589,11 @@ def _generate_config(self): f" temperature = {temperature} + x*{delta_temp}" ) self.addToConfig( - f" integrator.setTemperature(temperature*kelvin)" + " integrator.setTemperature(temperature*kelvin)" ) if is_const_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(1)") @@ -1138,7 +1140,7 @@ def _generate_config(self): self.addToConfig( "remaining_cycles = math.ceil(remaining_steps / steps_per_cycle)" ) - self.addToConfig(f"start_cycles = total_cycles - remaining_cycles") + self.addToConfig("start_cycles = total_cycles - remaining_cycles") self.addToConfig("checkpoint = 100") self.addToConfig("if is_restart:") self.addToConfig(" fraction_complete = step / total_steps") @@ -1264,7 +1266,9 @@ def start(self): A handle to the OpenMM process. """ import timeit as _timeit + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -1323,9 +1327,10 @@ def getSystem(self, block="AUTO"): system : :class:`System ` The latest molecular system. """ - from .. import Protocol as _Protocol from sire.legacy import IO as _SireIO + from .. import Protocol as _Protocol + # Wait for the process to finish. if block is True: self.wait() @@ -1442,9 +1447,10 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): The latest trajectory object. """ import os as _os - from .. import Trajectory as _Trajectory import warnings as _warnings + from .. import Trajectory as _Trajectory + if not isinstance(backend, str): raise TypeError("'backend' must be of type 'str'") @@ -1482,11 +1488,13 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory - from sire.legacy import IO as _SireIO import warnings as _warnings - if not type(index) is int: + from sire.legacy import IO as _SireIO + + from .. import Trajectory as _Trajectory + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = int( @@ -2003,7 +2011,7 @@ def _add_config_imports(self): """ # We should verify that openmm is available to prevent # difficult-to-debug errors in the run script - from BioSimSpace._Utils import _try_import, _assert_imported + from BioSimSpace._Utils import _assert_imported, _try_import _openmm = _try_import("openmm") _assert_imported(_openmm) @@ -2146,14 +2154,15 @@ def _add_config_reporters( is_restart : bool Whether the simulation is a restart. """ - from .. import Protocol as _Protocol import math as _math - if not type(state_interval) is int: + from .. import Protocol as _Protocol + + if type(state_interval) is not int: raise TypeError("'state_interval' must be of type 'int'.") if state_interval <= 0: raise ValueError("'state_interval' must be a positive integer.") - if not type(traj_interval) is int: + if type(traj_interval) is not int: raise TypeError("'traj_interval' must be of type 'int'.") if traj_interval <= 0: raise ValueError("'traj_interval' must be a positive integer.") @@ -2189,7 +2198,7 @@ def _add_config_reporters( # Write state information to file every 100 steps. self.addToConfig(f"log_file = open('{self._name}.log', 'a')") - self.addToConfig(f"simulation.reporters.append(StateDataReporter(log_file,") + self.addToConfig("simulation.reporters.append(StateDataReporter(log_file,") self.addToConfig( f" {state_interval}," ) @@ -2275,6 +2284,7 @@ def _add_config_restraints(self): def _update_stdout_dict(self): """Update the dictionary of thermodynamic records.""" import os as _os + from .._Exceptions import IncompatibleError as _IncompatibleError # Exit if log file hasn't been created. @@ -2393,9 +2403,10 @@ def _get_stdout_record(self, key, time_series=False, unit=None): record : The matching stdout record. """ - from ..Types._type import Type as _Type import warnings as _warnings + from ..Types._type import Type as _Type + # No data! if len(self._stdout_dict) == 0: return None diff --git a/python/BioSimSpace/Process/_plumed.py b/src/BioSimSpace/Process/_plumed.py similarity index 99% rename from python/BioSimSpace/Process/_plumed.py rename to src/BioSimSpace/Process/_plumed.py index 798eb952d..b5ca4bf8e 100644 --- a/python/BioSimSpace/Process/_plumed.py +++ b/src/BioSimSpace/Process/_plumed.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -49,11 +48,12 @@ def __init__(self, work_dir): The working directory of the process that is interfacing with PLUMED. """ - import subprocess as _subprocess import os as _os - from .. import _Exceptions + import subprocess as _subprocess + from sire.legacy.Base import findExe as _findExe - from .. import _Utils + + from .. import _Exceptions, _Utils from ._process import _MultiDict # Check that the working directory is valid. @@ -165,9 +165,9 @@ def createConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from ..Protocol import Steering as _Steering from .._SireWrappers import System as _System from ..Protocol import Metadynamics as _Metadynamics + from ..Protocol import Steering as _Steering if not isinstance(system, _System): raise TypeError( @@ -213,15 +213,17 @@ def _createMetadynamicsConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from .. import Units as _Units - import sire.legacy.Vol as _SireVol - from ..Protocol import Metadynamics as _Metadynamics - from ..Types import Coordinate as _Coordinate import os as _os + + import sire.legacy.Vol as _SireVol + from sire.legacy.Maths import Vector as _Vector + + from .. import Units as _Units from .. import _Exceptions - from ..Metadynamics import CollectiveVariable as _CollectiveVariable from .._SireWrappers import System as _System - from sire.legacy.Maths import Vector as _Vector + from ..Metadynamics import CollectiveVariable as _CollectiveVariable + from ..Protocol import Metadynamics as _Metadynamics + from ..Types import Coordinate as _Coordinate if not isinstance(system, _System): raise TypeError( @@ -928,13 +930,14 @@ def _createSteeringConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from .. import Units as _Units - from ..Protocol import Steering as _Steering - from ..Types import Coordinate as _Coordinate import os as _os + + from .. import Units as _Units from .. import _Exceptions - from ..Metadynamics import CollectiveVariable as _CollectiveVariable from .._SireWrappers import System as _System + from ..Metadynamics import CollectiveVariable as _CollectiveVariable + from ..Protocol import Steering as _Steering + from ..Types import Coordinate as _Coordinate if not isinstance(system, _System): raise TypeError( @@ -1348,8 +1351,8 @@ def getTime(self, time_series=False): time : :class:`Time ` The simulation run time. """ - from .. import _Exceptions from .. import Units as _Units + from .. import _Exceptions # We need to have generated a valid config before being able to parse # the COLVAR records. @@ -1397,7 +1400,7 @@ def getCollectiveVariable(self, index, time_series=False): msg = "No PLUMED configuration found! Please run 'createConfig' first." raise _Exceptions.IncompatibleError(msg) - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if index > self._num_components - 1 or index < -self._num_components: raise IndexError( @@ -1442,13 +1445,13 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): [[:class:`Type `, :class:`Type `, ...], ...] The free energy estimate for the chosen collective variables. """ - from .. import Units as _Units - import shutil as _shutil import glob as _glob - import subprocess as _subprocess import os as _os - from .. import _Exceptions - from .. import _Utils + import shutil as _shutil + import subprocess as _subprocess + + from .. import Units as _Units + from .. import _Exceptions, _Utils # We need to have generated a valid config before being able to compute # free energies. @@ -1457,7 +1460,7 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): raise _Exceptions.IncompatibleError(msg) if index is not None: - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if index > self._num_components - 1 or index < -self._num_components: raise IndexError( @@ -1466,7 +1469,7 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): ) if stride is not None: - if not type(stride) is int: + if type(stride) is not int: raise TypeError("'stride' must be of type 'int'") if stride < 0: raise ValueError("'stride' must be >= 0") diff --git a/python/BioSimSpace/Process/_process.py b/src/BioSimSpace/Process/_process.py similarity index 99% rename from python/BioSimSpace/Process/_process.py rename to src/BioSimSpace/Process/_process.py index 99fcfa7bf..496f14d13 100644 --- a/python/BioSimSpace/Process/_process.py +++ b/src/BioSimSpace/Process/_process.py @@ -32,11 +32,11 @@ _pygtail = _try_import("pygtail") -from .. import _is_notebook from .. import Units as _Units +from .. import _is_notebook if _is_notebook: - from IPython.display import FileLink as _FileLink + pass class _MultiDict(dict): @@ -108,14 +108,16 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .._SireWrappers import System as _System - from .. import _is_interactive - from .._Exceptions import IncompatibleError as _IncompatibleError + import collections as _collections import os as _os + + from sire.legacy import Mol as _SireMol + + from .. import _is_interactive from .. import _Utils as _Utils - import collections as _collections + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import System as _System from ..Protocol._protocol import Protocol as _Protocol - from sire.legacy import Mol as _SireMol # Don't allow user to create an instance of this base class. if type(self) is Process: @@ -167,7 +169,7 @@ def __init__( ) # Check that the seed is valid. - if seed is not None and not type(seed) is int: + if seed is not None and type(seed) is not int: raise TypeError("'seed' must be of type 'int'") # Check the extra options. @@ -559,11 +561,11 @@ def _sampleConfigurations(self, bounds, number=1, block="AUTO"): collective_variables : [(:class:`Type `, int, float, ...)] The value of the collective variable for each configuration. """ + import random as _random import sys as _sys import warnings as _warnings - import random as _random - if not type(number) is int: + if type(number) is not int: raise TypeError("'number' must be of type 'int'") if number < 1: @@ -712,9 +714,10 @@ def _checkPerturbable(self, system): system : :class:`System ` The molecular system at a given end state. """ - from .._SireWrappers import System as _System import warnings as _warnings + from .._SireWrappers import System as _System + # Check that the system is valid. if not isinstance(system, _System): raise TypeError( @@ -724,7 +727,7 @@ def _checkPerturbable(self, system): # If the system contains a perturbable molecule, then we'll warn the user # and simulate the lambda = 0 state. if system.nPerturbableMolecules() > 0: - if not "is_lambda1" in self._property_map: + if "is_lambda1" not in self._property_map: is_lambda1 = False _warnings.warn( "The system contains a perturbable molecule ." @@ -898,7 +901,7 @@ def setSeed(self, seed): """ import warnings as _warnings - if not type(seed) is int: + if type(seed) is not int: _warnings.warn("The seed must be an integer. Disabling seeding.") self._seed = None else: @@ -996,7 +999,7 @@ def isError(self): def kill(self): """Kill the running process.""" - if not self._process is None and self._process.is_running(): + if self._process is not None and self._process.is_running(): self._process.kill() def stdout(self, n=10): @@ -1177,9 +1180,10 @@ def getInput(self, name=None, file_link=False): output : str, IPython.display.FileLink A path, or file link, to an archive of the process input. """ - from IPython.display import FileLink as _FileLink - import zipfile as _zipfile import os as _os + import zipfile as _zipfile + + from IPython.display import FileLink as _FileLink if name is None: name = self._name + "_input" @@ -1236,10 +1240,11 @@ def getOutput(self, name=None, block="AUTO", file_link=False): output : str, IPython.display.FileLink A path, or file link, to an archive of the process output. """ + import glob as _glob import os as _os - from IPython.display import FileLink as _FileLink import zipfile as _zipfile - import glob as _glob + + from IPython.display import FileLink as _FileLink if name is None: name = self._name + "_output" @@ -1678,7 +1683,7 @@ def _is_list_of_strings(lst): def _odict_insert(dct, key, value, index): """Insert an item into an ordered dictionary.""" - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Store the original size of the dictionary. diff --git a/python/BioSimSpace/Process/_process_runner.py b/src/BioSimSpace/Process/_process_runner.py similarity index 99% rename from python/BioSimSpace/Process/_process_runner.py rename to src/BioSimSpace/Process/_process_runner.py index 35d507025..48770aa0b 100644 --- a/python/BioSimSpace/Process/_process_runner.py +++ b/src/BioSimSpace/Process/_process_runner.py @@ -67,9 +67,10 @@ def __init__(self, processes, name="runner", work_dir=None): work_dir : str The working directory for the processes. """ - from ._process import Process as _Process import os as _os + from ._process import Process as _Process + # Convert tuple to list. if isinstance(processes, tuple): processes = list(processes) @@ -551,7 +552,7 @@ def startAll(self, serial=False, batch_size=None, max_retries=5): raise TypeError("'serial' must be of type 'bool'.") if batch_size is not None: - if not type(batch_size) is int: + if type(batch_size) is not int: raise TypeError("'batch_size' must be of type 'int'.") if batch_size < 1: raise ValueError("'batch_size' must be > 1.") @@ -560,7 +561,7 @@ def startAll(self, serial=False, batch_size=None, max_retries=5): batch_size = cpu_count() - if not type(max_retries) is int: + if type(max_retries) is not int: raise TypeError("'max_retries' must be of type 'int'.") if max_retries < 1: @@ -619,7 +620,7 @@ def _run_processes(self, serial=False, batch_size=None, max_retries=5): raise TypeError("'serial' must be of type 'bool'.") if batch_size is not None: - if not type(batch_size) is int: + if type(batch_size) is not int: raise TypeError("'batch_size' must be of type 'int'.") if batch_size < 1: raise ValueError("'batch_size' must be > 1.") @@ -628,7 +629,7 @@ def _run_processes(self, serial=False, batch_size=None, max_retries=5): batch_size = cpu_count() - if not type(max_retries) is int: + if type(max_retries) is not int: raise TypeError("'max_retries' must be of type 'int'.") if max_retries < 1: @@ -833,9 +834,10 @@ def _nest_directories(self, processes): new_processes : [:class:`Process `] A list of procesess with updated working directories. """ - from .._SireWrappers import System as _System import os as _os + from .._SireWrappers import System as _System + # Create the list of new processes. new_processes = [] diff --git a/python/BioSimSpace/Process/_somd.py b/src/BioSimSpace/Process/_somd.py similarity index 99% rename from python/BioSimSpace/Process/_somd.py rename to src/BioSimSpace/Process/_somd.py index 53d9cd53b..bed1c9cb2 100644 --- a/python/BioSimSpace/Process/_somd.py +++ b/src/BioSimSpace/Process/_somd.py @@ -32,7 +32,6 @@ import string as _string - from . import _process @@ -105,14 +104,16 @@ def __init__( kwargs : dict Additional keyword arguments. """ - from .._Exceptions import IncompatibleError as _IncompatibleError - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - import sys as _sys + import math as _math import os as _os + import sys as _sys + from sire.legacy import Base as _SireBase + from .. import Protocol as _Protocol + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..Protocol._free_energy_mixin import _FreeEnergyMixin - import math as _math # Call the base class constructor. super().__init__( @@ -295,16 +296,17 @@ def __repr__(self): def _setup(self): """Setup the input files and working directory ready for simulation.""" - from sire.legacy import IO as _SireIO - from .._SireWrappers import System as _System - from .. import _isVerbose import os as _os - from .. import Protocol as _Protocol import warnings as _warnings + + from sire.legacy import IO as _SireIO + from .. import IO as _IO + from .. import Protocol as _Protocol + from .. import _isVerbose + from .._SireWrappers import System as _System # Create the input files... - # First create a copy of the system. system = self._system.copy() @@ -412,11 +414,12 @@ def _setup(self): def _generate_config(self): """Generate SOMD configuration file strings.""" - from .._SireWrappers import System as _System import os as _os - from .. import Protocol as _Protocol import warnings as _warnings + + from .. import Protocol as _Protocol from .._Config import Somd as _SomdConfig + from .._SireWrappers import System as _System # Check whether the system contains periodic box information. # For now, well not attempt to generate a box if the system property @@ -497,11 +500,13 @@ def start(self): process : :class:`Process.Somd ` A handle to the running process. """ - import timeit as _timeit import os as _os - from .. import _Utils + import timeit as _timeit + from sire.legacy import Base as _SireBase + from .. import _Utils + # The process is currently queued. if self.isQueued(): return @@ -559,7 +564,9 @@ def getSystem(self, block="AUTO"): The latest molecular system. """ import warnings as _warnings + from sire.legacy import IO as _SireIO + from .. import IO as _IO # Wait for the process to finish. @@ -657,6 +664,7 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): The latest trajectory object. """ import warnings as _warnings + from .. import Trajectory as _Trajectory if not isinstance(backend, str): @@ -697,10 +705,11 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory from sire.legacy import IO as _SireIO - if not type(index) is int: + from .. import Trajectory as _Trajectory + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -776,9 +785,10 @@ def getTime(self, time_series=False, block="AUTO"): time : :class:`Time ` The current simulation time in nanoseconds. """ - from .. import Protocol as _Protocol import warnings as _warnings + from .. import Protocol as _Protocol + # Warn the user if the process has exited with an error. if self.isError(): _warnings.warn("The process exited with an error!") @@ -848,8 +858,8 @@ def getGradient(self, time_series=False, block="AUTO"): gradient : float The free energy gradient. """ - import warnings as _warnings import os as _os + import warnings as _warnings # Wait for the process to finish. if block is True: @@ -899,9 +909,10 @@ def getCurrentGradient(self, time_series=False): def _clear_output(self): """Reset stdout and stderr.""" - from .. import Protocol as _Protocol - import os as _os import glob as _glob + import os as _os + + from .. import Protocol as _Protocol # Call the base class method. super()._clear_output() @@ -991,13 +1002,15 @@ def _to_pert_file( molecule : :class:`System ` The molecule with properties corresponding to the lamda = 0 state. """ - from sire.legacy import CAS as _SireCAS import random as _random - from .._Exceptions import IncompatibleError as _IncompatibleError + + from sire.legacy import CAS as _SireCAS from sire.legacy import MM as _SireMM - from .._SireWrappers import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule + if not isinstance(molecule, _Molecule): raise TypeError( "'molecule' must be of type 'BioSimSpace._SireWrappers.Molecule'" @@ -2570,7 +2583,7 @@ def sort_dihedrals(dihedrals, idx): for idx0 in impropers0_idx.keys(): if idx1.equivalent(idx0): # Don't store duplicates. - if not idx0 in impropers_shared_idx.keys(): + if idx0 not in impropers_shared_idx.keys(): impropers_shared_idx[idx1] = ( impropers0_idx[idx0], impropers1_idx[idx1], @@ -3192,6 +3205,7 @@ def _somd1_compatibility(system): from sire.legacy import CAS as _SireCAS from sire.legacy import MM as _SireMM from sire.legacy import Mol as _SireMol + from .._SireWrappers import System as _System # Check the system is a Sire system. @@ -3607,7 +3621,7 @@ def _somd1_compatibility(system): for idx0 in impropers0_idx.keys(): if idx1.equivalent(idx0): # Don't store duplicates. - if not idx0 in impropers_shared_idx.keys(): + if idx0 not in impropers_shared_idx.keys(): impropers_shared_idx[idx1] = ( impropers0_idx[idx0], impropers1_idx[idx1], diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_task.py b/src/BioSimSpace/Process/_task.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_task.py rename to src/BioSimSpace/Process/_task.py index c7c3d39b1..b42b6c5f3 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_task.py +++ b/src/BioSimSpace/Process/_task.py @@ -247,10 +247,12 @@ def getOutput(self, filename=None, file_link=False): The name of, or link to, a zipfile containing the output. """ import glob as _glob - from .. import _is_notebook + import os as _os import zipfile as _zipfile + from IPython.display import FileLink as _FileLink - import os as _os + + from .. import _is_notebook # Don't recreate an existing zip file. if self._zipfile is None: diff --git a/python/BioSimSpace/Process/_utils.py b/src/BioSimSpace/Process/_utils.py similarity index 100% rename from python/BioSimSpace/Process/_utils.py rename to src/BioSimSpace/Process/_utils.py diff --git a/python/BioSimSpace/Protocol/__init__.py b/src/BioSimSpace/Protocol/__init__.py similarity index 100% rename from python/BioSimSpace/Protocol/__init__.py rename to src/BioSimSpace/Protocol/__init__.py index b5ee0d179..fa0b3e4d6 100644 --- a/python/BioSimSpace/Protocol/__init__.py +++ b/src/BioSimSpace/Protocol/__init__.py @@ -104,6 +104,7 @@ _sr.use_new_api() del _sr +from ._atm import * from ._custom import * from ._equilibration import * from ._free_energy_equilibration import * @@ -114,4 +115,3 @@ from ._production import * from ._steering import * from ._utils import * -from ._atm import * diff --git a/python/BioSimSpace/Protocol/_atm.py b/src/BioSimSpace/Protocol/_atm.py similarity index 99% rename from python/BioSimSpace/Protocol/_atm.py rename to src/BioSimSpace/Protocol/_atm.py index a19d4ae78..4869b41b1 100644 --- a/python/BioSimSpace/Protocol/_atm.py +++ b/src/BioSimSpace/Protocol/_atm.py @@ -1,6 +1,6 @@ -from ._protocol import Protocol as _Protocol -from ._position_restraint_mixin import _PositionRestraintMixin from .. import Units as _Units +from ._position_restraint_mixin import _PositionRestraintMixin +from ._protocol import Protocol as _Protocol __all__ = ["ATMMinimisation", "ATMEquilibration", "ATMAnnealing", "ATMProduction"] @@ -27,9 +27,10 @@ def __init__( ): # Call the base class constructor. import json as _json + import warnings as _warnings + from .._SireWrappers import System as _System from ..Types import Vector as _Vector - import warnings as _warnings super().__init__() @@ -1152,6 +1153,7 @@ def setStartTemperature(self, temperature): The starting temperature. """ import math as _math + from .. import Types as _Types if isinstance(temperature, str): @@ -1191,6 +1193,7 @@ def setEndTemperature(self, temperature): The final temperature. """ import math as _math + from .. import Types as _Types if isinstance(temperature, str): @@ -1303,7 +1306,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -1340,7 +1343,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: @@ -2115,7 +2118,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -2152,7 +2155,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: @@ -3001,7 +3004,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -3038,7 +3041,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: @@ -3174,9 +3177,10 @@ def setLambda1(self, lambda1): lambda1 : [float] The lambda1 values. """ - import numpy as _np import math as _math + import numpy as _np + if isinstance(lambda1, list): if len(lambda1) != self._num_lambda: raise ValueError("'lambda1' must have the same length as 'num_lambda'") @@ -3223,9 +3227,10 @@ def setLambda2(self, lambda2): lambda2 : [float] The lambda2 values. """ - import numpy as _np import math as _math + import numpy as _np + if isinstance(lambda2, list): if len(lambda2) != self._num_lambda: raise ValueError("'lambda2' must have the same length as 'num_lambda'") diff --git a/python/BioSimSpace/Protocol/_custom.py b/src/BioSimSpace/Protocol/_custom.py similarity index 100% rename from python/BioSimSpace/Protocol/_custom.py rename to src/BioSimSpace/Protocol/_custom.py diff --git a/python/BioSimSpace/Protocol/_equilibration.py b/src/BioSimSpace/Protocol/_equilibration.py similarity index 99% rename from python/BioSimSpace/Protocol/_equilibration.py rename to src/BioSimSpace/Protocol/_equilibration.py index c5543152c..0703a7713 100644 --- a/python/BioSimSpace/Protocol/_equilibration.py +++ b/src/BioSimSpace/Protocol/_equilibration.py @@ -29,7 +29,6 @@ from .. import Types as _Types from .. import Units as _Units - from ._position_restraint_mixin import _PositionRestraintMixin from ._protocol import Protocol as _Protocol @@ -451,7 +450,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -488,7 +487,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Protocol/_free_energy_equilibration.py b/src/BioSimSpace/Protocol/_free_energy_equilibration.py similarity index 99% rename from python/BioSimSpace/Protocol/_free_energy_equilibration.py rename to src/BioSimSpace/Protocol/_free_energy_equilibration.py index fc539bcfa..d0ade349b 100644 --- a/python/BioSimSpace/Protocol/_free_energy_equilibration.py +++ b/src/BioSimSpace/Protocol/_free_energy_equilibration.py @@ -28,9 +28,8 @@ from .. import Types as _Types from .. import Units as _Units - -from ._free_energy_mixin import _FreeEnergyMixin from ._equilibration import Equilibration as _Equilibration +from ._free_energy_mixin import _FreeEnergyMixin class FreeEnergyEquilibration(_Equilibration, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Protocol/_free_energy_minimisation.py b/src/BioSimSpace/Protocol/_free_energy_minimisation.py similarity index 100% rename from python/BioSimSpace/Protocol/_free_energy_minimisation.py rename to src/BioSimSpace/Protocol/_free_energy_minimisation.py index 4a52b74dd..ac7c7fcb4 100644 --- a/python/BioSimSpace/Protocol/_free_energy_minimisation.py +++ b/src/BioSimSpace/Protocol/_free_energy_minimisation.py @@ -23,9 +23,9 @@ __all__ = ["FreeEnergyMinimisation"] +from .. import Units as _Units from ._free_energy_mixin import _FreeEnergyMixin from ._minimisation import Minimisation as _Minimisation -from .. import Units as _Units class FreeEnergyMinimisation(_Minimisation, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Protocol/_free_energy_mixin.py b/src/BioSimSpace/Protocol/_free_energy_mixin.py similarity index 98% rename from python/BioSimSpace/Protocol/_free_energy_mixin.py rename to src/BioSimSpace/Protocol/_free_energy_mixin.py index 555ba6f5c..22f3f1f69 100644 --- a/python/BioSimSpace/Protocol/_free_energy_mixin.py +++ b/src/BioSimSpace/Protocol/_free_energy_mixin.py @@ -260,7 +260,7 @@ def setLambdaValues( raise ValueError("'lam_vals' cannot contain duplicate values!") # Make sure the lambda value is in the list. - if not lam in lam_vals: + if lam not in lam_vals: raise ValueError("'lam' is not a member of the 'lam_vals' list!") # Set the values. @@ -283,7 +283,7 @@ def setLambdaValues( if not isinstance(max_lam, float): raise TypeError("'max_lam' must be of type 'float'.") - if not type(num_lam) is int: + if type(num_lam) is not int: raise TypeError("'num_lam' must be of type 'int'.") # Validate values. @@ -309,7 +309,7 @@ def setLambdaValues( self._lambda_vals.append(round(min_lam + (x * step), 5)) # Make sure the lambda value is in the list. - if not self._lambda in self._lambda_vals: + if self._lambda not in self._lambda_vals: raise ValueError( "'lam' (%5.4f) is not a member of the 'lam_vals' list: %s" % (self._lambda, self._lambda_vals) diff --git a/python/BioSimSpace/Protocol/_free_energy_production.py b/src/BioSimSpace/Protocol/_free_energy_production.py similarity index 100% rename from python/BioSimSpace/Protocol/_free_energy_production.py rename to src/BioSimSpace/Protocol/_free_energy_production.py index 9c620120c..52cb13633 100644 --- a/python/BioSimSpace/Protocol/_free_energy_production.py +++ b/src/BioSimSpace/Protocol/_free_energy_production.py @@ -26,10 +26,10 @@ __all__ = ["FreeEnergy", "FreeEnergyProduction"] -from ._free_energy_mixin import _FreeEnergyMixin -from ._production import Production as _Production from .. import Types as _Types from .. import Units as _Units +from ._free_energy_mixin import _FreeEnergyMixin +from ._production import Production as _Production class FreeEnergyProduction(_Production, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Protocol/_metadynamics.py b/src/BioSimSpace/Protocol/_metadynamics.py similarity index 99% rename from python/BioSimSpace/Protocol/_metadynamics.py rename to src/BioSimSpace/Protocol/_metadynamics.py index 242f171f7..14a74d183 100644 --- a/python/BioSimSpace/Protocol/_metadynamics.py +++ b/src/BioSimSpace/Protocol/_metadynamics.py @@ -29,7 +29,6 @@ from .. import Types as _Types from ..Metadynamics import CollectiveVariable as _CollectiveVariable - from ._protocol import Protocol as _Protocol # Store the collective variable base type. @@ -564,7 +563,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -601,7 +600,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Protocol/_minimisation.py b/src/BioSimSpace/Protocol/_minimisation.py similarity index 99% rename from python/BioSimSpace/Protocol/_minimisation.py rename to src/BioSimSpace/Protocol/_minimisation.py index 9b278f76b..31c21ae93 100644 --- a/python/BioSimSpace/Protocol/_minimisation.py +++ b/src/BioSimSpace/Protocol/_minimisation.py @@ -28,7 +28,6 @@ from .. import Units as _Units - from ._position_restraint_mixin import _PositionRestraintMixin from ._protocol import Protocol as _Protocol @@ -135,7 +134,7 @@ def setSteps(self, steps): """ import warnings as _warnings - if not type(steps) is int: + if type(steps) is not int: raise TypeError("'steps' must be of type 'int'") if steps <= 0: diff --git a/python/BioSimSpace/Protocol/_position_restraint_mixin.py b/src/BioSimSpace/Protocol/_position_restraint_mixin.py similarity index 100% rename from python/BioSimSpace/Protocol/_position_restraint_mixin.py rename to src/BioSimSpace/Protocol/_position_restraint_mixin.py diff --git a/python/BioSimSpace/Protocol/_production.py b/src/BioSimSpace/Protocol/_production.py similarity index 99% rename from python/BioSimSpace/Protocol/_production.py rename to src/BioSimSpace/Protocol/_production.py index b15f88934..4d01f3e0a 100644 --- a/python/BioSimSpace/Protocol/_production.py +++ b/src/BioSimSpace/Protocol/_production.py @@ -29,7 +29,6 @@ from .. import Types as _Types from .. import Units as _Units - from ._position_restraint_mixin import _PositionRestraintMixin from ._protocol import Protocol as _Protocol @@ -380,7 +379,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -417,7 +416,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Protocol/_protocol.py b/src/BioSimSpace/Protocol/_protocol.py similarity index 100% rename from python/BioSimSpace/Protocol/_protocol.py rename to src/BioSimSpace/Protocol/_protocol.py diff --git a/python/BioSimSpace/Protocol/_steering.py b/src/BioSimSpace/Protocol/_steering.py similarity index 99% rename from python/BioSimSpace/Protocol/_steering.py rename to src/BioSimSpace/Protocol/_steering.py index 8602ac2ef..53fe86a29 100644 --- a/python/BioSimSpace/Protocol/_steering.py +++ b/src/BioSimSpace/Protocol/_steering.py @@ -29,7 +29,6 @@ from .. import Types as _Types from ..Metadynamics import CollectiveVariable as _CollectiveVariable - from ._protocol import Protocol as _Protocol # Store the collective variable base type. @@ -658,7 +657,7 @@ def setReportInterval(self, report_interval): report_interval : int The number of integration steps between reporting statistics. """ - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -693,7 +692,7 @@ def setRestartInterval(self, restart_interval): The number of integration steps between saving restart configurations and/or trajectory frames. """ - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Protocol/_utils.py b/src/BioSimSpace/Protocol/_utils.py similarity index 100% rename from python/BioSimSpace/Protocol/_utils.py rename to src/BioSimSpace/Protocol/_utils.py index a5ce1be48..4aee6a50a 100644 --- a/python/BioSimSpace/Protocol/_utils.py +++ b/src/BioSimSpace/Protocol/_utils.py @@ -28,8 +28,8 @@ from ._custom import * from ._equilibration import * -from ._free_energy_minimisation import * from ._free_energy_equilibration import * +from ._free_energy_minimisation import * from ._free_energy_production import * from ._metadynamics import * from ._minimisation import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Align/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Align/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/__init__.py index 43d31f2a3..f73b0f9e2 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/__init__.py @@ -48,5 +48,5 @@ from ._align import * from ._decouple import * -from ._squash import * from ._ml import * +from ._squash import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py index 220cc2551..1d84c5204 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_alch_ion.py @@ -25,6 +25,7 @@ def _mark_alchemical_ion(molecule): The molecule marked as being alchemical ion. """ import warnings + from .._SireWrappers import Molecule as _Molecule # Validate input. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_align.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_align.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_align.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_align.py index 7ef9527e6..6ff9b757e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_align.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_align.py @@ -34,10 +34,10 @@ ] -from .._Utils import _try_import, _have_imported - import warnings as _warnings +from .._Utils import _have_imported, _try_import + # Suppress duplicate to-Python converted warnings. # Both Sire and RDKit register the same converter. with _warnings.catch_warnings(): @@ -46,8 +46,8 @@ if _have_imported(_rdkit): from rdkit import Chem as _Chem - from rdkit.Chem import rdFMCS as _rdFMCS from rdkit import RDLogger as _RDLogger + from rdkit.Chem import rdFMCS as _rdFMCS # Disable RDKit warnings. _RDLogger.DisableLog("rdApp.*") @@ -58,7 +58,6 @@ from sire.legacy import Base as _SireBase - from .. import Units as _Units # lomap depends on RDKit and networkx @@ -167,14 +166,14 @@ def generateNetwork( perturbation between molecules along an edge is likely to be more accurate. """ - from .. import _Utils - from .. import _is_notebook, _isVerbose - from .._SireWrappers import Molecule as _Molecule - from .._Utils import _assert_imported import csv as _csv + import os as _os + from .. import IO as _IO + from .. import _is_notebook, _isVerbose, _Utils from .._Exceptions import AlignmentError as _AlignmentError - import os as _os + from .._SireWrappers import Molecule as _Molecule + from .._Utils import _assert_imported # Adapted from code by Jenke Scheen (@JenkeScheen). @@ -265,9 +264,9 @@ def generateNetwork( ) # Make sure that the ligands are in the names list. - if not records[0] in names: + if records[0] not in names: raise ValueError(f"Ligand '{records[0]}' not in 'names' list!") - if not records[1] in names: + if records[1] not in names: raise ValueError(f"Ligand '{records[1]}' not in 'names' list!") else: @@ -275,7 +274,7 @@ def generateNetwork( # Validate the number of edges parameter. if n_edges_forced is not None: - if not type(n_edges_forced) is int: + if type(n_edges_forced) is not int: raise TypeError("'n_edges_forced' must be of type 'int'") n_edges_fully_connected = int((len(molecules) ** 2 - len(molecules)) / 2) + 1 @@ -470,7 +469,7 @@ def generateNetwork( # Update the list while checking that the inverse edge is not already in # the network. - if not (mol1, mol0) in edges: + if (mol1, mol0) not in edges: edges_excluded.append((mol0, mol1, score)) # If the user has specified a forced number of edges, adjust the network @@ -837,12 +836,14 @@ def matchAtoms( >>> import BioSimSpace as BSS >>> mapping = BSS.Align.matchAtoms(molecule0, molecule1, prematch={0 : 10, 3 : 7}) """ - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError import sys as _sys + + from sire.legacy import Mol as _SireMol + from sire.legacy import Units as _SireUnits + from .. import Convert as _Convert + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from .._SireWrappers import Molecule as _Molecule - from sire.legacy import Units as _SireUnits - from sire.legacy import Mol as _SireMol # A list of supported scoring functions. scoring_functions = ["RMSD", "RMSDALIGN", "RMSDFLEXALIGN"] @@ -865,7 +866,7 @@ def matchAtoms( # Strip underscores and whitespace, then convert to upper case. _scoring_function = scoring_function.replace("_", "").upper() _scoring_function = _scoring_function.replace(" ", "").upper() - if not _scoring_function in scoring_functions: + if _scoring_function not in scoring_functions: raise ValueError( "Unsupported scoring function '%s'. Options are: %s" % (scoring_function, scoring_functions) @@ -877,7 +878,7 @@ def matchAtoms( "https://pdbj.org/kcombu" ) - if not type(matches) is int: + if type(matches) is not int: raise TypeError("'matches' must be of type 'int'") else: if matches < 0: @@ -894,7 +895,7 @@ def matchAtoms( if not isinstance(timeout, _Units.Time._Time): raise TypeError("'timeout' must be of type 'BioSimSpace.Types.Time'") - if not type(max_scoring_matches) is int: + if type(max_scoring_matches) is not int: raise TypeError("'max_scoring_matches' must be of type 'int'") if max_scoring_matches <= 0: @@ -1110,10 +1111,11 @@ def rmsdAlign(molecule0, molecule1, mapping=None, property_map0={}, property_map >>> import BioSimSpace as BSS >>> molecule0 = BSS.Align.rmsdAlign(molecule0, molecule1) """ + from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from .._Exceptions import AlignmentError as _AlignmentError from .._SireWrappers import Molecule as _Molecule - from .. import _isVerbose - from sire.legacy import Mol as _SireMol if not isinstance(molecule0, _Molecule): raise TypeError( @@ -1249,13 +1251,14 @@ def flexAlign( >>> import BioSimSpace as BSS >>> molecule0 = BSS.Align.flexAlign(molecule0, molecule1) """ - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from .. import _Utils + import os as _os import subprocess as _subprocess - from .._SireWrappers import Molecule as _Molecule + from .. import IO as _IO + from .. import _Utils from .._Exceptions import AlignmentError as _AlignmentError - import os as _os + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from .._SireWrappers import Molecule as _Molecule # Check that we found fkcombu in the PATH. if fkcombu_exe is None: @@ -1561,12 +1564,11 @@ def viewMapping( labelled. """ from .. import Convert as _Convert + from .. import _is_notebook from .._SireWrappers import Molecule as _Molecule from .._Utils import _assert_imported - from .. import _is_notebook # Adapted from: https://gist.github.com/cisert/d05664d4c98ac1cf86ee70b8700e56a9 - # Only draw within a notebook. if not _is_notebook: return None @@ -1606,7 +1608,7 @@ def viewMapping( if isinstance(pixels, float): pixels = int(pixels) - if not type(pixels) is int: + if type(pixels) is not int: raise TypeError("'pixels' must be of type 'int'") if pixels <= 0: raise ValueError("pixels' must be > 0!") @@ -1774,14 +1776,14 @@ def _score_rdkit_mappings( mapping, scores : ([dict], list) The ranked mappings and corresponding scores. """ - from .. import _isVerbose - from .._SireWrappers import Molecule as _Molecule + from sire.legacy import Maths as _SireMaths from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from .._Exceptions import AlignmentError as _AlignmentError - from sire.legacy import Maths as _SireMaths + from .._SireWrappers import Molecule as _Molecule # Adapted from FESetup: https://github.com/CCPBioSim/fesetup - # Make sure to re-map the coordinates property in both molecules, otherwise # the move and align functions from Sire will not work. prop0 = property_map0.get("coordinates", "coordinates") @@ -1856,7 +1858,7 @@ def _score_rdkit_mappings( } # This is a new mapping: - if not mapping in mappings: + if mapping not in mappings: # Check that the mapping contains the pre-match. is_valid = True for idx0, idx1 in prematch.items(): @@ -2011,11 +2013,12 @@ def _score_sire_mappings( mapping, scores : ([dict], list) The ranked mappings and corresponding scores. """ - from .. import _isVerbose - from .._SireWrappers import Molecule as _Molecule + from sire.legacy import Maths as _SireMaths from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from .._Exceptions import AlignmentError as _AlignmentError - from sire.legacy import Maths as _SireMaths + from .._SireWrappers import Molecule as _Molecule # Make sure to re-map the coordinates property in both molecules, otherwise # the move and align functions from Sire will not work. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py index 07d2189c7..c2f88fcaf 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_decouple.py @@ -44,9 +44,10 @@ def decouple( decoupled : Sire.Mol.Molecule The molecule marked as being decoupled. """ + from sire.legacy import Base as _SireBase + from .._Exceptions import IncompatibleError as _IncompatibleError from .._SireWrappers import Molecule as _Molecule - from sire.legacy import Base as _SireBase # Validate input. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_merge.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_merge.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_merge.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_merge.py index edf02eb67..acded1402 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_merge.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_merge.py @@ -85,11 +85,12 @@ def merge( The merged molecule. """ from sire.legacy import MM as _SireMM - from sire.legacy import Units as _SireUnits - from .._SireWrappers import Molecule as _Molecule - from .._Exceptions import IncompatibleError as _IncompatibleError from sire.legacy import Base as _SireBase from sire.legacy import Mol as _SireMol + from sire.legacy import Units as _SireUnits + + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule # Validate input. @@ -321,7 +322,7 @@ def merge( # lambda = 0 for prop in props0: - if not prop in ignored_props: + if prop not in ignored_props: # This is a perturbable property. if prop in shared_props: name = f"{prop}0" @@ -341,7 +342,7 @@ def merge( # lambda = 1 for prop in props1: - if not prop in ignored_props: + if prop not in ignored_props: # This is a perturbable property. if prop in shared_props: name = f"{prop}1" @@ -1591,10 +1592,11 @@ def _removeDummies(molecule, is_lambda1): is_lambda1 : bool Whether to use the molecule at lambda = 1. """ - from .._SireWrappers import Molecule as _Molecule - from .._Exceptions import IncompatibleError as _IncompatibleError - from sire.legacy import Mol as _SireMol from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule if not molecule._is_perturbable: raise _IncompatibleError("'molecule' is not a perturbable molecule") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_ml.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_ml.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_ml.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_ml.py index d97856ba2..a98faba2c 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_ml.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_ml.py @@ -24,8 +24,8 @@ def make_ml(molecule): ML_molecule : BSS._SireWrappers.Molecule The molecule marked as being ML. """ - from .._SireWrappers import Molecule as _Molecule from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule # Validate input. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Align/_squash.py b/src/BioSimSpace/Sandpit/Exscientia/Align/_squash.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Align/_squash.py rename to src/BioSimSpace/Sandpit/Exscientia/Align/_squash.py index 8ef08d5a7..fe6832b4e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Align/_squash.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Align/_squash.py @@ -96,12 +96,14 @@ def _squash_molecule(molecule, explicit_dummies=False): system : BioSimSpace._SireWrappers.System The output squashed system. """ - from ..IO import readMolecules as _readMolecules, saveMolecules as _saveMolecules - from ._merge import _removeDummies + import os as _os import shutil as _shutil import tempfile - import os as _os + from .._SireWrappers import Molecule as _Molecule + from ..IO import readMolecules as _readMolecules + from ..IO import saveMolecules as _saveMolecules + from ._merge import _removeDummies if not molecule.isPerturbable(): return molecule @@ -289,6 +291,7 @@ def _unsquash_molecule(molecule, squashed_molecules, explicit_dummies=False): The output updated merged molecule. """ from sire.legacy import Mol as _SireMol + from .._SireWrappers import Molecule as _Molecule # Get the common core atoms @@ -443,9 +446,10 @@ def _squashed_atom_mapping(system, is_lambda1=False, environment=True, **kwargs) mapping : dict(int, int) The corresponding atom mapping. """ - from .._SireWrappers import Molecule as _Molecule import numpy as _np + from .._SireWrappers import Molecule as _Molecule + if isinstance(system, _Molecule): return _squashed_atom_mapping( system.toSystem(), is_lambda1=is_lambda1, environment=environment, **kwargs diff --git a/python/BioSimSpace/Sandpit/Exscientia/Box/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Box/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Box/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Box/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Box/_box.py b/src/BioSimSpace/Sandpit/Exscientia/Box/_box.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Box/_box.py rename to src/BioSimSpace/Sandpit/Exscientia/Box/_box.py index 1c120756f..1d7a6c61a 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Box/_box.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Box/_box.py @@ -89,8 +89,8 @@ def cubic(image_distance): angles : [:class:`Angle `] The box vector angles: yz, xz, and xy. """ - from ..Types import Length as _Length from ..Types import Angle as _Angle + from ..Types import Length as _Length # Validate arguments. @@ -126,6 +126,7 @@ def rhombicDodecahedronSquare(image_distance): The box vector angles: yz, xz, and xy. """ from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length # Validate arguments. @@ -165,6 +166,7 @@ def rhombicDodecahedronHexagon(image_distance): The box vector angles: yz, xz, and xy. """ from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length # Validate arguments. @@ -204,6 +206,7 @@ def truncatedOctahedron(image_distance): The box vector angles: yz, xz, and xy. """ from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from ..Types import Length as _Length # Validate arguments. @@ -238,9 +241,10 @@ def _get_box_parameters(triclinic_box): box : [:class:`Length `] The box vector magnitudes. """ - from ..Types import Length as _Length from sire.legacy.Maths import Vector as _Vector + from ..Types import Angle as _Angle + from ..Types import Length as _Length box = [ _Length(triclinic_box.vector0().magnitude(), "angstrom"), diff --git a/python/BioSimSpace/Sandpit/Exscientia/Convert/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Convert/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Convert/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Convert/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py b/src/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py rename to src/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py index 717334842..c71ead665 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Convert/_convert.py @@ -72,9 +72,10 @@ def smiles( molecule : :class:`Molecule ` A BioSimSpace molecule. """ - from .._Exceptions import ConversionError as _ConversionError from sire import smiles as _sire_smiles + from .. import _SireWrappers + from .._Exceptions import ConversionError as _ConversionError if not isinstance(smiles_string, str): raise TypeError("'smiles_string' must be of type 'str'.") @@ -158,16 +159,17 @@ def to(obj, format="biosimspace", property_map={}, **kwargs): converted_obj : The object in the converted format. """ - from sire import convert as _sire_convert - from .._Utils import _have_imported - from .. import _SireWrappers import sire.legacy.Base as _SireBase - from .._Exceptions import ConversionError as _ConversionError - import sire.system as _NewSireSystem - import sire.legacy.Vol as _SireVol import sire.legacy.Mol as _SireMol - from rdkit.Chem.rdchem import Mol as _RDMol import sire.legacy.System as _SireSystem + import sire.legacy.Vol as _SireVol + import sire.system as _NewSireSystem + from rdkit.Chem.rdchem import Mol as _RDMol + from sire import convert as _sire_convert + + from .. import _SireWrappers + from .._Exceptions import ConversionError as _ConversionError + from .._Utils import _have_imported # Validate the input. @@ -177,7 +179,7 @@ def to(obj, format="biosimspace", property_map={}, **kwargs): # Convert to lower case and strip whitespace. format = format.lower().replace(" ", "") - if not format in supportedFormats(): + if format not in supportedFormats(): raise ValueError( f"Unsupported format '{format}', options are: {', '.join(supportedFormats())}." ) @@ -611,9 +613,10 @@ def _to_rdkit(molecule, work_dir=_os.getcwd(), direct=True, property_map={}): The molecule in RDKit format. """ import rdkit.Chem as _Chem + + from .. import IO as _IO from .. import _SireWrappers from .._Exceptions import ConversionError as _ConversionError - from .. import IO as _IO if not isinstance(molecule, _SireWrappers.Molecule): raise TypeError( diff --git a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py index a51fa95df..0dc31833c 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/__init__.py @@ -48,6 +48,6 @@ del _sr from ._alchemical_free_energy import * -from ._utils import * from ._restraint import * from ._restraint_search import * +from ._utils import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py similarity index 97% rename from python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py rename to src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py index fffe510c1..dbb6db306 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py +++ b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_alchemical_free_energy.py @@ -30,37 +30,17 @@ import os as _os import sys as _sys -from .._Utils import _have_imported, _try_import +from .._Utils import _try_import # alchemlyb isn't available on all variants of Python that we support, so we # need to try_import it. _alchemlyb = _try_import("alchemlyb") -if _have_imported(_alchemlyb): - from alchemlyb.workflows import ABFE - from alchemlyb.postprocessors.units import R_kJmol as _R_kJmol - from alchemlyb.postprocessors.units import kJ2kcal as _kJ2kcal - from alchemlyb.preprocessing.subsampling import ( - statistical_inefficiency as _statistical_inefficiency, - ) - - try: - from alchemlyb.estimators import AutoMBAR as _AutoMBAR - except ImportError: - from alchemlyb.estimators import MBAR as _AutoMBAR - from alchemlyb.estimators import TI as _TI - from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol - from sire.legacy.Base import getBinDir as _getBinDir from sire.legacy.Base import getShareDir as _getShareDir - -from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from .. import _is_notebook - - -if _is_notebook: - from IPython.display import FileLink as _FileLink +from .._Exceptions import MissingSoftwareError as _MissingSoftwareError # Check that the analyse_freenrg script exists. if _sys.platform != "win32": @@ -167,13 +147,13 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ._restraint import Restraint as _Restraint import warnings as _warnings - from .. import _gmx_exe - from .. import _Utils - from ..MD._md import _find_md_engines - from .._SireWrappers import System as _System + from .. import Protocol as _Protocol + from .. import _gmx_exe, _Utils + from .._SireWrappers import System as _System + from ..MD._md import _find_md_engines + from ._restraint import Restraint as _Restraint # Validate the input. @@ -455,10 +435,10 @@ def getData(self, name="data", file_link=False, work_dir=None): output : str, IPython.display.FileLink A path, or file link, to an archive of the process input. """ + import zipfile as _zipfile from glob import glob as _glob + from .._Utils import cd as _cd - from IPython.display import FileLink as _FileLink - import zipfile as _zipfile if self._work_dir is None: raise ValueError("'work_dir' must be set!") @@ -500,6 +480,8 @@ def getData(self, name="data", file_link=False, work_dir=None): # Return a link to the archive. if _is_notebook: if file_link: + from IPython.display import FileLink as _FileLink + # Create a FileLink to the archive. f_link = _FileLink(zipname) @@ -550,8 +532,9 @@ def analyse(work_dir, temperature=None, estimator="MBAR", **kwargs): window. """ from glob import glob as _glob - from .._Utils import _assert_imported + from .. import Types as _Types + from .._Utils import _assert_imported _assert_imported(_alchemlyb) @@ -661,8 +644,9 @@ def _analyse_noSOMD( The overlap matrix. This gives the overlap between each lambda window. For TI, this gives the dhdl. """ - from alchemlyb.workflows import ABFE from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol + from alchemlyb.workflows import ABFE + from .. import Units as _Units if not isinstance(work_dir, str): @@ -763,15 +747,20 @@ def _analyse_somd(work_dir=None, estimator=None): The overlap matrix. This gives the overlap between each lambda window. For TI, this gives the dhdl. """ - from alchemlyb.estimators import MBAR as _AutoMBAR from glob import glob as _glob + + try: + from alchemlyb.estimators import AutoMBAR as _AutoMBAR + except ImportError: + from alchemlyb.estimators import MBAR as _AutoMBAR + from alchemlyb.estimators import TI as _TI from alchemlyb.postprocessors.units import to_kcalmol as _to_kcalmol - from .. import Units as _Units from alchemlyb.preprocessing.subsampling import ( statistical_inefficiency as _statistical_inefficiency, ) + + from .. import Units as _Units from .._Exceptions import AnalysisError as _AnalysisError - from alchemlyb.estimators import TI as _TI if not isinstance(work_dir, str): raise TypeError("'work_dir' must be of type 'str'.") @@ -839,8 +828,8 @@ def _somd_extract_u_nk(simfile, T): u_nk : DataFrame Reduced potential for each alchemical state (k) for each frame (n). """ - import pandas as _pd import numpy as _np + import pandas as _pd # open the file - check if it is okay, if not raise an error file = simfile @@ -874,9 +863,7 @@ def _somd_extract_u_nk(simfile, T): .replace("(", "") .replace(")", "") .replace(" ", "") - ).split( - "," - ) # list + ).split(",") # list if lambda_array is not None: found_array = True if start_t and end_t in line: @@ -924,9 +911,7 @@ def _somd_extract_u_nk(simfile, T): time_rows = _np.arange(0, len(file_df["step"]), 1) time = _np.arange(0, sim_length, time_step) - mbar_energies = ( - [] - ) # results in list of lists where each list is 0 to 1 window values + mbar_energies = [] # results in list of lists where each list is 0 to 1 window values # # so for the energies for each lambda, append the kt to the data list of vals for all lambda wins # then trun into df @@ -967,10 +952,10 @@ def _somd_extract_dHdl(simfile, T): dH/dl : Series dH/dl as a function of time for this lambda window. """ + import numpy as _np + import pandas as _pd from alchemlyb.postprocessors.units import R_kJmol as _R_kJmol from alchemlyb.postprocessors.units import kJ2kcal as _kJ2kcal - import pandas as _pd - import numpy as _np # open the file file = simfile @@ -1003,9 +988,7 @@ def _somd_extract_dHdl(simfile, T): .replace("(", "") .replace(")", "") .replace(" ", "") - ).split( - "," - ) # list + ).split(",") # list if lambda_array is not None: found_array = True if start_t and end_t in line: @@ -1207,9 +1190,10 @@ def difference(pmf, pmf_ref): free_energy : (:class:`Energy `, :class:`Energy `) The relative free-energy difference and its associated error. """ - from .. import Units as _Units import math as _math + from .. import Types as _Types + from .. import Units as _Units if not isinstance(pmf, list): raise TypeError("'pmf' must be of type 'list'.") @@ -1315,8 +1299,9 @@ def _initialise_runner(self, system): system : :class:`System ` The molecular system. """ - import shutil as _shutil import copy as _copy + import shutil as _shutil + from .. import Process as _Process # Initialise list to store the processes diff --git a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py similarity index 98% rename from python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py rename to src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py index ad1c93410..a62c71592 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py +++ b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint.py @@ -22,12 +22,15 @@ """ A class for holding restraints. """ + from typing import Literal def sqrt(u): - from sire.units import GeneralUnit as _sire_GeneralUnit import math as _math + + from sire.units import GeneralUnit as _sire_GeneralUnit + from ..Types._general_unit import GeneralUnit as _GeneralUnit dims = u._sire_unit.dimensions() @@ -42,8 +45,10 @@ def sqrt(u): def exp(u): - from sire.units import GeneralUnit as _sire_GeneralUnit import math as _math + + from sire.units import GeneralUnit as _sire_GeneralUnit + from ..Types._general_unit import GeneralUnit as _GeneralUnit dims = u._sire_unit.dimensions() @@ -51,8 +56,9 @@ def exp(u): def erf(u): - from sire.units import GeneralUnit as _sire_GeneralUnit from scipy.special import erf as _erf + from sire.units import GeneralUnit as _sire_GeneralUnit + from ..Types._general_unit import GeneralUnit as _GeneralUnit dims = u._sire_unit.dimensions() @@ -148,17 +154,17 @@ def __init__(self, system, restraint_dict, temperature, restraint_type="Boresch" The type of the restraint. (`Boresch`, `multiple_distance`) """ import warnings as _warnings - from ..Types import ( - Angle as _Angle, - Length as _Length, - Temperature as _Temperature, - ) + import numpy as _np from sire.legacy.Units import k_boltz as _k_boltz - from ..Units.Temperature import kelvin as _kelvin + from .._SireWrappers import Atom as _Atom + from ..Types import Angle as _Angle + from ..Types import Length as _Length + from ..Types import Temperature as _Temperature from ..Units.Angle import radian as _radian from ..Units.Energy import kcal_per_mol as _kcal_per_mol + from ..Units.Temperature import kelvin as _kelvin if not isinstance(temperature, _Temperature): raise ValueError( @@ -377,7 +383,7 @@ def system(self, system): ) for key in ["r1", "r2", "r3"]: atom = self._restraint_dict["anchor_points"][key] - if not atom in system: + if atom not in system: raise ValueError(f"The receptor atom {key} is not in the system.") if self._restraint_type == "multiple_distance": @@ -399,7 +405,7 @@ def system(self, system): f"The ligand atom {ligand_atom} is not from decoupled molecule." ) receptor_atom = single_restraint_dict["r1"] - if not receptor_atom in system: + if receptor_atom not in system: raise ValueError( f"The protein atom {receptor_atom} is not in the system." ) @@ -409,8 +415,9 @@ def system(self, system): def _gromacs_boresch(self, perturbation_type=None, restraint_lambda=False): """Format the Gromacs string for boresch restraint.""" + from ..Units.Angle import degree as _degree + from ..Units.Angle import radian as _radian from ..Units.Energy import kcal_per_mol as _kcal_per_mol - from ..Units.Angle import degree as _degree, radian as _radian # Format the atoms into index list def format_index(key_list): @@ -474,9 +481,10 @@ def format_angle( When restraint_lambda is True, the dihedrals will be stored in the dihedral_restraints. """ - from ..Types._general_unit import GeneralUnit as _GeneralUnit from ..Types import Angle as _Angle - from ..Units.Angle import degree as _degree, radian as _radian + from ..Types._general_unit import GeneralUnit as _GeneralUnit + from ..Units.Angle import degree as _degree + from ..Units.Angle import radian as _radian from ..Units.Energy import kj_per_mol as _kj_per_mol if isinstance(equilibrium_values, _Angle): @@ -770,8 +778,8 @@ def _get_restraint_potential_bond_str(r1, l1, r0, r_fb, kr): def _somd_boresch(self, perturbation_type=None): """Format the SOMD string for the Boresch restraints.""" - from ..Units.Energy import kcal_per_mol as _kcal_per_mol from ..Units.Angle import radian as _radian + from ..Units.Energy import kcal_per_mol as _kcal_per_mol from ..Units.Length import angstrom as _angstrom # Indices @@ -940,19 +948,19 @@ def getCorrection( in kcal / mol. """ import warnings as _warnings - from sire.legacy.Units import ( - angstrom3 as _Sire_angstrom3, - k_boltz as _k_boltz, - meter3 as _Sire_meter3, - mole as _Sire_mole, - ) - from ..Units.Length import angstrom as _angstrom + import numpy as _np from scipy import integrate as _integrate - from ..Units.Temperature import kelvin as _kelvin + from sire.legacy.Units import angstrom3 as _Sire_angstrom3 + from sire.legacy.Units import k_boltz as _k_boltz + from sire.legacy.Units import meter3 as _Sire_meter3 + from sire.legacy.Units import mole as _Sire_mole + from ..Units.Angle import radian as _radian - from ..Units.Energy import kcal_per_mol as _kcal_per_mol from ..Units.Area import angstrom2 as _angstrom2 + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + from ..Units.Length import angstrom as _angstrom + from ..Units.Temperature import kelvin as _kelvin # Constants. Take .value() to avoid issues with ** and log of GeneralUnit v0 = ( @@ -1175,9 +1183,10 @@ def _get_correction(r0, r_fb, kr): be truncated to [0, 8 RT] for practicality. """ import numpy as _np - from ..Units.Energy import kcal_per_mol as _kcal_per_mol from scipy import integrate as _integrate + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + dist_at_8RT = ( 4 * _np.sqrt((R * T) / kr) + r_fb ) # Dist. which gives restraint energy = 8 RT @@ -1212,12 +1221,13 @@ def _get_correction(r0, r_fb, kr): def _schrodinger_analytical_correction(self): # Adapted from DOI: 10.1021/acs.jcim.3c00013 - from ..Types._general_unit import GeneralUnit as _GeneralUnit import numpy as _np from scipy.special import erf as _erf from sire.legacy.Units import k_boltz as _k_boltz - from ..Units.Volume import angstrom3 as _angstrom3 + + from ..Types._general_unit import GeneralUnit as _GeneralUnit from ..Units.Angle import radian as _radian + from ..Units.Volume import angstrom3 as _angstrom3 k_boltz = _GeneralUnit(_k_boltz) beta = 1 / (k_boltz * self.T) @@ -1227,11 +1237,9 @@ def _schrodinger_analytical_correction(self): # Schrodinger uses k(b-b0)**2 kr = self._restraint_dict["force_constants"]["kr"] / 2 - Z_dist = r / (2 * beta * kr) * _np.exp(-beta * kr * r**2) + _np.sqrt( - _np.pi - ) / (4 * beta * kr * sqrt(beta * kr)) * (1 + 2 * beta * kr * r**2) * ( - 1 + _erf(sqrt(beta * kr) * r) - ) + Z_dist = r / (2 * beta * kr) * _np.exp(-beta * kr * r**2) + _np.sqrt(_np.pi) / ( + 4 * beta * kr * sqrt(beta * kr) + ) * (1 + 2 * beta * kr * r**2) * (1 + _erf(sqrt(beta * kr) * r)) Z_angles = [] for angle in ["A", "B"]: @@ -1271,18 +1279,17 @@ def _schrodinger_analytical_correction(self): return dG def _boresch_analytical_correction(self): - from sire.legacy.Units import ( - angstrom3 as _Sire_angstrom3, - k_boltz as _k_boltz, - meter3 as _Sire_meter3, - mole as _Sire_mole, - ) - from ..Units.Length import angstrom as _angstrom import numpy as _np - from ..Units.Temperature import kelvin as _kelvin + from sire.legacy.Units import angstrom3 as _Sire_angstrom3 + from sire.legacy.Units import k_boltz as _k_boltz + from sire.legacy.Units import meter3 as _Sire_meter3 + from sire.legacy.Units import mole as _Sire_mole + from ..Units.Angle import radian as _radian - from ..Units.Energy import kcal_per_mol as _kcal_per_mol from ..Units.Area import angstrom2 as _angstrom2 + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + from ..Units.Length import angstrom as _angstrom + from ..Units.Temperature import kelvin as _kelvin R = ( _k_boltz.value() * _kcal_per_mol / _kelvin diff --git a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py rename to src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py index 185e76e12..b61ffd62f 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py +++ b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_restraint_search.py @@ -31,32 +31,26 @@ import warnings as _warnings - -from ..Units.Length import angstrom as _angstrom -from ..Units.Length import angstrom as _angstrom from .. import _is_notebook +from ..Units.Length import angstrom as _angstrom if _is_notebook: - from tqdm.notebook import tqdm as _tqdm + pass else: - from tqdm import tqdm as _tqdm - -from .._Utils import _try_import, _have_imported + pass +from .._Utils import _have_imported, _try_import if _is_notebook: - from IPython.display import FileLink as _FileLink - from tqdm.notebook import tqdm as _tqdm + pass else: - from tqdm import tqdm as _tqdm + pass _mda = _try_import("MDAnalysis") if _have_imported(_mda): - from MDAnalysis.analysis.distances import dist as _dist - from MDAnalysis.lib.distances import calc_angles as _calc_angles - from MDAnalysis.lib.distances import calc_dihedrals as _calc_dihedrals + pass _MDRestraintsGenerator = _try_import( @@ -67,10 +61,6 @@ from Bio import BiopythonDeprecationWarning _warnings.simplefilter("ignore", BiopythonDeprecationWarning) - from MDRestraintsGenerator import search as _search - from MDRestraintsGenerator.restraints import ( - FindBoreschRestraint as _FindBoreschRestraint, - ) is_MDRestraintsGenerator = _have_imported(_MDRestraintsGenerator) @@ -151,12 +141,12 @@ def __init__( kwargs : Keyword arguments to be passed to the BSS.Process. """ + from .. import Protocol as _Protocol + from .. import _gmx_exe from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from .._SireWrappers import System as _System from .._Utils import WorkDir as _WorkDir - from .. import Protocol as _Protocol from ..MD._md import _find_md_engines - from .. import _gmx_exe # Validate the input. if not _have_imported(_mda): @@ -403,9 +393,10 @@ def _initialise_process(self, system, gpu_support, **kwargs): kwargs : Keyword arguments to be passed to the BSS.Process. """ - from .. import Process as _Process import os as _os + from .. import Process as _Process + # Convert to an appropriate AMBER topology. (Required by SOMD for its # FEP setup.) if self._engine == "SOMD": @@ -545,11 +536,12 @@ def analyse( The restraints of `restraint_type` which best mimic the strongest receptor-ligand interactions. """ - from ..Trajectory._trajectory import Trajectory as _Trajectory - from ..Types import Temperature as _Temperature - from .._SireWrappers import System as _System import os as _os + + from .._SireWrappers import System as _System + from ..Trajectory._trajectory import Trajectory as _Trajectory from ..Types import Length as _Length + from ..Types import Temperature as _Temperature _supported_methods = { "boresch": ["BSS", "MDRestraintsGenerator"], @@ -594,7 +586,7 @@ def analyse( f"restraint_type {type(restraint_type)} must be of type 'str'." ) - if not restraint_type.lower() in RestraintSearch._restraint_types: + if restraint_type.lower() not in RestraintSearch._restraint_types: raise NotImplementedError( f"Restraint type {restraint_type} is not implemented. " f"Please choose from {RestraintSearch._restraint_types}" @@ -602,13 +594,13 @@ def analyse( if not isinstance(method, str): raise TypeError(f"method {type(method)} must be of type 'str'.") - if not method.lower() in ["mdrestraintsgenerator", "bss"]: + if method.lower() not in ["mdrestraintsgenerator", "bss"]: raise NotImplementedError( "Deriving restraints using 'MDRestraintsGenerator'" "or 'BSS' are the only options implemented." ) # Check that the selected method is supported for the selected restraint type. - if not method in _supported_methods[restraint_type.lower()]: + if method not in _supported_methods[restraint_type.lower()]: raise NotImplementedError( f"Method {method} is not supported for restraint type {restraint_type}. " f"Please choose from {_supported_methods[restraint_type.lower()]}" @@ -865,15 +857,16 @@ def _boresch_restraint_MDRestraintsGenerator( The restraints of `restraint_type` which best mimic the strongest receptor-ligand interactions. """ - from ._restraint import Restraint as _Restraint - from ..Units.Angle import degree as _degree - from ..Units.Energy import kcal_per_mol as _kcal_per_mol - from ..Units.Angle import radian as _radian from MDRestraintsGenerator import search as _search from MDRestraintsGenerator.restraints import ( FindBoreschRestraint as _FindBoreschRestraint, ) + from ..Units.Angle import degree as _degree + from ..Units.Angle import radian as _radian + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + from ._restraint import Restraint as _Restraint + print( "Using MDRestraintsGenerator to generate Boresch restraints. If you publish " "any results using this method, please cite: 10.5281/zenodo.4570556 " @@ -1025,11 +1018,12 @@ def _findOrderedPairs(u, ligand_selection_str, receptor_selection_str, cutoff): List of receptor-ligand atom pairs ordered by increasing variance of distance over the trajectory. """ - from .._Exceptions import AnalysisError as _AnalysisError - from MDAnalysis.analysis.distances import dist as _dist import numpy as _np + from MDAnalysis.analysis.distances import dist as _dist from tqdm import tqdm as _tqdm + from .._Exceptions import AnalysisError as _AnalysisError + lig_selection = u.select_atoms(ligand_selection_str) # Ensure that there are no shared atoms between the ligand selection and all possible receptor selections. @@ -1436,13 +1430,14 @@ def _findOrderedBoresch( Dictionary of statistics for the Boresch restraints obtained over the trajectory. Keys are the pair tuples supplied in pair_list. """ - from .._Exceptions import AnalysisError as _AnalysisError - from sire.legacy.Units import k_boltz as _k_boltz - from ..Units.Energy import kcal_per_mol as _kcal_per_mol - from scipy.stats import circmean as _circmean import numpy as _np + from scipy.stats import circmean as _circmean + from sire.legacy.Units import k_boltz as _k_boltz from tqdm import tqdm as _tqdm + from .._Exceptions import AnalysisError as _AnalysisError + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + boresch_dof_list = [ "r", "thetaA", @@ -1724,11 +1719,11 @@ def _getBoreschRestraint(pair, boresch_dof_data): The restraint defined by boresch_dof_data and labelled by pair. """ - from ._restraint import Restraint as _Restraint from .. import Units as _Units from .._Exceptions import AnalysisError as _AnalysisError - from ..Units.Energy import kcal_per_mol as _kcal_per_mol from ..Units.Angle import radian as _radian + from ..Units.Energy import kcal_per_mol as _kcal_per_mol + from ._restraint import Restraint as _Restraint anchor_idxs = { "l1": boresch_dof_data[pair]["anchor_ats"][0], @@ -1967,8 +1962,9 @@ def _multiple_distance_restraint_BSS( interactions. """ import numpy as _np - from ._restraint import Restraint as _Restraint + from .._Exceptions import AnalysisError as _AnalysisError + from ._restraint import Restraint as _Restraint def _get_norm_vector(frame, pair): """ @@ -2100,8 +2096,8 @@ def _plotDistanceRestraints(distance_dict): the keys are the pair indices and the values are lists of distances in Angstroms. """ - import numpy as _np import matplotlib.pyplot as _plt + import numpy as _np n_pairs = len(distance_dict) n_columns = 6 @@ -2188,6 +2184,7 @@ def _getRestraintDict(u, pairs_ordered): The multiple distance restraints dictionary. """ import numpy as _np + from ..Units.Energy import kcal_per_mol as _kcal_per_mol # For each pair, get a list of the distances over the trajectory. diff --git a/python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/FreeEnergy/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py index ac98ea098..3493ffe6c 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Gateway/__init__.py @@ -52,9 +52,10 @@ Temperature Time """ + from ._node import * -from ._resources import * from ._requirements import * +from ._resources import * # Create and initialise the hardware resource manager. ResourceManager = ResourceManager() diff --git a/python/BioSimSpace/Gateway/_node.py b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py similarity index 99% rename from python/BioSimSpace/Gateway/_node.py rename to src/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py index 5e4146498..66d6f45a2 100644 --- a/python/BioSimSpace/Gateway/_node.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py @@ -26,26 +26,18 @@ __all__ = ["Node"] -from .._Utils import _try_import - import configargparse as _argparse +from .._Utils import _try_import + _yaml = _try_import("yaml") from .. import _is_notebook -# Enable Jupyter widgets. -if _is_notebook: - from IPython.display import FileLink as _FileLink - - import ipywidgets as _widgets - import zipfile as _zipfile - - from ._requirements import Area as _Area -from ._requirements import Float as _Float from ._requirements import Charge as _Charge from ._requirements import Energy as _Energy +from ._requirements import Float as _Float from ._requirements import Length as _Length from ._requirements import Mass as _Mass from ._requirements import Pressure as _Pressure @@ -106,14 +98,16 @@ def bind_node(cls, node): def __call__(self, parser, namespace, values, option_string=None): """Export the CWL wrapper.""" - from ._requirements import Integer as _Integer - from ._requirements import FileSet as _FileSet - import sys as _sys - from ._requirements import File as _File import os as _os + import sys as _sys + import __main__ - from ._requirements import String as _String + from ._requirements import Boolean as _Boolean + from ._requirements import File as _File + from ._requirements import FileSet as _FileSet + from ._requirements import Integer as _Integer + from ._requirements import String as _String if values == False: parser.exit() @@ -132,7 +126,6 @@ def __call__(self, parser, namespace, values, option_string=None): exe = _sys.executable # Store the absolute path of the node. - import __main__ node = _os.path.abspath(__main__.__file__) @@ -291,9 +284,10 @@ def __init__(self, description, name=None): name : str The name of the node. """ + import collections as _collections import os as _os + import __main__ - import collections as _collections if not isinstance(description, str): raise TypeError("The 'description' keyword must be of type 'str'.") @@ -425,9 +419,10 @@ def addInput(self, name, input): input : :class:`Requirement ` The input requirement object. """ - from ._requirements import Requirement as _Requirement import warnings as _warnings + from ._requirements import Requirement as _Requirement + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -595,13 +590,14 @@ def _addInputJupyter(self, name, input, reset=False): reset : bool Whether to reset the widget data. """ - from ._requirements import Integer as _Integer + import ipywidgets as _widgets + from ..Types._type import Type as _Type from ._requirements import Boolean as _Boolean - from ._requirements import FileSet as _FileSet from ._requirements import File as _File + from ._requirements import FileSet as _FileSet + from ._requirements import Integer as _Integer from ._requirements import String as _String - import ipywidgets as _widgets # Create a widget button to indicate whether the requirement value # has been set. @@ -953,9 +949,10 @@ def addOutput(self, name, output): output : :class:`Requirement ` The output requirement object. """ - from ._requirements import Requirement as _Requirement import warnings as _warnings + from ._requirements import Requirement as _Requirement + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -986,11 +983,12 @@ def setOutput(self, name, value): value : The value of the output. """ - from ._requirements import FileSet as _FileSet - from ._requirements import File as _File import os as _os - import warnings as _warnings import shutil as _shutil + import warnings as _warnings + + from ._requirements import File as _File + from ._requirements import FileSet as _FileSet try: # Enforce strict naming for all file-based outputs. This ensures @@ -1134,7 +1132,7 @@ def addAuthor(self, name=None, email=None, affiliation=None): self._authors = [{"name": name, "email": email, "affiliation": affiliation}] else: author = {"name": name, "email": email, "affiliation": affiliation} - if not author in self._authors: + if author not in self._authors: self._authors.append(author) def getAuthors(self): @@ -1263,6 +1261,7 @@ def showControls(self): def _validateInput(self): """Validate the parsed inputs.""" import sys as _sys + from .. import setVerbose # Knime. @@ -1314,7 +1313,7 @@ def _validateInput(self): if value is True: self._strict_file_naming = True else: - if not key in ["config", "export_cwl"]: + if key not in ["config", "export_cwl"]: self._inputs[key].setValue(value, name=key) def validate(self, file_prefix="output"): @@ -1335,12 +1334,12 @@ def validate(self, file_prefix="output"): validated output, else the name of a YAML file containing the node output. """ - from ._requirements import FileSet as _FileSet - import sys as _sys - from ._requirements import File as _File import os as _os + import sys as _sys import zipfile as _zipfile - from IPython.display import FileLink as _FileLink + + from ._requirements import File as _File + from ._requirements import FileSet as _FileSet if not isinstance(file_prefix, str): raise TypeError("The 'file_prefix' keyword must be of type 'str'.") @@ -1371,6 +1370,8 @@ def validate(self, file_prefix="output"): # Create a compressed archive containing all file output for the node. if self._is_notebook: + from IPython.display import FileLink as _FileLink + # There are files. if len(file_outputs) > 0: # Create the archive name. diff --git a/python/BioSimSpace/Gateway/_requirements.py b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py similarity index 100% rename from python/BioSimSpace/Gateway/_requirements.py rename to src/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py index 7b5436b85..0ca478fb0 100644 --- a/python/BioSimSpace/Gateway/_requirements.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py @@ -675,8 +675,8 @@ def getValue(self): def _validate(self, value): """Validate that the value is of the correct type.""" - import re as _re import os as _os + import re as _re # Handle optional requirement. if self._is_optional and value is None: @@ -2020,12 +2020,12 @@ def _unarchive(name): files : [ str ] A list of file names. """ - import tarfile as _tarfile + import bz2 as _bz2 import gzip as _gzip import os as _os - import bz2 as _bz2 - import zipfile as _zipfile import shutil as _shutil + import tarfile as _tarfile + import zipfile as _zipfile # Get the directory name. dir = _os.path.dirname(name) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py similarity index 97% rename from python/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py rename to src/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py index 1ce0b14c7..4af26a3c4 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Gateway/_resources.py @@ -99,7 +99,7 @@ def setNodes(self, nodes): The number of nodes. """ - if not type(nodes) is int: + if type(nodes) is not int: raise TypeError("'nodes' must be of type 'int'.") if nodes < 0: @@ -130,7 +130,7 @@ def setCPUs(self, cpus): The number of cpus. """ - if not type(cpus) is int: + if type(cpus) is not int: raise TypeError("'cpus' must be of type 'int'.") if cpus < 0: @@ -161,7 +161,7 @@ def setGPUs(self, gpus): The number of GPUs. """ - if not type(gpus) is int: + if type(gpus) is not int: raise TypeError("'gpus' must be of type 'int'.") if gpus < 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/IO/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/IO/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/IO/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/IO/__init__.py index 00865a000..56f5abd5d 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/IO/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/IO/__init__.py @@ -45,5 +45,5 @@ _sr.use_new_api() del _sr -from ._io import * from ._file_cache import * +from ._io import * diff --git a/python/BioSimSpace/IO/_file_cache.py b/src/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py similarity index 99% rename from python/BioSimSpace/IO/_file_cache.py rename to src/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py index 4a1c59393..7671bd8dd 100644 --- a/python/BioSimSpace/IO/_file_cache.py +++ b/src/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py @@ -160,9 +160,10 @@ def _check_cache( extension : str The extension for cached file. False if no file was found. """ - from .._SireWrappers import System as _System - import shutil as _shutil import os as _os + import shutil as _shutil + + from .._SireWrappers import System as _System # Validate input. @@ -204,7 +205,7 @@ def _check_cache( # Get the existing file path and MD5 hash from the cache. try: - (prev_system, path, original_hash) = _cache[key] + prev_system, path, original_hash = _cache[key] except: return False @@ -292,9 +293,10 @@ def _update_cache( skip_water : bool Whether to skip water molecules when comparing systems. """ - from .._SireWrappers import System as _System import os as _os + from .._SireWrappers import System as _System + # Validate input. if not isinstance(system, _System): diff --git a/python/BioSimSpace/Sandpit/Exscientia/IO/_io.py b/src/BioSimSpace/Sandpit/Exscientia/IO/_io.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/IO/_io.py rename to src/BioSimSpace/Sandpit/Exscientia/IO/_io.py index 16c3445ec..d13496dda 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/IO/_io.py +++ b/src/BioSimSpace/Sandpit/Exscientia/IO/_io.py @@ -37,7 +37,6 @@ from collections import OrderedDict as _OrderedDict - # Flag that we've not yet raised a warning about GROMACS not being installed. _has_gmx_warned = False @@ -230,13 +229,13 @@ def readPDB(id, pdb4amber=False, work_dir=None, show_warnings=False, property_ma >>> import BioSimSpace as BSS >>> system = BSS.IO.readPDB("file.pdb", pdb4amber=True) """ - from .._SireWrappers import System as _System - from .. import _amber_home import os as _os - from .. import _Utils - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError import subprocess as _subprocess + from .. import _amber_home, _Utils + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from .._SireWrappers import System as _System + if not isinstance(id, str): raise TypeError("'id' must be of type 'str'") @@ -408,14 +407,14 @@ def readMolecules( >>> import BioSimSpace as BSS >>> system = BSS.IO.readMolecules(["mol.gro87", "mol.grotop"], property_map={"GROMACS_PATH" : "/path/to/gromacs/topology"}) """ + import os as _os import warnings as _warnings + from glob import glob as _glob + from sire.legacy import Base as _SireBase + + from .. import _gmx_path, _isVerbose, _Utils from .._SireWrappers import System as _System - from .. import _isVerbose - from .. import _gmx_path - from glob import glob as _glob - import os as _os - from .. import _Utils global _has_gmx_warned if _gmx_path is None and not _has_gmx_warned: @@ -655,17 +654,16 @@ def saveMolecules( >>> system = BSS.IO.readMolecules(files, property_map={"charge" : "my-charge"}) >>> BSS.IO.saveMolecules("test", system, ["gro87", "grotop"], property_map={"charge" : "my-charge"}) """ + import os as _os import warnings as _warnings - from .._SireWrappers import Molecule as _Molecule - from .._SireWrappers import System as _System + from sire.legacy import Base as _SireBase - from ._file_cache import _update_cache - from .. import _isVerbose - from ._file_cache import _check_cache - from .. import _gmx_path + + from .. import _gmx_path, _isVerbose + from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Molecules as _Molecules - import os as _os - from ._file_cache import _cache_active + from .._SireWrappers import System as _System + from ._file_cache import _cache_active, _check_cache, _update_cache global _has_gmx_warned if _gmx_path is None and not _has_gmx_warned: @@ -909,8 +907,8 @@ def savePerturbableSystem(filebase, system, save_velocities=True, property_map={ own naming scheme, e.g. { "charge" : "my-charge" } """ from .._SireWrappers import Molecule as _Molecule - from .._SireWrappers import System as _System from .._SireWrappers import Molecules as _Molecules + from .._SireWrappers import System as _System # Check that the filebase is a string. if not isinstance(filebase, str): @@ -1014,9 +1012,10 @@ def readPerturbableSystem(top0, coords0, top1, coords1, property_map={}): system : :class:`System ` A molecular system. """ - from .._SireWrappers import Molecule as _Molecule from sire.legacy import Base as _SireBase + from .. import _isVerbose + from .._SireWrappers import Molecule as _Molecule if not isinstance(top0, str): raise TypeError("'top0' must be of type 'str'.") diff --git a/python/BioSimSpace/Sandpit/Exscientia/MD/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/MD/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/MD/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/MD/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/MD/_md.py b/src/BioSimSpace/Sandpit/Exscientia/MD/_md.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/MD/_md.py rename to src/BioSimSpace/Sandpit/Exscientia/MD/_md.py index a83115b81..aef0c95bc 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/MD/_md.py +++ b/src/BioSimSpace/Sandpit/Exscientia/MD/_md.py @@ -38,7 +38,7 @@ "sander": False, }, "GROMACS": {"gmx": True, "gmx_mpi": True}, - "NAMD": {"namd2": False}, + "NAMD": {"namd3": True, "namd2": False}, "OPENMM": {"sire_python": True}, "SOMD": {"somd": True}, } @@ -114,15 +114,16 @@ def _find_md_engines(system, protocol, engine="AUTO", gpu_support=False): engines, exes : [ str ], [ str ] Lists containing the supported MD engines and executables. """ - from .. import _amber_home, _gmx_exe + import os as _os + from sire.legacy import Base as _SireBase - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from .. import Protocol as _Protocol - import os as _os + from .. import _amber_home, _gmx_exe + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError # The input has already been validated in the run method, so no need # to re-validate here. - # Get the file format of the molecular system. fileformat = system.fileFormat() @@ -131,7 +132,7 @@ def _find_md_engines(system, protocol, engine="AUTO", gpu_support=False): if engine == "AUTO": raise ValueError("Cannot automatically choose an MD engine") engines = list(_md_engines.keys()) - elif not fileformat in _file_extensions: + elif fileformat not in _file_extensions: raise ValueError( "Cannot find an MD engine that supports format: %s" % fileformat ) @@ -292,9 +293,9 @@ def run( process : :class:`Process ` A process to run the molecular dynamics protocol. """ + from .. import Process as _Process from .. import Protocol as _Protocol from .._Exceptions import IncompatibleError as _IncompatibleError - from .. import Process as _Process from .._SireWrappers import System as _System # Check that the system is valid. @@ -339,7 +340,7 @@ def run( raise TypeError("'work_dir' must be of type 'str'") if seed is not None: - if not type(seed) is int: + if type(seed) is not int: raise TypeError("'seed' must be of type 'int'") if not isinstance(property_map, dict): diff --git a/python/BioSimSpace/Sandpit/Exscientia/MD/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/MD/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/MD/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/MD/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_collective_variable.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_collective_variable.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_collective_variable.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_collective_variable.py diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py similarity index 100% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py index e6c0a3204..5d0235071 100644 --- a/python/BioSimSpace/Metadynamics/CollectiveVariable/_distance.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_distance.py @@ -27,8 +27,8 @@ __all__ = ["Distance"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Distance(_CollectiveVariable): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py index 8f9c3eb51..49b21dc2e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_funnel.py @@ -27,10 +27,10 @@ __all__ = ["Funnel", "makeFunnel", "viewFunnel"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable +from ...Types import Length as _Length from .._bound import Bound as _Bound from .._grid import Grid as _Grid -from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Funnel(_CollectiveVariable): @@ -519,8 +519,9 @@ def getCorrection( The funnel correction. """ import math as _math - from ...Types import Volume as _Volume + from ...Types import Energy as _Energy + from ...Types import Volume as _Volume if proj_min is None: if proj_max is None: @@ -746,14 +747,14 @@ def makeFunnel( atoms1 : [int] A list of atom indices that define the inflection point of the funnel. """ - from ..._Exceptions import IncompatibleError as _IncompatibleError - from ...Types import Coordinate as _Coordinate from sire.legacy.Maths import Vector as _SireVector + + from ..._Exceptions import IncompatibleError as _IncompatibleError from ..._SireWrappers import Molecule as _Molecule from ..._SireWrappers import System as _System + from ...Types import Coordinate as _Coordinate # Validate the input. - # System. if not isinstance(system, _System): raise TypeError("'system' must be of type 'BioSimSpace._SireWrappers.System'.") @@ -1019,12 +1020,12 @@ def viewFunnel(system, collective_variable, property_map={}): """ import sire.legacy.Mol as _SireMol from sire.legacy.Maths import Vector as _SireVector + + from ... import _is_notebook from ..._SireWrappers import Molecule as _Molecule from ..._SireWrappers import System as _System - from ... import _is_notebook # The following is adapted from funnel_maker.py by Dominykas Lukauskis. - # Don't do anything if this isn't called from within a notebook. if not _is_notebook: return None diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py index 02876ecde..ae59b3be3 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_rmsd.py @@ -27,8 +27,8 @@ __all__ = ["RMSD"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Length as _Length +from ._collective_variable import CollectiveVariable as _CollectiveVariable class RMSD(_CollectiveVariable): @@ -104,12 +104,13 @@ def __init__( """ from sire.legacy import IO as _SireIO from sire.legacy import Mol as _SireMol - from ..._SireWrappers import Atom as _Atom - from ... import _isVerbose - from ..._SireWrappers import System as _System from sire.mol import selection_to_atoms as _selection_to_atoms - from ..._SireWrappers import Molecule as _Molecule + + from ... import _isVerbose from ..._Exceptions import IncompatibleError as _IncompatibleError + from ..._SireWrappers import Atom as _Atom + from ..._SireWrappers import Molecule as _Molecule + from ..._SireWrappers import System as _System # Call the base class constructor. super().__init__() @@ -334,7 +335,7 @@ def __init__( # Also strip any TER records. self._reference_pdb = [] for line, idx in zip(lines[1:-2], abs_atom_indices): - if not "TER" in line: + if "TER" not in line: self._reference_pdb.append(line[:6] + str(idx).rjust(5) + line[11:]) self._reference_pdb.append(lines[-1]) @@ -578,10 +579,12 @@ def _compute_initial_rmsd( rmsd : :class:`Length ` The initial value of the RMSD. """ - from sire.legacy import Mol as _SireMol - from ...Align import rmsdAlign as _rmsdAlign from math import sqrt as _sqrt + + from sire.legacy import Mol as _SireMol + from ..._SireWrappers import System as _System + from ...Align import rmsdAlign as _rmsdAlign # Note that we need to do this manually, since Sire.Mol.Evaluator doesn't # work correctly for molecules with different numbers of coordinate groups. @@ -675,7 +678,7 @@ def _compute_initial_rmsd( i.value(): i.value() for i in align_indices[ref._sire_object.number()] } - except Exception as e: + except Exception: pass if len(align_mapping) > 0: @@ -696,7 +699,7 @@ def _compute_initial_rmsd( try: rmsd_mapping = {i: i for i in rmsd_indices[ref._sire_object.number()]} - except Exception as e: + except Exception: pass if len(rmsd_mapping) > 0: diff --git a/python/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py similarity index 100% rename from python/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py index 47973bcf0..2c26bc9f5 100644 --- a/python/BioSimSpace/Metadynamics/CollectiveVariable/_torsion.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_torsion.py @@ -27,8 +27,8 @@ __all__ = ["Torsion"] -from ._collective_variable import CollectiveVariable as _CollectiveVariable from ...Types import Angle as _Angle +from ._collective_variable import CollectiveVariable as _CollectiveVariable class Torsion(_CollectiveVariable): @@ -231,9 +231,9 @@ def getPeriodicBoundaries(self): def _validate(self): """Internal function to check that the object is in a consistent state.""" + from math import ceil as _ceil from math import isclose as _isclose from math import pi as _pi - from math import ceil as _ceil if self._lower_bound is not None: if not isinstance(self._lower_bound.getValue(), _Angle): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/CollectiveVariable/_utils.py diff --git a/python/BioSimSpace/Metadynamics/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py similarity index 99% rename from python/BioSimSpace/Metadynamics/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py index 0ab6d284f..3e692922a 100644 --- a/python/BioSimSpace/Metadynamics/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/__init__.py @@ -47,10 +47,9 @@ _sr.use_new_api() del _sr +from . import CollectiveVariable from ._bound import * from ._grid import * from ._metadynamics import * from ._restraint import * from ._utils import * - -from . import CollectiveVariable diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/ProjectionOnAxis.cpp b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/ProjectionOnAxis.cpp similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/ProjectionOnAxis.cpp rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/ProjectionOnAxis.cpp diff --git a/python/BioSimSpace/Metadynamics/_aux/metadynamics.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py similarity index 99% rename from python/BioSimSpace/Metadynamics/_aux/metadynamics.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py index 10dfb7b97..e6f283d58 100644 --- a/python/BioSimSpace/Metadynamics/_aux/metadynamics.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_aux/metadynamics.py @@ -31,7 +31,7 @@ from collections import namedtuple try: - import numpy as np + pass except: pass @@ -108,9 +108,9 @@ def __init__( the directory to which biases should be written, and from which biases written by other processes should be loaded """ + import numpy as np import openmm as mm from openmm import unit - import numpy as np if not unit.is_quantity(temperature): temperature = temperature * unit.kelvin @@ -200,8 +200,8 @@ def step(self, simulation, steps): steps : int the number of time steps to integrate """ - from openmm import unit import numpy as np + from openmm import unit stepsToGo = steps while stepsToGo > 0: @@ -251,8 +251,8 @@ def getCollectiveVariables(self, simulation): def getHillHeight(self, simulation): """Get the current height of the Gaussian hill in kJ/mol.""" - from openmm import unit import numpy as np + from openmm import unit energy = simulation.context.getState( getEnergy=True, groups={31} @@ -267,8 +267,9 @@ def getHillHeight(self, simulation): def _addGaussian(self, position, height, context): """Add a Gaussian to the bias function.""" from functools import reduce - from openmm import unit + import numpy as np + from openmm import unit # Compute a Gaussian along each axis. @@ -306,9 +307,10 @@ def _addGaussian(self, position, height, context): def _syncWithDisk(self): """Save biases to disk, and check for updated files created by other processes.""" import os - import numpy as np import re + import numpy as np + if self.biasDir is None: return diff --git a/python/BioSimSpace/Metadynamics/_bound.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py similarity index 98% rename from python/BioSimSpace/Metadynamics/_bound.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py index 02e40df37..45cb5428f 100644 --- a/python/BioSimSpace/Metadynamics/_bound.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_bound.py @@ -98,7 +98,7 @@ def setValue(self, value): """ from ..Types._type import Type as _Type - if not isinstance(value, (float, _Type)) and not type(value) is int: + if not isinstance(value, (float, _Type)) and type(value) is not int: raise TypeError( "'value' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py similarity index 97% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py index cbd460878..db378c3ef 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_grid.py @@ -94,7 +94,7 @@ def setMinimum(self, minimum): """ from ..Types._type import Type as _Type - if not isinstance(minimum, (float, _Type)) and not type(minimum) is int: + if not isinstance(minimum, (float, _Type)) and type(minimum) is not int: raise TypeError( "'minimum' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) @@ -130,7 +130,7 @@ def setMaximum(self, maximum): """ from ..Types._type import Type as _Type - if not isinstance(maximum, (float, _Type)) and not type(maximum) is int: + if not isinstance(maximum, (float, _Type)) and type(maximum) is not int: raise TypeError( "'maximum' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Metadynamics/_metadynamics.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py similarity index 97% rename from python/BioSimSpace/Metadynamics/_metadynamics.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py index 96d4721b2..fdb073051 100644 --- a/python/BioSimSpace/Metadynamics/_metadynamics.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_metadynamics.py @@ -28,7 +28,7 @@ # Import common objects from BioSimSpace.MD._md -from ..MD._md import _file_extensions, _md_engines, _find_md_engines +from ..MD._md import _find_md_engines def run( @@ -89,7 +89,6 @@ def run( process : :class:`Process ` A process to run the molecular dynamics protocol. """ - from ..MD._md import _find_md_engines from .. import Process as _Process from .. import Protocol as _Protocol from .._SireWrappers import System as _System @@ -124,7 +123,7 @@ def run( raise TypeError("'work_dir' must be of type 'str'") if seed is not None: - if not type(seed) is int: + if type(seed) is not int: raise TypeError("'seed' must be of type 'int'") if not isinstance(property_map, dict): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py similarity index 98% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py index 137ddfcc0..646258c1f 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_restraint.py @@ -91,7 +91,7 @@ def setValue(self, value): """ from ..Types._type import Type as _Type - if not isinstance(value, (float, _Type)) and not type(value) is int: + if not isinstance(value, (float, _Type)) and type(value) is not int: raise TypeError( "'value' must be of type 'int', 'float', or 'BioSimSpace.Types._type.Type'" ) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Metadynamics/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/Metadynamics/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Node/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Node/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Node/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Node/__init__.py diff --git a/python/BioSimSpace/Node/_node.py b/src/BioSimSpace/Sandpit/Exscientia/Node/_node.py similarity index 99% rename from python/BioSimSpace/Node/_node.py rename to src/BioSimSpace/Sandpit/Exscientia/Node/_node.py index a70e1d37e..d1595a538 100644 --- a/python/BioSimSpace/Node/_node.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Node/_node.py @@ -1,8 +1,7 @@ -from .._Utils import _try_import - - import os as _os +from .._Utils import _try_import + _yaml = _try_import("yaml") @@ -35,10 +34,12 @@ def help(name): name : str The name of the node. """ - from .. import _Utils - from sire.legacy import Base as _SireBase import subprocess as _subprocess + from sire.legacy import Base as _SireBase + + from .. import _Utils + if not isinstance(name, str): raise TypeError("'name' must be of type 'str'.") @@ -92,7 +93,9 @@ def run(name, args={}, work_dir=None): A dictionary containing the output of the node. """ import subprocess as _subprocess + from sire.legacy import Base as _SireBase + from .. import _Utils # Validate the input. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Notebook/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Notebook/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Notebook/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Notebook/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py b/src/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py rename to src/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py index c40c78e03..c7697ca70 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Notebook/_plot.py @@ -41,8 +41,8 @@ if _display is not None: _has_display = True try: - import matplotlib.pyplot as _plt import matplotlib.colors as _colors + import matplotlib.pyplot as _plt _has_matplotlib = True except ImportError: @@ -50,8 +50,8 @@ else: if _is_notebook: try: - import matplotlib.pyplot as _plt import matplotlib.colors as _colors + import matplotlib.pyplot as _plt _has_matplotlib = True except ImportError: @@ -120,6 +120,7 @@ def plot( Whether the y axis is logarithmic. """ from warnings import warn as _warn + from .. import _is_interactive from ..Types._type import Type as _Type @@ -356,15 +357,14 @@ def plotContour(x, y, z, xlabel=None, ylabel=None, zlabel=None): The z axis label string. """ from warnings import warn as _warn - from .. import _is_interactive - from ..Types._type import Type as _Type - import numpy as _np import numpy as _np import scipy.interpolate as _interp - from mpl_toolkits.axes_grid1 import make_axes_locatable as _make_axes_locatable + from .. import _is_interactive + from ..Types._type import Type as _Type + # Make sure were running interactively. if not _is_interactive: _warn("You can only use BioSimSpace.Notebook.plot when running interactively.") @@ -501,7 +501,7 @@ def plotContour(x, y, z, xlabel=None, ylabel=None, zlabel=None): # Convert to two-dimensional arrays. We don't assume the data is on a grid, # so we interpolate the z values. try: - (X, Y) = _np.meshgrid( + X, Y = _np.meshgrid( _np.linspace(_np.min(x), _np.max(x), 1000), _np.linspace(_np.min(y), _np.max(y), 1000), ) @@ -562,10 +562,12 @@ def plotOverlapMatrix( Can not contain more than 3 elements. """ from warnings import warn as _warn - from .. import _is_interactive + import matplotlib.colors as _colors import numpy as _np + from .. import _is_interactive + # Make sure were running interactively. if not _is_interactive: _warn("You can only use BioSimSpace.Notebook.plot when running interactively.") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py b/src/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py rename to src/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py index 259891561..e6ba6ca1f 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Notebook/_view.py @@ -55,12 +55,13 @@ def __init__(self, handle, property_map={}, is_lambda1=False): perturbable molecules. By default, the state at lambda = 0 is used. """ - import warnings as _warnings - from .._SireWrappers import System as _System import tempfile as _tempfile + import warnings as _warnings + from .. import IO as _IO - from ..Process._process import Process as _Process from .. import _is_notebook + from .._SireWrappers import System as _System + from ..Process._process import Process as _Process # Make sure we're running inside a Jupyter notebook. if not _is_notebook: @@ -181,6 +182,7 @@ def molecules(self, indices=None, gui=True): """ from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem + from .. import _is_notebook # Make sure we're running inside a Jupyter notebook. @@ -255,6 +257,7 @@ def molecule(self, index=0, gui=True): """ from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem + from .. import _is_notebook # Make sure we're running inside a Jupyter notebook. @@ -262,7 +265,7 @@ def molecule(self, index=0, gui=True): return None # Check that the index is an integer. - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") # Get the latest system from the process. @@ -326,7 +329,7 @@ def reload(self, index=None, gui=True): index = self._num_views - 1 # Check that the index is an integer. - elif not type(index) is int: + elif type(index) is not int: raise TypeError("'index' must be of type 'int'") # Make sure the view index is valid. @@ -364,6 +367,7 @@ def savePDB(self, file, index=None): The view index. """ import shutil as _shutil + from .. import _is_notebook # Make sure we're running inside a Jupyter notebook. @@ -375,7 +379,7 @@ def savePDB(self, file, index=None): index = self._num_views - 1 # Check that the index is an integer. - elif not type(index) is int: + elif type(index) is not int: raise TypeError("'index' must be of type 'int'") # Make sure the view index is valid. @@ -418,9 +422,10 @@ def _create_view(self, system=None, view=None, gui=True): gui : bool Whether to display the gui. """ - from .. import _isVerbose from sire.legacy import IO as _SireIO + from .. import _isVerbose + if system is None and view is None: raise ValueError("Both 'system' and 'view' cannot be 'None'.") diff --git a/python/BioSimSpace/Parameters/_Protocol/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py similarity index 100% rename from python/BioSimSpace/Parameters/_Protocol/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py index 1484d54df..485711d31 100644 --- a/python/BioSimSpace/Parameters/_Protocol/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/__init__.py @@ -24,6 +24,6 @@ Author: Lester Hedges . """ -from ._protocol import Protocol as _Protocol from ._amber import * from ._openforcefield import * +from ._protocol import Protocol as _Protocol diff --git a/python/BioSimSpace/Parameters/_Protocol/_amber.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py similarity index 99% rename from python/BioSimSpace/Parameters/_Protocol/_amber.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py index e85f9918b..c2a77cb50 100644 --- a/python/BioSimSpace/Parameters/_Protocol/_amber.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_amber.py @@ -34,11 +34,11 @@ import os as _os import subprocess as _subprocess -from ..._Utils import _try_import, _have_imported - # Temporarily redirect stderr to suppress import warnings. import sys as _sys +from ..._Utils import _have_imported, _try_import + _orig_stderr = _sys.stderr _sys.stderr = open(_os.devnull, "w") @@ -54,10 +54,8 @@ del _sys, _orig_stderr -from ... import _amber_home -from ... import _Utils +from ... import _amber_home, _Utils from ...Types import Length as _Length - from . import _protocol # Set the tLEaP cmd directory. @@ -297,13 +295,14 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ + import queue as _queue + + from ... import IO as _IO from ... import _gmx_exe, _isVerbose - from ...Convert import smiles as _smiles from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError - from ... import IO as _IO - from ..._SireWrappers import Molecule as _Molecule from ..._Exceptions import ThirdPartyError as _ThirdPartyError - import queue as _queue + from ..._SireWrappers import Molecule as _Molecule + from ...Convert import smiles as _smiles if not isinstance(molecule, (_Molecule, str)): raise TypeError( @@ -427,11 +426,12 @@ def _run_tleap(self, molecule, work_dir): work_dir : str The working directory. """ - from ..._Exceptions import ParameterisationError as _ParameterisationError - from ... import IO as _IO - from ..._SireWrappers import Molecule as _Molecule from sire.legacy import IO as _SireIO + + from ... import IO as _IO from ... import _isVerbose + from ..._Exceptions import ParameterisationError as _ParameterisationError + from ..._SireWrappers import Molecule as _Molecule # Write the system to a PDB file. try: @@ -566,10 +566,10 @@ def _run_pdb2gmx(self, molecule, work_dir): work_dir : str The working directory. """ + from ... import IO as _IO from ... import _gmx_exe, _isVerbose - from ..._Exceptions import ParameterisationError as _ParameterisationError from ..._Exceptions import IncompatibleError as _IncompatibleError - from ... import IO as _IO + from ..._Exceptions import ParameterisationError as _ParameterisationError # A list of supported force fields, mapping to their GROMACS ID string. # GROMACS supports a sub-set of the AMBER force fields. @@ -662,6 +662,7 @@ def _get_disulphide_bonds( own naming scheme, e.g. { "charge" : "my-charge" } """ import warnings as _warnings + from sire.legacy import Mol as _SireMol if not isinstance(molecule, _SireMol.Molecule): @@ -768,6 +769,7 @@ def _generate_bond_records(molecule, bonds): A list of LEaP formatted bond records. """ import warnings as _warnings + from ..._SireWrappers import Atom as _Atom from ..._SireWrappers import Molecule as _Molecule @@ -914,7 +916,7 @@ def __init__( raise TypeError("'version' must be of type 'int'.") # Check that the version is valid. - if not version in [1, 2]: + if version not in [1, 2]: raise ValueError("Unsupported version: options are 1 or 2.") if not isinstance(charge_method, str): @@ -924,7 +926,7 @@ def __init__( charge_method = charge_method.replace(" ", "").upper() # Check that the charge method is valid. - if not charge_method in self._charge_methods: + if charge_method not in self._charge_methods: raise ValueError( "Unsupported charge method: '%s'. Supported methods are: %s" % (charge_method, self._charge_methods) @@ -991,15 +993,16 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ - from ..._Exceptions import ParameterisationError as _ParameterisationError - from ...Convert import smiles as _smiles + import queue as _queue import warnings as _warnings - from ...Parameters._utils import formalCharge as _formalCharge + from ... import IO as _IO - from ..._SireWrappers import Molecule as _Molecule - from ..._Exceptions import ThirdPartyError as _ThirdPartyError - import queue as _queue from ... import _isVerbose + from ..._Exceptions import ParameterisationError as _ParameterisationError + from ..._Exceptions import ThirdPartyError as _ThirdPartyError + from ..._SireWrappers import Molecule as _Molecule + from ...Convert import smiles as _smiles + from ...Parameters._utils import formalCharge as _formalCharge if not isinstance(molecule, (_Molecule, str)): raise TypeError( diff --git a/python/BioSimSpace/Parameters/_Protocol/_openforcefield.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py similarity index 99% rename from python/BioSimSpace/Parameters/_Protocol/_openforcefield.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py index 4da36b57c..dcf80a344 100644 --- a/python/BioSimSpace/Parameters/_Protocol/_openforcefield.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_openforcefield.py @@ -31,13 +31,11 @@ __all__ = ["OpenForceField"] -from ..._Utils import _try_import, _have_imported - import os as _os - - import warnings as _warnings +from ..._Utils import _have_imported, _try_import + # Suppress duplicate to-Python converted warnings. # Both Sire and RDKit register the same converter. with _warnings.catch_warnings(): @@ -193,15 +191,15 @@ def run(self, molecule, work_dir=None, queue=None): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ - from ..._Exceptions import ThirdPartyError as _ThirdPartyError - from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError - from ... import Convert as _Convert - from ..._SireWrappers import Molecule as _Molecule - from ... import _isVerbose - from ... import IO as _IO import queue as _queue + + from ... import IO as _IO + from ... import Convert as _Convert + from ... import _isVerbose, _Utils from ..._Exceptions import ConversionError as _ConversionError - from ... import _Utils + from ..._Exceptions import MissingSoftwareError as _MissingSoftwareError + from ..._Exceptions import ThirdPartyError as _ThirdPartyError + from ..._SireWrappers import Molecule as _Molecule if not isinstance(molecule, (_Molecule, str)): raise TypeError( diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_protocol.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_protocol.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_protocol.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_Protocol/_protocol.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py index 846debdfa..361e2a6ad 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_parameters.py @@ -48,10 +48,8 @@ } from .. import _isVerbose - +from .._Utils import _have_imported, _try_import from ..Types import Length as _Length -from .._Utils import _try_import, _have_imported - from . import _Protocol @@ -205,9 +203,9 @@ def _parameterise_amber_protein( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from .. import _amber_home, _gmx_exe, _gmx_path + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + from ._process import Process as _Process if not isinstance(forcefield, str): raise TypeError("'forcefield' must be of type 'str'.") @@ -316,10 +314,10 @@ def gaff( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process + from .. import _amber_home from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..Types import Charge as _Charge - from .. import _amber_home + from ._process import Process as _Process if _amber_home is None: raise _MissingSoftwareError( @@ -416,10 +414,10 @@ def gaff2( .getMolecule() method on the returned process to block until the parameterisation is complete and get the parameterised molecule. """ - from ._process import Process as _Process + from .. import _amber_home from .._Exceptions import MissingSoftwareError as _MissingSoftwareError from ..Types import Charge as _Charge - from .. import _amber_home + from ._process import Process as _Process if _amber_home is None: raise _MissingSoftwareError( @@ -844,9 +842,9 @@ def _validate( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ..Solvent import waterModels as _waterModels - from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Atom as _Atom + from .._SireWrappers import Molecule as _Molecule + from ..Solvent import waterModels as _waterModels if molecule is not None: if not isinstance(molecule, (_Molecule, str)): @@ -1139,8 +1137,8 @@ def _function( _openforcefields = _try_import("openforcefields") if _have_imported(_openforcefields): - from glob import glob as _glob import os as _os + from glob import glob as _glob _openff_dirs = _openforcefields.get_forcefield_dirs_paths() _open_forcefields = [] diff --git a/python/BioSimSpace/Parameters/_process.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py similarity index 99% rename from python/BioSimSpace/Parameters/_process.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py index b690b3f68..dc71d20d1 100644 --- a/python/BioSimSpace/Parameters/_process.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_process.py @@ -32,9 +32,8 @@ from .. import _is_notebook - if _is_notebook: - from IPython.display import FileLink as _FileLink + pass def _wrap_protocol(protocol_function, process): @@ -91,12 +90,13 @@ def __init__(self, molecule, protocol, work_dir=None, auto_start=False): auto_start : bool Whether to automatically start the process. """ - from .._SireWrappers import Molecule as _Molecule + import os as _os import sys as _sys + import warnings as _warnings + from .. import _Utils + from .._SireWrappers import Molecule as _Molecule from . import _Protocol - import os as _os - import warnings as _warnings # Validate arguments. @@ -159,8 +159,8 @@ def __init__(self, molecule, protocol, work_dir=None, auto_start=False): def start(self): """Start the process.""" - import threading as _threading import queue as _queue + import threading as _threading # Flag that the process has been started. if self._is_started: @@ -190,8 +190,8 @@ def getMolecule(self): molecule : BioSimSpace._SireWrappers.Molecule The parameterised molecule. """ - from .._Exceptions import ParameterisationError as _ParameterisationError from .. import _isVerbose + from .._Exceptions import ParameterisationError as _ParameterisationError # Start the process, if it's not already started. if not self._is_started: @@ -268,10 +268,11 @@ def getOutput(self, filename=None, file_link=False): file_link : str, IPython.lib.display.FileLink The name of, or link to, a zipfile containing the output. """ + import glob as _glob + import os as _os import zipfile as _zipfile + from IPython.display import FileLink as _FileLink - import os as _os - import glob as _glob if self._zipfile is None or filename is not None: if filename is not None: diff --git a/python/BioSimSpace/Parameters/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py similarity index 98% rename from python/BioSimSpace/Parameters/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py index bb5b99ce4..931b1dd76 100644 --- a/python/BioSimSpace/Parameters/_utils.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Parameters/_utils.py @@ -49,12 +49,12 @@ def formalCharge(molecule, property_map={}): formal_charge : :class:`Charge ` The total formal charge on the molecule. """ - from .. import IO as _IO - from ..Units.Charge import electron_charge as _electron_charge import tempfile as _tempfile - from .. import _isVerbose - from .. import _Utils + + from .. import IO as _IO + from .. import _isVerbose, _Utils from .._SireWrappers import Molecule as _Molecule + from ..Units.Charge import electron_charge as _electron_charge if not isinstance(molecule, _Molecule): raise TypeError( diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Process/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Process/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_amber.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_amber.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_amber.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_amber.py index e0e95028a..add46a4fb 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_amber.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_amber.py @@ -39,8 +39,7 @@ _alchemlyb = _try_import("alchemlyb") if _have_imported(_alchemlyb): - from alchemlyb.parsing.amber import extract as _extract - + pass from . import _process @@ -106,8 +105,9 @@ def __init__( own naming scheme, e.g. { "charge" : "my-charge" } """ import os as _os - from .. import _amber_home + from .. import Protocol as _Protocol + from .. import _amber_home from .._Exceptions import IncompatibleError as _IncompatibleError from .._Exceptions import MissingSoftwareError as _MissingSoftwareError @@ -214,9 +214,10 @@ def __init__( def _setup(self): """Setup the input files and working directory ready for simulation.""" - from .. import Protocol as _Protocol import shutil as _shutil + from .. import Protocol as _Protocol + # Create the input files... self._squashed_system, self._mapping = self._write_system( self._system, coord_file=self._rst_file, topol_file=self._top_file @@ -275,12 +276,14 @@ def _write_system(self, system, coord_file=None, topol_file=None, ref_file=None) The corresponding molecule-to-molecule mapping. """ import os as _os - from .. import Protocol as _Protocol + import shutil + from sire.legacy import Mol as _SireMol + + from .. import IO as _IO + from .. import Protocol as _Protocol from .. import _isVerbose from ..Align._squash import _squash - from .. import IO as _IO - import shutil # Create a copy of the system. system = system.copy() @@ -350,11 +353,12 @@ def _write_system(self, system, coord_file=None, topol_file=None, ref_file=None) def _generate_config(self): """Generate AMBER configuration file strings.""" import os as _os + import shutil as _shutil + import warnings as _warnings + from .. import Protocol as _Protocol from .._Exceptions import IncompatibleError as _IncompatibleError - import shutil as _shutil from ._plumed import Plumed as _Plumed - import warnings as _warnings # Clear the existing configuration list. self._config = [] @@ -569,8 +573,10 @@ def start(self): process : :class:`Process.Amber ` The process object. """ - from sire.legacy import Base as _SireBase import timeit as _timeit + + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -625,14 +631,16 @@ def getSystem(self, block="AUTO"): The latest molecular system. """ import os as _os + import shutil as _shutil + import tempfile as _tempfile + import warnings as _warnings + from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + from .. import Protocol as _Protocol from .._SireWrappers import System as _System - from sire.legacy import Mol as _SireMol - import shutil as _shutil from ..Align._squash import _unsquash - import warnings as _warnings - import tempfile as _tempfile # Wait for the process to finish. if block is True: @@ -762,9 +770,10 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): trajectory : :class:`Trajectory ` The latest trajectory object. """ - from .. import Trajectory as _Trajectory import warnings as _warnings + from .. import Trajectory as _Trajectory + if not isinstance(backend, str): raise TypeError("'backend' must be of type 'str'") @@ -803,13 +812,14 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory from sire.legacy import IO as _SireIO - from .. import Protocol as _Protocol from sire.legacy import Mol as _SireMol + + from .. import Protocol as _Protocol + from .. import Trajectory as _Trajectory from ..Align._squash import _unsquash - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = int( @@ -940,7 +950,7 @@ def getRecordKey(self, record, region=0, soft_core=False): cleaned_record = record.strip().upper() # Make sure the record exists in the key mapping. - if not cleaned_record in self._stdout_key[idx].values(): + if cleaned_record not in self._stdout_key[idx].values(): raise ValueError(f"No key found for record '{record}'") return list(self._stdout_key[idx].keys())[ @@ -1163,8 +1173,8 @@ def getTime(self, time_series=False, region=0, soft_core=False, block="AUTO"): time : :class:`Time ` The current simulation time in nanoseconds. """ - from .. import Units as _Units from .. import Protocol as _Protocol + from .. import Units as _Units # No time records for minimisation protocols. if isinstance(self._protocol, _Protocol.Minimisation): @@ -2158,8 +2168,8 @@ def getTotalEnergy( energy : :class:`Energy ` The total energy. """ - from .. import Units as _Units from .. import Protocol as _Protocol + from .. import Units as _Units if not isinstance(region, int): raise TypeError("'region' must be of type 'int'") @@ -2706,6 +2716,7 @@ def stdout(self, n=10): The number of lines to print. """ import re as _re + from .. import Protocol as _Protocol # Ensure that the number of lines is positive. @@ -2848,7 +2859,7 @@ def kill(self): """Kill the running process.""" # Kill the process. - if not self._process is None and self._process.is_running(): + if self._process is not None and self._process.is_running(): self._process.kill() def _get_stdout_record( @@ -2884,9 +2895,10 @@ def _get_stdout_record( record : The matching stdout record. """ - from ..Types._type import Type as _Type import warnings as _warnings + from ..Types._type import Type as _Type + # Update the standard output dictionary. self.stdout(0) @@ -3013,11 +3025,13 @@ def _saveMetric( is Free Energy protocol, the dHdl and the u_nk data will be saved in the same parquet format as well. """ + import warnings as _warnings + from alchemlyb.parsing.amber import extract as _extract - from .. import Units as _Units + from .. import Protocol as _Protocol + from .. import Units as _Units from .._Utils import _assert_imported - import warnings as _warnings if filename is not None: self._init_stdout_dict() diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py index e2f8875bc..9403e55bf 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_gromacs.py @@ -39,9 +39,7 @@ _alchemlyb = _try_import("alchemlyb") if _have_imported(_alchemlyb): - from alchemlyb.parsing.gmx import extract_u_nk as _extract_u_nk - from alchemlyb.parsing.gmx import extract_dHdl as _extract_dHdl - + pass from . import _process @@ -123,10 +121,11 @@ def __init__( to continue an existing simulation. Currently we only support the use of checkpoint files for Equilibration protocols. """ - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError import os as _os + from .. import Protocol as _Protocol from .. import _gmx_exe + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError # Call the base class constructor. super().__init__( @@ -229,6 +228,7 @@ def __init__( def _setup(self): """Setup the input files and working directory ready for simulation.""" import shutil as _shutil + from .. import Protocol as _Protocol # Create the input files... @@ -283,10 +283,12 @@ def _write_system(self, system, coord_file=None, topol_file=None, ref_file=None) ref_file : str or None The file to which to write out the reference system for position restraints. """ - from sire.legacy import Maths as _SireMaths - import warnings as _warnings import os as _os + import warnings as _warnings + + from sire.legacy import Maths as _SireMaths from sire.legacy import Vol as _SireVol + from .. import IO as _IO from .. import Protocol as _Protocol @@ -408,10 +410,11 @@ def _apply_ABFE_restraint(self): def _generate_config(self): """Generate GROMACS configuration file strings.""" + import os as _os import shutil as _shutil - from ._plumed import Plumed as _Plumed + from .. import Protocol as _Protocol - import os as _os + from ._plumed import Plumed as _Plumed # Clear the existing configuration list. self._config = [] @@ -565,8 +568,9 @@ def _generate_binary_run_file( Whether to show warning/error messages when generating the binary run file. """ - import subprocess as _subprocess import os as _os + import subprocess as _subprocess + from .. import _Utils if not isinstance(mdp_file, str): @@ -783,8 +787,10 @@ def start(self): process : :class:`Process.Gromacs ` A handle to the GROMACS process. """ - from sire.legacy import Base as _SireBase import timeit as _timeit + + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -846,9 +852,10 @@ def getSystem(self, block="AUTO"): system : :class:`System ` The latest molecular system. """ + import warnings as _warnings + from .. import Protocol as _Protocol from .. import Units as _Units - import warnings as _warnings # Wait for the process to finish. if block is True: @@ -911,9 +918,10 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): trajectory : :class:`System ` The latest trajectory object. """ - from .. import Trajectory as _Trajectory import warnings as _warnings + from .. import Trajectory as _Trajectory + if not isinstance(backend, str): raise TypeError("'backend' must be of type 'str'") @@ -962,7 +970,7 @@ def getFrame(self, index): """ import warnings as _warnings - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -2165,11 +2173,12 @@ def _add_position_restraints(self, config_options): config_options : dict The dictionary of configuration options. """ + from sire.legacy import IO as _SireIO from sire.legacy import Base as _SireBase + from sire.legacy import Units as _SireUnits + from .. import Protocol as _Protocol from .. import _isVerbose - from sire.legacy import Units as _SireUnits - from sire.legacy import IO as _SireIO # Get the restraint type. restraint = self._protocol.getRestraint() @@ -2296,7 +2305,7 @@ def _add_position_restraints(self, config_options): # Store the atom index if it hasn't already been recorded. for atom_idx in atom_idxs: - if not atom_idx in restrained_atoms: + if atom_idx not in restrained_atoms: restrained_atoms.append(atom_idx) # Write the position restraint file for this molecule. @@ -2367,7 +2376,7 @@ def _add_position_restraints(self, config_options): mol_type = sys_idx_moltypes[mol_idx] # Append this atom if it's not already been recorded. - if not atom_idx in mol_atoms[mol_type]: + if atom_idx not in mol_atoms[mol_type]: mol_atoms[mol_type].append(atom_idx) except Exception as e: @@ -2437,6 +2446,7 @@ def _add_position_restraints(self, config_options): def _initialise_energy_dict(self): # Grab the available energy terms import subprocess as _subprocess + from .. import _Utils command = f"{self._exe} energy -f {self._eng_file}" @@ -2548,9 +2558,10 @@ def _parse_energy_units(text): The order that the energy unit is printed will obey the order obtained from :meth:`~BioSimSpace.Process.Gromacs._parse_energy_terms`. """ - from .. import Units as _Units import warnings as _warnings + from .. import Units as _Units + section = text.split("---")[-1] lines = section.split("\n") units = [ @@ -2624,11 +2635,13 @@ def _sanitise_energy_term(key): return key def _update_energy_dict(self, initialise=False): - import numpy as _np - from .. import _Utils - from tempfile import TemporaryDirectory as _TemporaryDirectory import subprocess as _subprocess from pathlib import Path as _Path + from tempfile import TemporaryDirectory as _TemporaryDirectory + + import numpy as _np + + from .. import _Utils if initialise or len(self._energy_dict) == 0: self._initialise_energy_dict() @@ -2687,9 +2700,10 @@ def _get_energy_record(self, key, time_series=False, unit=None): record : The matching stdout record. """ - from ..Types._type import Type as _Type import warnings as _warnings + from ..Types._type import Type as _Type + # No data! if len(self._energy_dict) == 0: return None @@ -2738,14 +2752,16 @@ def _getFinalFrame(self): system : :class:`System ` The molecular system from the final frame. """ - from sire.legacy import Maths as _SireMaths - import warnings as _warnings - from .. import _Utils - from .. import IO as _IO import os as _os + import warnings as _warnings + + from sire.legacy import IO as _SireIO + from sire.legacy import Maths as _SireMaths from sire.legacy import Vol as _SireVol + + from .. import IO as _IO + from .. import _Utils from ..Units.Length import angstrom - from sire.legacy import IO as _SireIO # Grab the last frame from the GRO file. with _Utils.cd(self._work_dir): @@ -2847,16 +2863,18 @@ def _getFrame(self, time): system : :class:`System ` The molecular system from the closest trajectory frame. """ - from sire.legacy import Maths as _SireMaths - import warnings as _warnings - from .. import _Utils import os as _os + import subprocess as _subprocess + import warnings as _warnings + + from sire.legacy import IO as _SireIO + from sire.legacy import Maths as _SireMaths + from sire.legacy import Vol as _SireVol + from .. import IO as _IO from .. import Types as _Types - from sire.legacy import Vol as _SireVol + from .. import _Utils from ..Units.Length import angstrom - import subprocess as _subprocess - from sire.legacy import IO as _SireIO if not isinstance(time, _Types.Time): raise TypeError("'time' must be of type 'BioSimSpace.Types.Time'") @@ -2993,8 +3011,8 @@ def _find_trajectory_file(self): traj_file : str The path to the trajectory file. """ - import os as _os import glob as _glob + import os as _os import warnings as _warnings # Check that the current trajectory file is found. @@ -3034,11 +3052,13 @@ def _saveMetric( same parquet format as well. """ import warnings as _warnings - from alchemlyb.parsing.gmx import extract_u_nk as _extract_u_nk + from alchemlyb.parsing.gmx import extract_dHdl as _extract_dHdl + from alchemlyb.parsing.gmx import extract_u_nk as _extract_u_nk + from .. import Protocol as _Protocol - from .._Utils import _assert_imported from .. import Units as _Units + from .._Utils import _assert_imported if filename is not None: self._update_energy_dict(initialise=True) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_namd.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_namd.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_namd.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_namd.py index 01271b84c..130e1d400 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_namd.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_namd.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -77,9 +76,11 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ + import os as _os + from sire.legacy import Base as _SireBase + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - import os as _os # Call the base class constructor. super().__init__( @@ -95,9 +96,17 @@ def __init__( # If the path to the executable wasn't specified, then search # for it in $PATH. if exe is None: - try: - self._exe = _SireBase.findExe("namd2").absolute_file_path() - except: + exes = ["namd3", "namd2"] + exe_found = False + for e in exes: + try: + self._exe = _SireBase.findExe(e).absolute_file_path() + exe_found = True + break + except: + pass + + if not exe_found: raise _MissingSoftwareError( "'BioSimSpace.Process.Namd' is not supported. " "Please install NAMD (http://www.ks.uiuc.edu/Research/namd)." @@ -139,14 +148,15 @@ def __init__( def _setup(self): """Setup the input files and working directory ready for simulation.""" + import os as _os + + from sire.legacy import IO as _SireIO + from .. import IO as _IO from .. import Protocol as _Protocol - from sire.legacy import IO as _SireIO - import os as _os from .. import _isVerbose # Create the input files... - # Create a copy of the system. system = self._system.copy() @@ -262,12 +272,14 @@ def _setup(self): def _generate_config(self): """Generate NAMD configuration file strings.""" import math as _math + import os as _os + import warnings as _warnings + + from sire.legacy import IO as _SireIO from sire.legacy.Maths import Vector as _Vector + from .. import Protocol as _Protocol - from sire.legacy import IO as _SireIO - import warnings as _warnings from .._Exceptions import IncompatibleError as _IncompatibleError - import os as _os # Clear the existing configuration list. self._config = [] @@ -643,8 +655,10 @@ def start(self): process : :class:`Process.Namd ` The process object. """ - from sire.legacy import Base as _SireBase import timeit as _timeit + + from sire.legacy import Base as _SireBase + from .. import _Utils # The process is currently queued. @@ -700,10 +714,12 @@ def getSystem(self, block="AUTO"): The latest molecular system. """ import os as _os - from .. import IO as _IO - from sire.legacy import IO as _SireIO import warnings as _warnings + from sire.legacy import IO as _SireIO + + from .. import IO as _IO + # Wait for the process to finish. if block is True: self.wait() @@ -833,9 +849,10 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): trajectory : :class:`Trajectory ` The latest trajectory object. """ - from .. import Trajectory as _Trajectory import warnings as _warnings + from .. import Trajectory as _Trajectory + if not isinstance(backend, str): raise TypeError("'backend' must be of type 'str'") @@ -874,10 +891,11 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory from sire.legacy import IO as _SireIO - if not type(index) is int: + from .. import Trajectory as _Trajectory + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -2140,6 +2158,7 @@ def _createRestrainedSystem(self, system, restraint): The molecular system with an added 'restrained' property. """ from sire.legacy import Mol as _SireMol + from .. import _isVerbose # Get the force constant value in the default units. This is @@ -2257,9 +2276,10 @@ def _get_stdout_record(self, key, time_series=False, unit=None): record : The matching stdout record. """ - from ..Types._type import Type as _Type import warnings as _warnings + from ..Types._type import Type as _Type + # No data! if len(self._stdout_dict) == 0: return None diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py index 9b85a0522..68276df4d 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_openmm.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -88,10 +87,11 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Base as _SireBase import os as _os import sys as _sys + from sire.legacy import Base as _SireBase + # Call the base class constructor. super().__init__( system, @@ -202,10 +202,11 @@ def __repr__(self): def _setup(self): """Setup the input files and working directory ready for simulation.""" - from .. import _isVerbose - from .. import IO as _IO import os as _os + + from .. import IO as _IO from .. import Protocol as _Protocol + from .. import _isVerbose # Create a copy of the system. system = self._system.copy() @@ -261,14 +262,15 @@ def _setup(self): def _generate_config(self): """Generate OpenMM Python script file strings.""" - from .. import Protocol as _Protocol + import math as _math import os as _os - from ..Metadynamics import CollectiveVariable as _CollectiveVariable + import shutil as _shutil import warnings as _warnings + + from .. import Protocol as _Protocol from .._Exceptions import IncompatibleError as _IncompatibleError + from ..Metadynamics import CollectiveVariable as _CollectiveVariable from ._plumed import Plumed as _Plumed - import shutil as _shutil - import math as _math # Clear the existing configuration list. self._config = [] @@ -358,7 +360,7 @@ def _generate_config(self): self.addToConfig( "\n# Run a single simulation step to allow us to get the system and energy." ) - self.addToConfig(f"simulation.step(1)") + self.addToConfig("simulation.step(1)") elif isinstance(self._protocol, _Protocol.Equilibration): # Write the OpenMM import statements and monkey-patches. @@ -508,11 +510,11 @@ def _generate_config(self): f" temperature = {temperature} + x*{delta_temp}" ) self.addToConfig( - f" integrator.setTemperature(temperature*kelvin)" + " integrator.setTemperature(temperature*kelvin)" ) if is_const_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(100)") else: @@ -528,11 +530,11 @@ def _generate_config(self): f" temperature = {temperature} + x*{delta_temp}" ) self.addToConfig( - f" integrator.setTemperature(temperature*kelvin)" + " integrator.setTemperature(temperature*kelvin)" ) if is_const_pressure: self.addToConfig( - f" barostat.setDefaultTemperature(temperature*kelvin)" + " barostat.setDefaultTemperature(temperature*kelvin)" ) self.addToConfig(" simulation.step(1)") @@ -1079,7 +1081,7 @@ def _generate_config(self): self.addToConfig( "remaining_cycles = math.ceil(remaining_steps / steps_per_cycle)" ) - self.addToConfig(f"start_cycles = total_cycles - remaining_cycles") + self.addToConfig("start_cycles = total_cycles - remaining_cycles") self.addToConfig("checkpoint = 100") self.addToConfig("if is_restart:") self.addToConfig(" fraction_complete = step / total_steps") @@ -1204,9 +1206,11 @@ def start(self): process : :class:`Process.OpenMM ` A handle to the OpenMM process. """ + import timeit as _timeit + from sire.legacy import Base as _SireBase + from .. import _Utils - import timeit as _timeit # The process is currently queued. if self.isQueued(): @@ -1265,6 +1269,7 @@ def getSystem(self, block="AUTO"): The latest molecular system. """ from sire.legacy import IO as _SireIO + from .. import Protocol as _Protocol # Wait for the process to finish. @@ -1384,8 +1389,9 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): trajectory : :class:`System ` The latest trajectory object. """ - import warnings as _warnings import os as _os + import warnings as _warnings + from .. import Trajectory as _Trajectory if not isinstance(backend, str): @@ -1426,10 +1432,12 @@ def getFrame(self, index): The System object of the corresponding frame. """ import warnings as _warnings + from sire.legacy import IO as _SireIO + from .. import Trajectory as _Trajectory - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -1950,7 +1958,7 @@ def _add_config_imports(self): """ # We should verify that openmm is available to prevent # difficult-to-debug errors in the run script - from ...._Utils import _try_import, _assert_imported + from ...._Utils import _assert_imported, _try_import _openmm = _try_import("openmm") _assert_imported(_openmm) @@ -1968,8 +1976,8 @@ def _add_config_platform(self): Helper function to add platform information to the OpenMM Python script. """ - import warnings as _warnings import os as _os + import warnings as _warnings # Set the simulation platform. self.addToConfig("\n# Set the simulation platform.") @@ -2133,14 +2141,15 @@ def _add_config_reporters( is_restart : bool Whether the simulation is a restart. """ - from .. import Protocol as _Protocol import math as _math - if not type(state_interval) is int: + from .. import Protocol as _Protocol + + if type(state_interval) is not int: raise TypeError("'state_interval' must be of type 'int'.") if state_interval <= 0: raise ValueError("'state_interval' must be a positive integer.") - if not type(traj_interval) is int: + if type(traj_interval) is not int: raise TypeError("'traj_interval' must be of type 'int'.") if traj_interval <= 0: raise ValueError("'traj_interval' must be a positive integer.") @@ -2172,7 +2181,7 @@ def _add_config_reporters( # Write state information to file every 100 steps. self.addToConfig(f"log_file = open('{self._name}.log', 'a')") - self.addToConfig(f"simulation.reporters.append(StateDataReporter(log_file,") + self.addToConfig("simulation.reporters.append(StateDataReporter(log_file,") self.addToConfig( f" {state_interval}," ) @@ -2208,9 +2217,10 @@ def _add_config_reporters( def _update_stdout_dict(self): """Update the dictionary of thermodynamic records.""" - from .._Exceptions import IncompatibleError as _IncompatibleError import os as _os + from .._Exceptions import IncompatibleError as _IncompatibleError + # Exit if log file hasn't been created. if not _os.path.isfile(self._log_file): return @@ -2328,6 +2338,7 @@ def _get_stdout_record(self, key, time_series=False, unit=None): The matching stdout record. """ import warnings as _warnings + from ..Types._type import Type as _Type # No data! diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py index 0ba2cadf5..b5ca4bf8e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_plumed.py @@ -28,7 +28,6 @@ from .._Utils import _try_import - _pygtail = _try_import("pygtail") @@ -49,11 +48,12 @@ def __init__(self, work_dir): The working directory of the process that is interfacing with PLUMED. """ + import os as _os import subprocess as _subprocess + from sire.legacy.Base import findExe as _findExe - from .. import _Utils - from .. import _Exceptions - import os as _os + + from .. import _Exceptions, _Utils from ._process import _MultiDict # Check that the working directory is valid. @@ -165,8 +165,8 @@ def createConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from ..Protocol import Metadynamics as _Metadynamics from .._SireWrappers import System as _System + from ..Protocol import Metadynamics as _Metadynamics from ..Protocol import Steering as _Steering if not isinstance(system, _System): @@ -213,15 +213,17 @@ def _createMetadynamicsConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from ..Protocol import Metadynamics as _Metadynamics + import os as _os + import sire.legacy.Vol as _SireVol - from ..Metadynamics import CollectiveVariable as _CollectiveVariable - from .. import _Exceptions from sire.legacy.Maths import Vector as _Vector - from ..Types import Coordinate as _Coordinate - from .._SireWrappers import System as _System - import os as _os + from .. import Units as _Units + from .. import _Exceptions + from .._SireWrappers import System as _System + from ..Metadynamics import CollectiveVariable as _CollectiveVariable + from ..Protocol import Metadynamics as _Metadynamics + from ..Types import Coordinate as _Coordinate if not isinstance(system, _System): raise TypeError( @@ -928,13 +930,14 @@ def _createSteeringConfig(self, system, protocol, property_map={}): The list of PLUMED configuration strings and paths to any auxiliary files required by the collective variables. """ - from ..Metadynamics import CollectiveVariable as _CollectiveVariable + import os as _os + + from .. import Units as _Units from .. import _Exceptions - from ..Types import Coordinate as _Coordinate from .._SireWrappers import System as _System + from ..Metadynamics import CollectiveVariable as _CollectiveVariable from ..Protocol import Steering as _Steering - import os as _os - from .. import Units as _Units + from ..Types import Coordinate as _Coordinate if not isinstance(system, _System): raise TypeError( @@ -1348,8 +1351,8 @@ def getTime(self, time_series=False): time : :class:`Time ` The simulation run time. """ - from .. import _Exceptions from .. import Units as _Units + from .. import _Exceptions # We need to have generated a valid config before being able to parse # the COLVAR records. @@ -1397,7 +1400,7 @@ def getCollectiveVariable(self, index, time_series=False): msg = "No PLUMED configuration found! Please run 'createConfig' first." raise _Exceptions.IncompatibleError(msg) - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if index > self._num_components - 1 or index < -self._num_components: raise IndexError( @@ -1442,13 +1445,13 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): [[:class:`Type `, :class:`Type `, ...], ...] The free energy estimate for the chosen collective variables. """ - import subprocess as _subprocess - import shutil as _shutil - from .. import _Utils - from .. import _Exceptions import glob as _glob import os as _os + import shutil as _shutil + import subprocess as _subprocess + from .. import Units as _Units + from .. import _Exceptions, _Utils # We need to have generated a valid config before being able to compute # free energies. @@ -1457,7 +1460,7 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): raise _Exceptions.IncompatibleError(msg) if index is not None: - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if index > self._num_components - 1 or index < -self._num_components: raise IndexError( @@ -1466,7 +1469,7 @@ def getFreeEnergy(self, index=None, stride=None, kt=_Types.Energy(1.0, "kt")): ) if stride is not None: - if not type(stride) is int: + if type(stride) is not int: raise TypeError("'stride' must be of type 'int'") if stride < 0: raise ValueError("'stride' must be >= 0") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_process.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_process.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_process.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_process.py index 1dced8aac..1dbee6800 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_process.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_process.py @@ -32,12 +32,12 @@ _pygtail = _try_import("pygtail") +from .. import Units as _Units from .. import _is_notebook from ..Types import Time as _Time -from .. import Units as _Units if _is_notebook: - from IPython.display import FileLink as _FileLink + pass class _MultiDict(dict): @@ -103,15 +103,16 @@ def __init__( The Restraint object that contains information for the ABFE calculations. """ - from .._SireWrappers import System as _System - from ..Protocol._protocol import Protocol as _Protocol - from .. import _is_interactive - from .. import _Utils - from sire.legacy import Mol as _SireMol import collections as _collections import warnings as _warnings + + from sire.legacy import Mol as _SireMol + + from .. import _is_interactive, _Utils from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import System as _System from ..FreeEnergy._restraint import Restraint as _Restraint + from ..Protocol._protocol import Protocol as _Protocol # Warn user when create an instance of this base class. # The class is used for testing. @@ -143,7 +144,7 @@ def __init__( ) # Check that the seed is valid. - if seed is not None and not type(seed) is int: + if seed is not None and type(seed) is not int: raise TypeError("'seed' must be of type 'int'") # Check that the map is valid. @@ -160,7 +161,7 @@ def __init__( ) # Check that the restraint is valid. - if not restraint is None: + if restraint is not None: if not isinstance(restraint, _Restraint): raise TypeError( "'restraint' must be of type 'BioSimSpace.FreeEnergy.Restraint'." @@ -269,10 +270,11 @@ def _check_protocol_restart(self, protocol, system): """This function checks if the restart setting in the protocol is consistent with the velocity in the system. """ - from ..Protocol import Production as _Production - from ..Protocol import Equilibration as _Equilibration import warnings as _warnings + from ..Protocol import Equilibration as _Equilibration + from ..Protocol import Production as _Production + # Ensure that the restart is off when the system doesn't have velocity if ( isinstance(protocol, (_Equilibration, _Production)) @@ -332,8 +334,8 @@ def __repr__(self): def _clear_output(self): """Reset stdout and stderr.""" - import os as _os import glob as _glob + import os as _os # Create the files. This makes sure that the 'stdout' and 'stderr' # methods can be called when the files are empty. @@ -562,11 +564,11 @@ def _sampleConfigurations(self, bounds, number=1, block="AUTO"): collective_variables : [(:class:`Type `, int, float, ...)] The value of the collective variable for each configuration. """ - import sys as _sys import random as _random + import sys as _sys import warnings as _warnings - if not type(number) is int: + if type(number) is not int: raise TypeError("'number' must be of type 'int'") if number < 1: @@ -715,9 +717,10 @@ def _checkPerturbable(self, system): system : :class:`System ` The molecular system at a given end state. """ - from .._SireWrappers import System as _System import warnings as _warnings + from .._SireWrappers import System as _System + # Check that the system is valid. if not isinstance(system, _System): raise TypeError( @@ -727,7 +730,7 @@ def _checkPerturbable(self, system): # If the system contains a perturbable molecule, then we'll warn the user # and simulate the lambda = 0 state. if system.nPerturbableMolecules() > 0: - if not "is_lambda1" in self._property_map: + if "is_lambda1" not in self._property_map: is_lambda1 = False _warnings.warn( "The system contains a perturbable molecule ." @@ -901,7 +904,7 @@ def setSeed(self, seed): """ import warnings as _warnings - if not type(seed) is int: + if type(seed) is not int: _warnings.warn("The seed must be an integer. Disabling seeding.") self._seed = None else: @@ -917,9 +920,10 @@ def wait(self, max_time=None, inactivity_timeout: None | _Time = None): max_time : :class:`Time `, int, float The maximum time to wait (in minutes). """ - from ..Types._type import Type as _Type from loguru import logger + from ..Types._type import Type as _Type + # The process isn't running. if not self.isRunning(): return @@ -1041,7 +1045,7 @@ def isError(self): def kill(self): """Kill the running process.""" - if not self._process is None and self._process.is_running(): + if self._process is not None and self._process.is_running(): self._process.kill() def stdout(self, n=10): @@ -1223,9 +1227,10 @@ def getInput(self, name=None, file_link=False): A path, or file link, to an archive of the process input. """ import os as _os - from IPython.display import FileLink as _FileLink import zipfile as _zipfile + from IPython.display import FileLink as _FileLink + if name is None: name = self._name + "_input" else: @@ -1281,11 +1286,12 @@ def getOutput(self, name=None, block="AUTO", file_link=False): output : str, IPython.display.FileLink A path, or file link, to an archive of the process output. """ - from IPython.display import FileLink as _FileLink - import os as _os import glob as _glob + import os as _os import zipfile as _zipfile + from IPython.display import FileLink as _FileLink + if name is None: name = self._name + "_output" else: @@ -1748,6 +1754,7 @@ def _convert_datadict_keys(self, datadict_keys): The DataFrame object containing the metric of the simulation. """ import warnings as _warnings + import pandas as pd datadict = {} @@ -1793,7 +1800,7 @@ def _is_list_of_strings(lst): def _odict_insert(dct, key, value, index): """Insert an item into an ordered dictionary.""" - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Store the original size of the dictionary. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py index fe3b36add..add3a4e7b 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_process_runner.py @@ -68,6 +68,7 @@ def __init__(self, processes, name="runner", work_dir=None): The working directory for the processes. """ import os as _os + from ._process import Process as _Process # Convert tuple to list. @@ -551,7 +552,7 @@ def startAll(self, serial=False, batch_size=None, max_retries=5): raise TypeError("'serial' must be of type 'bool'.") if batch_size is not None: - if not type(batch_size) is int: + if type(batch_size) is not int: raise TypeError("'batch_size' must be of type 'int'.") if batch_size < 1: raise ValueError("'batch_size' must be > 1.") @@ -560,7 +561,7 @@ def startAll(self, serial=False, batch_size=None, max_retries=5): batch_size = cpu_count() - if not type(max_retries) is int: + if type(max_retries) is not int: raise TypeError("'max_retries' must be of type 'int'.") if max_retries < 1: @@ -619,7 +620,7 @@ def _run_processes(self, serial=False, batch_size=None, max_retries=5): raise TypeError("'serial' must be of type 'bool'.") if batch_size is not None: - if not type(batch_size) is int: + if type(batch_size) is not int: raise TypeError("'batch_size' must be of type 'int'.") if batch_size < 1: raise ValueError("'batch_size' must be > 1.") @@ -628,7 +629,7 @@ def _run_processes(self, serial=False, batch_size=None, max_retries=5): batch_size = cpu_count() - if not type(max_retries) is int: + if type(max_retries) is not int: raise TypeError("'max_retries' must be of type 'int'.") if max_retries < 1: @@ -833,9 +834,10 @@ def _nest_directories(self, processes): new_processes : [:class:`Process `] A list of procesess with updated working directories. """ - from .._SireWrappers import System as _System import os as _os + from .._SireWrappers import System as _System + # Create the list of new processes. new_processes = [] diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_somd.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_somd.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_somd.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_somd.py index 8134b561e..34b8456e0 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Process/_somd.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_somd.py @@ -32,7 +32,6 @@ _pygtail = _try_import("pygtail") import string as _string - from . import _process @@ -101,12 +100,14 @@ def __init__( The Restraint object that contains information for the ABFE calculations. """ - import sys as _sys - from .._Exceptions import MissingSoftwareError as _MissingSoftwareError - from .. import Protocol as _Protocol import os as _os + import sys as _sys + from sire.legacy import Base as _SireBase + from .. import Protocol as _Protocol + from .._Exceptions import MissingSoftwareError as _MissingSoftwareError + # Call the base class constructor. super().__init__( system, @@ -244,15 +245,16 @@ def __repr__(self): def _setup(self): """Setup the input files and working directory ready for simulation.""" - from .. import _isVerbose - from .._SireWrappers import System as _System - from .. import Protocol as _Protocol import os as _os - from .. import IO as _IO + from sire.legacy import IO as _SireIO - # Create the input files... + from .. import IO as _IO + from .. import Protocol as _Protocol + from .. import _isVerbose + from .._SireWrappers import System as _System + # Create the input files... # First create a copy of the system. system = self._system.copy() @@ -389,11 +391,12 @@ def _setup(self): def _generate_config(self): """Generate SOMD configuration file strings.""" - from .._SireWrappers import System as _System + import os as _os import warnings as _warnings + from .. import Protocol as _Protocol - import os as _os from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import System as _System # Clear the existing configuration list. self._config = [] @@ -489,11 +492,13 @@ def start(self): process : :class:`Process.Somd ` A handle to the running process. """ - import timeit as _timeit import os as _os - from .. import _Utils + import timeit as _timeit + from sire.legacy import Base as _SireBase + from .. import _Utils + # The process is currently queued. if self.isQueued(): return @@ -551,9 +556,11 @@ def getSystem(self, block="AUTO"): The latest molecular system. """ import warnings as _warnings - from .. import IO as _IO + from sire.legacy import IO as _SireIO + from .. import IO as _IO + # Wait for the process to finish. if block is True: self.wait() @@ -649,6 +656,7 @@ def getTrajectory(self, backend="AUTO", block="AUTO"): The latest trajectory object. """ import warnings as _warnings + from .. import Trajectory as _Trajectory if not isinstance(backend, str): @@ -689,10 +697,11 @@ def getFrame(self, index): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import Trajectory as _Trajectory from sire.legacy import IO as _SireIO - if not type(index) is int: + from .. import Trajectory as _Trajectory + + if type(index) is not int: raise TypeError("'index' must be of type 'int'") max_index = ( @@ -769,6 +778,7 @@ def getTime(self, time_series=False, block="AUTO"): The current simulation time in nanoseconds. """ import warnings as _warnings + from .. import Protocol as _Protocol # Warn the user if the process has exited with an error. @@ -840,8 +850,8 @@ def getGradient(self, time_series=False, block="AUTO"): gradient : float The free energy gradient. """ - import warnings as _warnings import os as _os + import warnings as _warnings # Wait for the process to finish. if block is True: @@ -891,10 +901,11 @@ def getCurrentGradient(self, time_series=False): def _clear_output(self): """Reset stdout and stderr.""" - from .. import Protocol as _Protocol import glob as _glob import os as _os + from .. import Protocol as _Protocol + # Call the base class method. super()._clear_output() @@ -984,13 +995,15 @@ def _to_pert_file( molecule : :class:`System ` The molecule with properties corresponding to the lamda = 0 state. """ - from sire.legacy import Mol as _SireMol - from sire.legacy import MM as _SireMM + import random as _random + from sire.legacy import CAS as _SireCAS - from .._SireWrappers import Molecule as _Molecule + from sire.legacy import MM as _SireMM + from sire.legacy import Mol as _SireMol from sire.legacy import Units as _SireUnits - import random as _random + from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import Molecule as _Molecule if not isinstance(molecule, _Molecule): raise TypeError( @@ -2871,7 +2884,7 @@ def sort_dihedrals(dihedrals, idx): for idx0 in impropers0_idx.keys(): if idx1.equivalent(idx0): # Don't store duplicates. - if not idx0 in impropers_shared_idx.keys(): + if idx0 not in impropers_shared_idx.keys(): impropers_shared_idx[idx1] = ( impropers0_idx[idx0], impropers1_idx[idx1], diff --git a/python/BioSimSpace/Process/_task.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_task.py similarity index 99% rename from python/BioSimSpace/Process/_task.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_task.py index 30601b61b..b42b6c5f3 100644 --- a/python/BioSimSpace/Process/_task.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Process/_task.py @@ -246,11 +246,13 @@ def getOutput(self, filename=None, file_link=False): file_link : str, IPython.lib.display.FileLink The name of, or link to, a zipfile containing the output. """ - import zipfile as _zipfile + import glob as _glob import os as _os - from .. import _is_notebook + import zipfile as _zipfile + from IPython.display import FileLink as _FileLink - import glob as _glob + + from .. import _is_notebook # Don't recreate an existing zip file. if self._zipfile is None: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Process/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/Process/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Process/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/Process/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py index 7d3800d7a..3c6fb3f17 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py @@ -88,6 +88,7 @@ def _restart_interval(self): def _steps(self): # Return the number of steps based on the protocol value. import math as _math + from .. import Protocol as _Protocol if isinstance(self.protocol, _Protocol.Minimisation): @@ -178,12 +179,14 @@ def generateAmberConfig(self, extra_options=None, extra_lines=None): config : list The generated config list in an AMBER format. """ + import math as _math + import warnings as _warnings + from sire.legacy import Units as _SireUnits + from .. import Protocol as _Protocol - from ..Align._squash import _amber_mask_from_indices, _squashed_atom_mapping - import warnings as _warnings - import math as _math from ..Align._alch_ion import _get_protein_com_idx + from ..Align._squash import _amber_mask_from_indices, _squashed_atom_mapping extra_options = extra_options if extra_options is not None else {} extra_lines = extra_lines if extra_lines is not None else [] @@ -459,10 +462,12 @@ def generateGromacsConfig( config : list The generated config list in a GROMACS format. """ - from .. import Protocol as _Protocol, _gmx_version + import math as _math import warnings as _warnings + + from .. import Protocol as _Protocol + from .. import _gmx_version from ..FreeEnergy._restraint import Restraint as _Restraint - import math as _math from ..Units.Energy import kj_per_mol as _kj_per_mol from ..Units.Length import nanometer as _nanometer @@ -730,8 +735,9 @@ def generateSomdConfig( """ import math as _math import warnings as _warnings - from .._Exceptions import IncompatibleError as _IncompatibleError + from .. import Protocol as _Protocol + from .._Exceptions import IncompatibleError as _IncompatibleError extra_options = extra_options if extra_options is not None else {} extra_lines = extra_lines if extra_lines is not None else [] diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_custom.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_custom.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_custom.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_custom.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py similarity index 80% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py index 8860a7564..803b809b9 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_dummy.py @@ -10,8 +10,8 @@ def __init__(self): def __str__(self): """Return a human readable string representation of the object.""" - return f"" + return "" def __repr__(self): """Return a string showing how to instantiate the object.""" - return f"BioSimSpace.Protocol.Dummy()" + return "BioSimSpace.Protocol.Dummy()" diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py index cc225c97f..4c153d074 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_equilibration.py @@ -29,9 +29,8 @@ from .. import Types as _Types from .. import Units as _Units - -from ._protocol import Protocol as _Protocol from ._position_restraint import _PositionRestraintMixin +from ._protocol import Protocol as _Protocol class Equilibration(_Protocol, _PositionRestraintMixin): @@ -451,7 +450,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -488,7 +487,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py index 0b87236b0..612120222 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy.py @@ -26,10 +26,10 @@ __all__ = ["FreeEnergy"] -from ._free_energy_mixin import _FreeEnergyMixin -from ._production import Production as _Production from .. import Types as _Types from .. import Units as _Units +from ._free_energy_mixin import _FreeEnergyMixin +from ._production import Production as _Production class FreeEnergy(_Production, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py index c562b1493..b0b83b1a0 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_equilibration.py @@ -2,9 +2,8 @@ from .. import Types as _Types from .. import Units as _Units - -from ._free_energy_mixin import _FreeEnergyMixin from ._equilibration import Equilibration as _Equilibration +from ._free_energy_mixin import _FreeEnergyMixin class FreeEnergyEquilibration(_Equilibration, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py index a51655838..3b2918efd 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_minimisation.py @@ -1,8 +1,8 @@ __all__ = ["FreeEnergyMinimisation"] +from .. import Units as _Units from ._free_energy_mixin import _FreeEnergyMixin from ._minimisation import Minimisation as _Minimisation -from .. import Units as _Units class FreeEnergyMinimisation(_Minimisation, _FreeEnergyMixin): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py index 4bf0a29d2..82aa169c8 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_free_energy_mixin.py @@ -161,9 +161,10 @@ def setPerturbationType(self, perturbation_type): @staticmethod def _check_column_name(df): """Check if the dataframe or series has the right column name.""" - import pandas as _pd import warnings + import pandas as _pd + permitted_names = [ "fep", "bonded", @@ -175,7 +176,7 @@ def _check_column_name(df): ] if isinstance(df, _pd.Series): for name in df.index: - if not name in permitted_names: + if name not in permitted_names: warnings.warn( f"{name} not in the list of permitted names, " f"so may not be supported by the MD Engine " @@ -183,7 +184,7 @@ def _check_column_name(df): ) elif isinstance(df, _pd.DataFrame): for name in df.columns: - if not name in permitted_names: + if name not in permitted_names: warnings.warn( f"{name} not in the list of permitted names, " f"so may not be supported by the MD Engine " @@ -319,8 +320,8 @@ def checkLambdaValues(lam_vals, min_lam=None, max_lam=None, num_lam=None): lam_vals : pandas.DataFrame The pd.DataFrame representing the checked lambda values. """ - import pandas as _pd import numpy as _np + import pandas as _pd # A list of lambda values takes precedence. if lam_vals is not None: @@ -361,7 +362,7 @@ def checkLambdaValues(lam_vals, min_lam=None, max_lam=None, num_lam=None): else: _FreeEnergyMixin._check_column_name(lam_vals) - if not type(num_lam) is int: + if type(num_lam) is not int: raise TypeError("'num_lam' must be of type 'int'.") # Validate values. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py index bf9ee195c..da3eaf21d 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_metadynamics.py @@ -29,7 +29,6 @@ from .. import Types as _Types from ..Metadynamics import CollectiveVariable as _CollectiveVariable - from ._protocol import Protocol as _Protocol # Store the collective variable base type. @@ -521,7 +520,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -558,7 +557,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py index 098c217ad..430f4a220 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_minimisation.py @@ -27,9 +27,9 @@ __all__ = ["Minimisation"] -from ._protocol import Protocol as _Protocol -from ._position_restraint import _PositionRestraintMixin from .. import Units as _Units +from ._position_restraint import _PositionRestraintMixin +from ._protocol import Protocol as _Protocol class Minimisation(_Protocol, _PositionRestraintMixin): @@ -134,7 +134,7 @@ def setSteps(self, steps): """ import warnings as _warnings - if not type(steps) is int: + if type(steps) is not int: raise TypeError("'steps' must be of type 'int'") if steps <= 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py index fef64b689..715f9c021 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_position_restraint.py @@ -176,7 +176,7 @@ def setForceConstant(self, force_constant): force_constant = _Types._GeneralUnit(force_constant) except: raise ValueError( - f"Unable to parse 'force_constant' string." + "Unable to parse 'force_constant' string." ) from None elif not isinstance(force_constant, _Types._GeneralUnit): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py index 8df0e9dc4..0298d397e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_production.py @@ -27,10 +27,10 @@ __all__ = ["Production"] -from ._position_restraint import _PositionRestraintMixin -from ._protocol import Protocol as _Protocol from .. import Types as _Types from .. import Units as _Units +from ._position_restraint import _PositionRestraintMixin +from ._protocol import Protocol as _Protocol class Production(_Protocol, _PositionRestraintMixin): @@ -382,7 +382,7 @@ def setReportInterval(self, report_interval): """ import warnings as _warnings - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -419,7 +419,7 @@ def setRestartInterval(self, restart_interval): """ import warnings as _warnings - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: @@ -453,7 +453,7 @@ def setFirstStep(self, first_step): import math as _math import warnings as _warnings - if not type(first_step) is int: + if type(first_step) is not int: raise TypeError("'first_step' must be of type 'int'") if first_step < 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_protocol.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_protocol.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_protocol.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_protocol.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py index a530d303f..be1e88ebe 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_steering.py @@ -29,7 +29,6 @@ from .. import Types as _Types from ..Metadynamics import CollectiveVariable as _CollectiveVariable - from ._protocol import Protocol as _Protocol # Store the collective variable base type. @@ -615,7 +614,7 @@ def setReportInterval(self, report_interval): report_interval : int The number of integration steps between reporting statistics. """ - if not type(report_interval) is int: + if type(report_interval) is not int: raise TypeError("'report_interval' must be of type 'int'") if report_interval <= 0: @@ -650,7 +649,7 @@ def setRestartInterval(self, restart_interval): The number of integration steps between saving restart configurations and/or trajectory frames. """ - if not type(restart_interval) is int: + if type(restart_interval) is not int: raise TypeError("'restart_interval' must be of type 'int'") if restart_interval <= 0: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Protocol/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/Protocol/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Protocol/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/Protocol/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Solvent/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Solvent/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Solvent/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Solvent/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py b/src/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py rename to src/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py index 59012e57c..908a6396a 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Solvent/_solvent.py @@ -28,7 +28,6 @@ import sys as _sys - from ..Types import Angle as _Angle @@ -815,11 +814,12 @@ def _validate_input( (molecule, box, angles, shell, work_dir, property_map) : tuple The validated input arguments. """ + import warnings as _warnings + from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Molecules as _Molecules - import warnings as _warnings - from ..Types import Coordinate as _Coordinate from .._SireWrappers import System as _System + from ..Types import Coordinate as _Coordinate from ..Types import Length as _Length # Whether to check the box size. @@ -948,7 +948,7 @@ def _validate_input( box = 3 * [base_length] # Check that the ion concentration is valid. - if not isinstance(ion_conc, float) and not type(ion_conc) is int: + if not isinstance(ion_conc, float) and type(ion_conc) is not int: raise TypeError("'ion_conc' must be of type 'int' or 'float'.") elif ion_conc < 0: raise ValueError("'ion_conc' cannot be negative!") @@ -1049,21 +1049,21 @@ def _solvate( system : :class:`System ` The solvated system. """ - from sire.legacy.Maths import Vector as _Vector - from sire.legacy import Base as _SireBase + import os as _os + import re as _re + import shutil as _shutil import subprocess as _subprocess - from sire.legacy.Vol import TriclinicBox as _TriclinicBox + import warnings as _warnings + + from sire.legacy import Base as _SireBase + from sire.legacy.Maths import Vector as _Vector from sire.legacy.Units import degree as _degree + from sire.legacy.Vol import TriclinicBox as _TriclinicBox + from .. import IO as _IO - import shutil as _shutil - from .. import _isVerbose - from .. import _Utils - from .. import _gmx_exe - import warnings as _warnings + from .. import _gmx_exe, _isVerbose, _Utils from .._SireWrappers import System as _System - import re as _re from ..Types import Length as _Length - import os as _os if molecule is not None: # Get the axis aligned bounding box. @@ -1728,7 +1728,6 @@ def _rename_water_molecule(molecule): _models = [] # List of water models (actual names). _models_lower = [] # List of lower case names. _model_dict = {} # Mapping between lower case names and functions. -import sys as _sys _namespace = _sys.modules[__name__] for _var in dir(): diff --git a/python/BioSimSpace/Sandpit/Exscientia/Stream/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Stream/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Stream/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Stream/__init__.py diff --git a/python/BioSimSpace/Stream/_stream.py b/src/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py similarity index 95% rename from python/BioSimSpace/Stream/_stream.py rename to src/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py index 15bff0d4e..83f15fc44 100644 --- a/python/BioSimSpace/Stream/_stream.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py @@ -43,10 +43,10 @@ def save(sire_object, filebase): The base name of the binary output file. """ from sire import stream as _NewSireStream - from .._Exceptions import StreamError as _StreamError - from .. import _isVerbose from sire import system as _NewSireSystem - from .. import _SireWrappers + + from .. import _isVerbose, _SireWrappers + from .._Exceptions import StreamError as _StreamError from .._SireWrappers._sire_wrapper import SireWrapper as _SireWrapper # Validate input. @@ -91,13 +91,14 @@ def load(file): file : str The path to the binary file containing the streamed object. """ + import os as _os + from sire import stream as _NewSireStream + from sire import system as _NewSireSystem from sire.legacy import Mol as _SireMol + + from .. import _isVerbose, _SireWrappers from .._Exceptions import StreamError as _StreamError - from .. import _isVerbose - from sire import system as _NewSireSystem - from .. import _SireWrappers - import os as _os # Validate input. @@ -151,9 +152,10 @@ def getMetadata(file): The metadata associated with the file. If none is present, then an empty dictionary will be returned. """ - from sire import stream as _NewSireStream import os as _os + from sire import stream as _NewSireStream + if not _os.path.isfile(file): raise ValueError(f"Unable to locate stream file: {file}") @@ -182,9 +184,10 @@ def getSireMetadata(file): The Sire metadata associated with the file. If none is present, then an empty dictionary will be returned. """ - from sire import stream as _NewSireStream import os as _os + from sire import stream as _NewSireStream + if not _os.path.isfile(file): raise ValueError(f"Unable to locate stream file: {file}") @@ -242,6 +245,7 @@ def _add_metadata(sire_object): The metadata associated with the object. """ from sire import stream as _NewSireStream + from .. import _SireWrappers from .._SireWrappers._sire_wrapper import SireWrapper as _SireWrapper @@ -252,9 +256,10 @@ def _add_metadata(sire_object): "'sire_object' must be of type 'BioSimSpace._SireWrappers.SireWrapper'." ) - from sire import __version__ as _sire_version from sire import __revisionid__ as _sire_revisionid - from .. import _version + from sire import __version__ as _sire_version + + from ...._version import __version__ as _bss_full_version # Work out the name of the Sandpit. try: @@ -263,10 +268,10 @@ def _add_metadata(sire_object): sandpit = "None" # Extract the BioSimSpace version and revision ID. - _bss_version = _version.get_versions()["version"].split("+")[0] - _bss_revisionid = _version.get_versions()["full-revisionid"] - if _bss_revisionid is not None: - _bss_revisionid = _bss_revisionid[0:7] + _bss_version = _bss_full_version.split("+")[0] + # Extract revision from version string (e.g., "1.0+5.gabcdef" -> "abcdef") + if "+" in _bss_full_version and ".g" in _bss_full_version: + _bss_revisionid = _bss_full_version.split(".g")[-1].split(".")[0] else: _bss_revisionid = "None" diff --git a/python/BioSimSpace/Sandpit/Exscientia/Trajectory/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Trajectory/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Trajectory/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Trajectory/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py b/src/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py rename to src/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py index f8eac1a6b..535dc986d 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Trajectory/_trajectory.py @@ -81,24 +81,25 @@ def getFrame(trajectory, topology, index, system=None, property_map={}): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import _Utils import os as _os - from sire.legacy import Mol as _SireMol - from sire._load import _resolve_path - from .._SireWrappers import System as _System import uuid as _uuid - from sire.legacy import IO as _SireIO - from .. import _isVerbose - from sire import load as _sire_load import warnings as _warnings + from sire import load as _sire_load + from sire._load import _resolve_path + from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + + from .. import _isVerbose, _Utils + from .._SireWrappers import System as _System + if not isinstance(trajectory, str): raise TypeError("'trajectory' must be of type 'str'") if not isinstance(topology, str): raise TypeError("'topology' must be of type 'str'") - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if not isinstance(property_map, dict): @@ -361,14 +362,16 @@ def __init__( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .. import _Utils import os as _os - from sire.legacy import Mol as _SireMol + import warnings as _warnings + from sire._load import _resolve_path - from .._SireWrappers import System as _System - from ..Process._process import Process as _Process from sire.legacy import IO as _SireIO - import warnings as _warnings + from sire.legacy import Mol as _SireMol + + from .. import _Utils + from .._SireWrappers import System as _System + from ..Process import _process # Set default member variables. self._process = None @@ -388,7 +391,7 @@ def __init__( ) # Both use cases active. Default to process. - if not process is None and not trajectory is None: + if process is not None and trajectory is not None: _warnings.warn( "Both a process and trajectory file are specified! Defaulting to 'process'." ) @@ -396,7 +399,7 @@ def __init__( # BioSimSpace process. if process is not None: - if isinstance(process, _Process): + if isinstance(process, _process.Process): self._process = process process_name = process.__class__.__name__ # Check that the process can generate a trajectory. @@ -538,11 +541,13 @@ def getTrajectory(self, format="auto"): The trajectory in MDTraj or MDAnalysis format. """ import copy as _copy - import shutil as _shutil import os as _os + import shutil as _shutil import uuid as _uuid - from sire import load as _sire_load import warnings as _warnings + + from sire import load as _sire_load + from .._Exceptions import IncompatibleError as _IncompatibleError if not isinstance(format, str): @@ -685,14 +690,16 @@ def getFrames(self, indices=None): frames : [:class:`System `] The list of System objects. """ - from ..Types import Time as _Time import os as _os - from .._SireWrappers import System as _System import uuid as _uuid + import warnings as _warnings + from sire.legacy import IO as _SireIO + from .. import _isVerbose - import warnings as _warnings from .._Exceptions import IncompatibleError as _IncompatibleError + from .._SireWrappers import System as _System + from ..Types import Time as _Time # The process is running. Grab the latest trajectory. if self._process is not None and self._process.isRunning(): @@ -1005,14 +1012,14 @@ def rmsd(self, frame=None, atoms=None): rmsd : [:class:`Length `] A list containing the RMSD value at each time point. """ - from .. import _isVerbose from .. import Units as _Units + from .. import _isVerbose # Default to the first frame. if frame is None: frame = 0 else: - if not type(frame) is int: + if type(frame) is not int: raise TypeError("'frame' must be of type 'int'") else: # Store the number of frames. @@ -1132,14 +1139,16 @@ def _split_molecules(frame, pdb, reference, work_dir, property_map={}): is_squashed : bool Whether the passed frame was squashed. """ - from sire.legacy import Vol as _SireVol import os as _os - from .._SireWrappers import System as _System import uuid as _uuid - from ..Align._squash import _squash, _unsquash + from sire.legacy import IO as _SireIO - from .. import _isVerbose from sire.legacy import Units as _SireUnits + from sire.legacy import Vol as _SireVol + + from .. import _isVerbose + from .._SireWrappers import System as _System + from ..Align._squash import _squash, _unsquash if not isinstance(frame, (_SireIO.AmberRst7, _SireIO.Gro87)): raise TypeError( @@ -1354,9 +1363,11 @@ def _update_water_topology(system, topology, trajectory, property_map): system : :class:`System ` The passed system with updated water topology. """ + import os as _os + from sire.legacy import IO as _SireIO + from .._SireWrappers import System as _System - import os as _os if not isinstance(system, _System): raise TypeError("'system' must be of type 'BioSimSpace._SireWrappers.System'") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Types/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/__init__.py index 19f34e385..c1412dd0e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Types/__init__.py @@ -52,6 +52,10 @@ from ._charge import * from ._coordinate import * from ._energy import * + +# Hide GeneralUnit since it will be automatically created from combinations +# of the unit based types above. +from ._general_unit import GeneralUnit as _GeneralUnit from ._length import * from ._mass import * from ._pressure import * @@ -59,7 +63,3 @@ from ._time import * from ._vector import * from ._volume import * - -# Hide GeneralUnit since it will be automatically created from combinations -# of the unit based types above. -from ._general_unit import GeneralUnit as _GeneralUnit diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_angle.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_angle.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_angle.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_angle.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_area.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_area.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_area.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_area.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py index 990417caa..29cdb8ce9 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Types/_base_units.py @@ -34,8 +34,8 @@ from ._pressure import * from ._temperature import * from ._time import * -from ._volume import * from ._type import Type as _Type +from ._volume import * _namespace = _sys.modules[__name__] diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_charge.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_charge.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_charge.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_charge.py diff --git a/python/BioSimSpace/Types/_coordinate.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_coordinate.py similarity index 100% rename from python/BioSimSpace/Types/_coordinate.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_coordinate.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_energy.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_energy.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_energy.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_energy.py diff --git a/python/BioSimSpace/Types/_general_unit.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py similarity index 99% rename from python/BioSimSpace/Types/_general_unit.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py index 07ad85c8b..3af0aa4a7 100644 --- a/python/BioSimSpace/Types/_general_unit.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py @@ -813,7 +813,7 @@ def _from_string(cls, string): # Create and return a new object. return GeneralUnit(general_unit) - except Exception as e: + except Exception: raise ValueError( f"Could not infer GeneralUnit from string '{string}'" ) from None diff --git a/python/BioSimSpace/Types/_length.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_length.py similarity index 100% rename from python/BioSimSpace/Types/_length.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_length.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_mass.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_mass.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_pressure.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_pressure.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_pressure.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_pressure.py diff --git a/python/BioSimSpace/Types/_temperature.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py similarity index 99% rename from python/BioSimSpace/Types/_temperature.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py index a33dd6eaa..77356b718 100644 --- a/python/BioSimSpace/Types/_temperature.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py @@ -410,7 +410,7 @@ def _validate_unit(cls, unit): elif unit in cls._abbreviations: return cls._abbreviations[unit] elif len(unit) == 0: - raise ValueError(f"Unit is not given. You must supply the unit.") + raise ValueError("Unit is not given. You must supply the unit.") else: raise ValueError( "Unsupported unit '%s'. Supported units are: '%s'" diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_time.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_time.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_time.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_time.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_type.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_type.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_type.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_type.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_vector.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_vector.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_vector.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_vector.py diff --git a/python/BioSimSpace/Types/_volume.py b/src/BioSimSpace/Sandpit/Exscientia/Types/_volume.py similarity index 100% rename from python/BioSimSpace/Types/_volume.py rename to src/BioSimSpace/Sandpit/Exscientia/Types/_volume.py index be7b90c06..f3d2bde88 100644 --- a/python/BioSimSpace/Types/_volume.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Types/_volume.py @@ -121,8 +121,8 @@ def __init__(self, *args): def __truediv__(self, other): """Division operator.""" - from ._length import Length as _Length from ._area import Area as _Area + from ._length import Length as _Length # Convert int to float. if type(other) is int: diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Angle/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Angle/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Angle/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Angle/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Area/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Area/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Area/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Area/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Charge/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Charge/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Charge/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Charge/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Energy/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Energy/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Energy/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Energy/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Length/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Length/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Length/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Length/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Pressure/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Pressure/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Pressure/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Pressure/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Temperature/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Temperature/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Temperature/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Temperature/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Time/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Time/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Time/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Time/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Volume/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/Volume/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Units/Volume/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/Volume/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/Units/__init__.py similarity index 92% rename from python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/Units/__init__.py index 691f52307..7ebeabc95 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/Units/__init__.py @@ -137,16 +137,18 @@ _sr.use_new_api() del _sr -from . import Angle -from . import Area -from . import Charge -from . import Energy -from . import Length -from . import Mass -from . import Pressure -from . import Temperature -from . import Time -from . import Volume +from . import ( + Angle, + Area, + Charge, + Energy, + Length, + Mass, + Pressure, + Temperature, + Time, + Volume, +) # Whether to allow operations between offset units, see here for details: # http://pint.readthedocs.io/en/latest/nonmult.html diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Exceptions/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/_Exceptions/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_Exceptions/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/_Exceptions/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Exceptions/_exceptions.py b/src/BioSimSpace/Sandpit/Exscientia/_Exceptions/_exceptions.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_Exceptions/_exceptions.py rename to src/BioSimSpace/Sandpit/Exscientia/_Exceptions/_exceptions.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py index 6a9f76699..6b84c5297 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/__init__.py @@ -47,7 +47,7 @@ from ._bond import * from ._molecule import * from ._molecules import * +from ._replica_system import * from ._residue import * from ._search_result import * from ._system import * -from ._replica_system import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py index b8aa38e88..a9a1b7567 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_atom.py @@ -49,7 +49,6 @@ def __init__(self, atom): from sire.legacy import Mol as _SireMol # Check that the atom is valid. - # A Sire Atom object. if isinstance(atom, _SireMol._Mol.Atom): sire_object = atom @@ -138,8 +137,8 @@ def coordinates(self, property_map={}): coordinates : class:`Coordinate ` The coordinates of the atom. """ - from ..Types import Length as _Length from ..Types import Coordinate as _Coordinate + from ..Types import Length as _Length prop = property_map.get("coordinates", "coordinates") @@ -197,6 +196,7 @@ def toMolecule(self): system : :class:`Molecule ` """ from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule return _Molecule( diff --git a/python/BioSimSpace/_SireWrappers/_bond.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_bond.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py index e7df85b07..c30efa810 100644 --- a/python/BioSimSpace/_SireWrappers/_bond.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py @@ -49,7 +49,6 @@ def __init__(self, bond): from sire.legacy import MM as _SireMM # Check that the bond is valid. - # A Sire Bond object. if isinstance(bond, _SireMM._MM.Bond): sire_object = bond @@ -324,6 +323,7 @@ def toMolecule(self): system : :class:`Molecule ` """ from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule return _Molecule( @@ -363,6 +363,7 @@ def search(self, query, property_map={}): >>> result = bond.search("atomidx 23") """ from sire.legacy import Mol as _SireMol + from .. import _isVerbose from ._search_result import SearchResult as _SearchResult diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py similarity index 98% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py index 33a5f2f11..654be76bf 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecule.py @@ -117,8 +117,8 @@ def __repr__(self): def __add__(self, other): """Addition operator.""" - from ._system import System as _System from ._molecules import Molecules as _Molecules + from ._system import System as _System # Convert tuple to a list. if isinstance(other, tuple): @@ -229,7 +229,8 @@ def coordinates(self, property_map={}): [coordinates] : [class:`Coordinate `] The coordinates of the atoms in the molecule. """ - from ..Types import Coordinate as _Coordinate, Length as _Length + from ..Types import Coordinate as _Coordinate + from ..Types import Length as _Length prop = property_map.get("coordinates", "coordinates") @@ -310,13 +311,14 @@ def extract(self, indices, renumber=False, property_map={}): molecule : :class:`Molecule ` The extracted molecule. """ - from sire.legacy import IO as _SireIO, Mol as _SireMol - from .._Exceptions import IncompatibleError as _IncompatibleError + from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError # TODO: This method is slow for large molecules. Re-write in pure C++ # and provide a suitable wrapper function. - # Convert tuple to list. if isinstance(indices, tuple): indices = list(indices) @@ -332,7 +334,7 @@ def extract(self, indices, renumber=False, property_map={}): for x in indices: # Check type. - if not type(x) is int: + if type(x) is not int: raise TypeError("'indices' must be a list of 'int' types.") # Map index back to range. @@ -689,9 +691,10 @@ def search(self, query, property_map={}): >>> result = molecule.search("atomidx 23") """ - from ._search_result import SearchResult as _SearchResult from sire.legacy import Mol as _SireMol + from .. import _isVerbose + from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): raise TypeError("'query' must be of type 'str'") @@ -756,15 +759,14 @@ def makeCompatibleWith( verbose : bool Whether to report status updates to stdout. """ - from .._Exceptions import IncompatibleError as _IncompatibleError - from sire.legacy import ( - Base as _SireBase, - IO as _SireIO, - MM as _SireMM, - Mol as _SireMol, - System as _SireSystem, - ) + from sire.legacy import IO as _SireIO + from sire.legacy import MM as _SireMM + from sire.legacy import Base as _SireBase + from sire.legacy import Mol as _SireMol + from sire.legacy import System as _SireSystem + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError from ._system import System as _System # Validate input. @@ -871,10 +873,10 @@ def makeCompatibleWith( # See if any of the new properties are in the map, add them if not. for prop in props0: - if not prop in _property_map: + if prop not in _property_map: _property_map[prop] = prop for prop in props1: - if not prop in _property_map: + if prop not in _property_map: _property_map[prop] = prop # Make the molecule editable. @@ -1413,9 +1415,10 @@ def translate(self, vector, property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ..Types import Length as _Length from sire.legacy import Maths as _SireMaths + from ..Types import Length as _Length + # Convert tuple to a list. if isinstance(vector, tuple): vector = list(vector) @@ -1516,7 +1519,8 @@ def repartitionHydrogenMass( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Base as _SireBase, IO as _SireIO + from sire.legacy import IO as _SireIO + from sire.legacy import Base as _SireBase # Convert int to float. if type(factor) is int: @@ -1648,10 +1652,12 @@ def _fixCharge(self, property_map={}): user defined values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .._Exceptions import IncompatibleError as _IncompatibleError from math import isclose as _isclose + from sire.legacy import Units as _SireUnits + from .._Exceptions import IncompatibleError as _IncompatibleError + # Get the user defined charge property. prop = property_map.get("charge", "charge") @@ -1727,7 +1733,10 @@ def _toRegularMolecule( molecule : BioSimSpace._SireWrappers.Molecule The molecule at the chosen end state. """ - from sire.legacy import Base as _SireBase, IO as _SireIO, Mol as _SireMol + from sire.legacy import IO as _SireIO + from sire.legacy import Base as _SireBase + from sire.legacy import Mol as _SireMol + from ._system import System as _System if not isinstance(is_lambda1, bool): @@ -1867,8 +1876,8 @@ def _extractMolecule(self, property_map={}, is_lambda1=False): dummy_indices : [ int ] The indices of any dummy atoms in the original molecule. """ - from .._Exceptions import IncompatibleError as _IncompatibleError from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError if not isinstance(is_lambda1, bool): raise TypeError("'is_lambda1' must be of type 'bool'") @@ -1952,9 +1961,10 @@ def _getPerturbationIndices(self): def getCOMIdx(self): """Get the index of the atom that closest to the center of mass.""" + import numpy as _np + from ..Types import Vector as _BSSVector from ..Units.Length import angstrom as _angstrom - import numpy as _np if self.isPerturbable(): property_map = {"coordinates": "coordinates0", "mass": "mass0"} diff --git a/python/BioSimSpace/_SireWrappers/_molecules.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_molecules.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py index ef7240381..2ce4bc8a7 100644 --- a/python/BioSimSpace/_SireWrappers/_molecules.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py @@ -51,11 +51,11 @@ def __init__(self, molecules): """ from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem - from ._system import System as _System + from ._molecule import Molecule as _Molecule + from ._system import System as _System # Check that the molecules argument is valid. - # Convert tuple to list. if isinstance(molecules, tuple): molecules = list(molecules) @@ -120,8 +120,8 @@ def __repr__(self): def __add__(self, other): """Addition operator.""" - from ._system import System as _System from ._molecule import Molecule as _Molecule + from ._system import System as _System # Convert tuple to a list. if isinstance(other, tuple): @@ -182,6 +182,7 @@ def __add__(self, other): def __getitem__(self, key): """Get a molecule from the container.""" from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule # Slice. diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py index c42a0a414..780b3d173 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_replica_system.py @@ -65,9 +65,10 @@ def __init__( format. """ + from sire.legacy.System import System as _SireSystem from sire.mol._trajectory import TrajectoryIterator as _TrajectoryIterator from sire.system import System as _NewSireSystem - from sire.legacy.System import System as _SireSystem + from ._system import System as _System # Check that the system is valid. @@ -136,6 +137,7 @@ def __init__( if not is_traj_iterator: import os as _os from tempfile import NamedTemporaryFile as _NamedTemporaryFile + from .. import _isVerbose if not _os.path.isfile(trajectory): @@ -218,8 +220,10 @@ def __init__( import os as _os from tempfile import TemporaryDirectory as _TemporaryDirectory + from sire import load as _load from sire import save as _save + from .. import _isVerbose with _TemporaryDirectory() as tmp_dir: @@ -227,7 +231,7 @@ def __init__( # Write out the current coordinates the specified number of times. try: # Write the first file only. - tmp_file = _os.path.join(tmp_dir, f"replica_0000.gro") + tmp_file = _os.path.join(tmp_dir, "replica_0000.gro") if self._is_perturbable and self._is_squashed: _save( _NewSireSystem(self._squashed_system), tmp_file, silent=True @@ -239,7 +243,7 @@ def __init__( # Copy the first file for the remaining replicas. for i in range(1, num_replicas): tmp_file = _os.path.join(tmp_dir, f"replica_{i:04d}.gro") - _os.link(_os.path.join(tmp_dir, f"replica_0000.gro"), tmp_file) + _os.link(_os.path.join(tmp_dir, "replica_0000.gro"), tmp_file) filenames.append(tmp_file) except Exception as e: msg = "Failed to write temporary files for replica duplication." @@ -364,6 +368,7 @@ def save(self, filename, save_velocities=False): from sire import save as _save from sire.stream import save as _save_stream + from .. import _isVerbose if not isinstance(filename, str): @@ -437,6 +442,7 @@ def load(stream, trajectory): """ from sire.stream import load as _load + from .. import _isVerbose if not isinstance(stream, str): @@ -482,9 +488,10 @@ def getReplica(self, index, is_lambda1=False, property_map={}): The requested replica as a BioSimSpace System object. """ - from ._system import System as _System from sire.morph import link_to_perturbed as _link_to_perturbed + from ._system import System as _System + if not isinstance(index, int): raise TypeError("'index' must be an integer.") @@ -555,6 +562,7 @@ def saveReplicas(self, filenames, save_velocities=False, is_lambda1=False): """ from sire import save as _save + from .. import _isVerbose if not isinstance(filenames, list): @@ -638,8 +646,10 @@ def loadReplicas(replica_system, filenames): import os as _os from tempfile import NamedTemporaryFile as _NamedTemporaryFile + from sire import load as _load from sire import save as _save + from .. import _isVerbose if not isinstance(replica_system, ReplicaSystem): diff --git a/python/BioSimSpace/_SireWrappers/_residue.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_residue.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py index 052318615..f4c4b0bef 100644 --- a/python/BioSimSpace/_SireWrappers/_residue.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py @@ -49,7 +49,6 @@ def __init__(self, residue): from sire.legacy import Mol as _SireMol # Check that the residue is valid. - # A Sire Residue object. if isinstance(residue, _SireMol._Mol.Residue): sire_object = residue @@ -277,6 +276,7 @@ def toMolecule(self): system : :class:`Molecule ` """ from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule return _Molecule( @@ -316,8 +316,9 @@ def search(self, query, property_map={}): >>> result = residue.search("atomidx 23") """ from sire.legacy import Mol as _SireMol - from ._search_result import SearchResult as _SearchResult + from .. import _isVerbose + from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): raise TypeError("'query' must be of type 'str'") diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py index eb9f37a42..98655bd75 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_search_result.py @@ -102,9 +102,10 @@ def __hash__(self): def __getitem__(self, key): """Get a search result from the container.""" - from ._bond import Bond as _Bond - from ._atom import Atom as _Atom import sire.legacy as _Sire + + from ._atom import Atom as _Atom + from ._bond import Bond as _Bond from ._molecule import Molecule as _Molecule from ._residue import Residue as _Residue diff --git a/python/BioSimSpace/_SireWrappers/_sire_wrapper.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_sire_wrapper.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py index bf8a08242..91175c5a7 100644 --- a/python/BioSimSpace/_SireWrappers/_sire_wrapper.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py @@ -171,10 +171,11 @@ def translate(self, vector, property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .._Exceptions import IncompatibleError as _IncompatibleError + from sire.legacy import Maths as _SireMaths + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError from ..Types import Length as _Length - from sire.legacy import Maths as _SireMaths # Convert tuple to a list. if isinstance(vector, tuple): @@ -290,9 +291,10 @@ def _getCenterOfMass(self, space=None, property_map={}): com: [:class:`Length `] The center of mass of the object. """ - from .. import Units as _Units from sire.legacy import Vol as _SireVol + from .. import Units as _Units + if space is None: space_prop = property_map.get("space", "space") try: @@ -313,7 +315,6 @@ def _getCenterOfMass(self, space=None, property_map={}): # Whether this is an atom, molecule or residue, or system. is_atom = False - is_mol_res = False is_system = False # Get the first atom in the object. @@ -323,7 +324,6 @@ def _getCenterOfMass(self, space=None, property_map={}): except: try: atom = self.getAtoms()[0] - is_mol_res = True except: atom = self is_atom = True @@ -448,8 +448,9 @@ def _getAABox(self, property_map={}): The axis-aligned bounding box for the object. """ from sire.legacy import Vol as _SireVol - from .._Exceptions import IncompatibleError as _IncompatibleError + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError # Initialise the coordinates vector. coord = [] diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py index 676098ccc..00115ae24 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_system.py @@ -30,10 +30,9 @@ __all__ = ["System"] +from .. import Units as _Units from ..Types import Angle as _Angle from ..Types import Coordinate as _Coordinate -from .. import Units as _Units - from ._sire_wrapper import SireWrapper as _SireWrapper @@ -54,13 +53,13 @@ def __init__(self, system): A Sire or BioSimSpace System object, a Sire or BioSimSpace Molecule object, a BioSimSpace Molecules object, or a list of BioSimSpace molecule objects. """ - from ._molecule import Molecule as _Molecule - from ._molecules import Molecules as _Molecules from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem - # Check that the system is valid. + from ._molecule import Molecule as _Molecule + from ._molecules import Molecules as _Molecules + # Check that the system is valid. # Convert tuple to a list. if isinstance(system, tuple): system = list(system) @@ -179,8 +178,8 @@ def __sub__(self, other): def __contains__(self, other): """Return whether other is in self.""" - from ._molecule import Molecule as _Molecule from ._atom import Atom as _Atom + from ._molecule import Molecule as _Molecule from ._residue import Residue as _Residue if not isinstance(other, (_Molecule, _Atom, _Residue)): @@ -194,9 +193,10 @@ def __contains__(self, other): def __getitem__(self, key): """Get a molecule from the system.""" + from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules - from sire.legacy import Mol as _SireMol # Slice. if isinstance(key, slice): @@ -272,9 +272,10 @@ def copy(self, renumber=False): System : :class:`System ` A copy of the object. """ - from ._molecules import Molecules as _Molecules from sire.legacy import Mol as _SireMol + from ._molecules import Molecules as _Molecules + if not isinstance(renumber, bool): raise TypeError("'renumber' must be of type 'bool'") @@ -529,7 +530,7 @@ def _object_compare(object0, object1): name0 = inv_prop_map0.get(p0, p0) # Skip if excluded. - if not name0 in _excluded_properties: + if name0 not in _excluded_properties: # Get the property name in other. name1 = property_map1.get(name0, name0) @@ -564,7 +565,7 @@ def _object_compare(object0, object1): for p1 in props1: name1 = inv_prop_map1.get(p1, p1) # This is a property unique to object1, so they differ. - if not name1 in _excluded_properties and name1 not in props0: + if name1 not in _excluded_properties and name1 not in props0: return False # If we get this far, then the objects are the same. @@ -606,15 +607,15 @@ def addMolecules(self, molecules): A Molecule, Molecules object, a list of Molecule objects, a System, or a SearchResult containing molecules. """ - from ._molecule import Molecule as _Molecule - from ._molecules import Molecules as _Molecules - from ._search_result import SearchResult as _SearchResult import warnings as _warnings - from sire.legacy import Mol as _SireMol + from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + from sire.legacy.Mol import SelectorMol as _SelectorMol + from ._molecule import Molecule as _Molecule + from ._molecules import Molecules as _Molecules from ._search_result import SearchResult as _SearchResult - from sire.legacy.Mol import SelectorMol as _SelectorMol # Whether this is a selector mol object. is_selector_mol = False @@ -705,7 +706,7 @@ def addMolecules(self, molecules): # Search for molecules with a velocity property. try: mols_with_velocities = self.search( - f"mols with property velocity" + "mols with property velocity" ).molecules() num_vels = len(mols_with_velocities) except: @@ -761,9 +762,10 @@ def removeMolecules(self, molecules): [:class:`Molecule `] A Molecule, Molecules object, or list of Molecule objects. """ + from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules - from sire.legacy import Mol as _SireMol # Whether the molecules are in a Sire container. is_sire_container = False @@ -835,9 +837,10 @@ def updateMolecule(self, index, molecule): molecule : :class:`Molecule ` The updated (or replacement) molecule. """ - from ._molecule import Molecule as _Molecule from sire.legacy import IO as _SireIO + from ._molecule import Molecule as _Molecule + if type(index) is not int: raise TypeError("'index' must be of type 'int'") @@ -884,9 +887,10 @@ def updateMolecules(self, molecules): [:class:`Molecule `] A Molecule, or list of Molecule objects. """ - from ._molecule import Molecule as _Molecule - from sire.legacy import Mol as _SireMol from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + + from ._molecule import Molecule as _Molecule # Convert tuple to a list. if isinstance(molecules, tuple): @@ -984,9 +988,10 @@ def getMolecules(self, group="all"): molecules : [:class:`Molecule `] The list of molecules in the group. """ - from ._molecules import Molecules as _Molecules from sire.legacy import Mol as _SireMol + from ._molecules import Molecules as _Molecules + if not isinstance(group, str): raise TypeError("'group' must be of type 'str'") @@ -1030,7 +1035,7 @@ def getAtom(self, index): atom : :class:`Atom ` The atom at the specified index. """ - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Set the MolNum to atom index mapping. @@ -1086,7 +1091,7 @@ def getResidue(self, index): residue : :class:`Residue ` The residue at the specified index. """ - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Set the MolNum to residue index mapping. @@ -1313,10 +1318,10 @@ def setCoordinates( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ + import numpy as _np from sire.legacy import IO as _SireIO - from .. import _isVerbose - import numpy as _np + from .. import _isVerbose # Validate input. if not isinstance(coordinates, _np.ndarray): @@ -1695,8 +1700,9 @@ def search(self, query, property_map={}): >>> result = system.search("molidx 10 and atomidx 23") """ from sire.mol import Select as _Select - from ._search_result import SearchResult as _SearchResult + from .. import _isVerbose + from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): raise TypeError("'query' must be of type 'str'") @@ -1740,8 +1746,8 @@ def getIndex(self, item): index : int, [int] The absolute index of the atom/residue/molecule in the system. """ - from ._molecule import Molecule as _Molecule from ._atom import Atom as _Atom + from ._molecule import Molecule as _Molecule from ._residue import Residue as _Residue # Convert single object to list. @@ -1842,10 +1848,11 @@ def setBox(self, box, angles=3 * [_Angle(90, "degree")], property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Vol as _SireVol from sire.legacy import Maths as _SireMaths - from ..Types import Length as _Length from sire.legacy import Units as _SireUnits + from sire.legacy import Vol as _SireVol + + from ..Types import Length as _Length # Convert tuples to lists. if isinstance(box, tuple): @@ -1925,6 +1932,7 @@ def getBox(self, property_map={}): The box vector angles: yz, xz, and xy. """ from sire.legacy import Vol as _SireVol + from ..Types import Length as _Length if not isinstance(property_map, dict): @@ -2095,8 +2103,8 @@ def getRestraintAtoms( indices : [int] A list of the backbone atom indices. """ - from ._utils import _prot_res, _nucl_res, _ions from .._Exceptions import IncompatibleError as _IncompatibleError + from ._utils import _ions, _nucl_res, _prot_res if not isinstance(restraint, str): raise TypeError("'restraint' must be of type 'str'.") @@ -2109,7 +2117,7 @@ def getRestraintAtoms( if restraint not in allowed: raise ValueError(f"'restraint' must be one of: {allowed}") - if mol_index is not None and not type(mol_index) is int: + if mol_index is not None and type(mol_index) is not int: raise TypeError("'mol_index' must be of type 'int'.") if not isinstance(is_absolute, bool): @@ -2461,8 +2469,9 @@ def _getAABox(self, property_map={}): The axis-aligned bounding box for the molecule. """ from sire.legacy import Vol as _SireVol - from .._Exceptions import IncompatibleError as _IncompatibleError + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError # Initialise the coordinates vector. coord = [] @@ -2513,9 +2522,10 @@ def _renumberMolecules(self, molecules, is_rebuild=False): molecules : [:class:`Molecule `] The renumber list of molecule objects. """ - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule + # Renumber everything. if is_rebuild: num_molecules = 0 diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_utils.py b/src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_utils.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_utils.py rename to src/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_utils.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Utils/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/_Utils/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_Utils/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/_Utils/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_command_split.py b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_command_split.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_Utils/_command_split.py rename to src/BioSimSpace/Sandpit/Exscientia/_Utils/_command_split.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py rename to src/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py index 70c7b2fb0..29e2a894b 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_contextmanagers.py @@ -41,9 +41,10 @@ def cd(work_dir): work_dir : str The working directory for the context. """ - from ._workdir import WorkDir as _WorkDir import os as _os + from ._workdir import WorkDir as _WorkDir + # Validate the input. if not isinstance(work_dir, (str, _WorkDir)): raise TypeError( diff --git a/python/BioSimSpace/_Utils/_module_stub.py b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py similarity index 99% rename from python/BioSimSpace/_Utils/_module_stub.py rename to src/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py index d8522ffb3..e048eae7e 100644 --- a/python/BioSimSpace/_Utils/_module_stub.py +++ b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py @@ -121,7 +121,7 @@ def _try_import(name: str, install_command: str = None): try: m = importlib.import_module(name) - except Exception as e: + except Exception: m = _ModuleStub(name=name, install_command=install_command) _failed_modules[name] = m diff --git a/python/BioSimSpace/_Utils/_workdir.py b/src/BioSimSpace/Sandpit/Exscientia/_Utils/_workdir.py similarity index 100% rename from python/BioSimSpace/_Utils/_workdir.py rename to src/BioSimSpace/Sandpit/Exscientia/_Utils/_workdir.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/__init__.py b/src/BioSimSpace/Sandpit/Exscientia/__init__.py similarity index 92% rename from python/BioSimSpace/Sandpit/Exscientia/__init__.py rename to src/BioSimSpace/Sandpit/Exscientia/__init__.py index 5625c5854..eecc8a01f 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/__init__.py +++ b/src/BioSimSpace/Sandpit/Exscientia/__init__.py @@ -134,9 +134,10 @@ def _isVerbose(): else: _amber_home = None +from os import path as _path + # Check to see if GROMACS is installed. from sire.legacy import Base as _SireBase -from os import path as _path # First, let the user tell us where to find GROMACS. This # assumes that gromacs is installed in $GROMACSHOME/bin/gmx. @@ -263,38 +264,35 @@ def _isVerbose(): "BioSimSpace.Sandpit.Exscientia._SireWrappers" ) - from . import _Exceptions - from . import _Utils + from . import _Exceptions, _Utils del _lazy_import else: - from . import Align - from . import Box - from . import Convert - from . import FreeEnergy - from . import Gateway - from . import IO - from . import Metadynamics - from . import MD - from . import Node - from . import Notebook - from . import Parameters - from . import Process - from . import Protocol - from . import Solvent - from . import Stream - from . import Trajectory - from . import Types - from . import Units - - from . import _Exceptions - from . import _SireWrappers - from . import _Utils + from . import ( + IO, + MD, + Align, + Box, + Convert, + FreeEnergy, + Gateway, + Metadynamics, + Node, + Notebook, + Parameters, + Process, + Protocol, + Solvent, + Stream, + Trajectory, + Types, + Units, + _Exceptions, + _SireWrappers, + _Utils, + ) del _can_lazy_import del _environ -# Import Versioneer from the package root. -from ... import _version - -__version__ = _version.get_versions()["version"] +from ..._version import __version__ diff --git a/python/BioSimSpace/Sandpit/__init__.py b/src/BioSimSpace/Sandpit/__init__.py similarity index 100% rename from python/BioSimSpace/Sandpit/__init__.py rename to src/BioSimSpace/Sandpit/__init__.py diff --git a/python/BioSimSpace/Solvent/__init__.py b/src/BioSimSpace/Solvent/__init__.py similarity index 100% rename from python/BioSimSpace/Solvent/__init__.py rename to src/BioSimSpace/Solvent/__init__.py diff --git a/python/BioSimSpace/Solvent/_solvent.py b/src/BioSimSpace/Solvent/_solvent.py similarity index 99% rename from python/BioSimSpace/Solvent/_solvent.py rename to src/BioSimSpace/Solvent/_solvent.py index b8bdbeba5..908a6396a 100644 --- a/python/BioSimSpace/Solvent/_solvent.py +++ b/src/BioSimSpace/Solvent/_solvent.py @@ -28,7 +28,6 @@ import sys as _sys - from ..Types import Angle as _Angle @@ -815,11 +814,12 @@ def _validate_input( (molecule, box, angles, shell, work_dir, property_map) : tuple The validated input arguments. """ - from .._SireWrappers import Molecule as _Molecule - from ..Types import Coordinate as _Coordinate - from .._SireWrappers import System as _System import warnings as _warnings + + from .._SireWrappers import Molecule as _Molecule from .._SireWrappers import Molecules as _Molecules + from .._SireWrappers import System as _System + from ..Types import Coordinate as _Coordinate from ..Types import Length as _Length # Whether to check the box size. @@ -948,7 +948,7 @@ def _validate_input( box = 3 * [base_length] # Check that the ion concentration is valid. - if not isinstance(ion_conc, float) and not type(ion_conc) is int: + if not isinstance(ion_conc, float) and type(ion_conc) is not int: raise TypeError("'ion_conc' must be of type 'int' or 'float'.") elif ion_conc < 0: raise ValueError("'ion_conc' cannot be negative!") @@ -1049,20 +1049,20 @@ def _solvate( system : :class:`System ` The solvated system. """ - from sire.legacy import Base as _SireBase - from .. import _Utils - from .. import IO as _IO - from .. import _gmx_exe - from .._SireWrappers import System as _System + import os as _os + import re as _re + import shutil as _shutil import subprocess as _subprocess import warnings as _warnings - from sire.legacy.Vol import TriclinicBox as _TriclinicBox - from .. import _isVerbose - import re as _re - import os as _os + + from sire.legacy import Base as _SireBase from sire.legacy.Maths import Vector as _Vector - import shutil as _shutil from sire.legacy.Units import degree as _degree + from sire.legacy.Vol import TriclinicBox as _TriclinicBox + + from .. import IO as _IO + from .. import _gmx_exe, _isVerbose, _Utils + from .._SireWrappers import System as _System from ..Types import Length as _Length if molecule is not None: @@ -1728,7 +1728,6 @@ def _rename_water_molecule(molecule): _models = [] # List of water models (actual names). _models_lower = [] # List of lower case names. _model_dict = {} # Mapping between lower case names and functions. -import sys as _sys _namespace = _sys.modules[__name__] for _var in dir(): diff --git a/python/BioSimSpace/Stream/__init__.py b/src/BioSimSpace/Stream/__init__.py similarity index 100% rename from python/BioSimSpace/Stream/__init__.py rename to src/BioSimSpace/Stream/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py b/src/BioSimSpace/Stream/_stream.py similarity index 95% rename from python/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py rename to src/BioSimSpace/Stream/_stream.py index 15bff0d4e..2b3a59ab9 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Stream/_stream.py +++ b/src/BioSimSpace/Stream/_stream.py @@ -43,10 +43,10 @@ def save(sire_object, filebase): The base name of the binary output file. """ from sire import stream as _NewSireStream - from .._Exceptions import StreamError as _StreamError - from .. import _isVerbose from sire import system as _NewSireSystem - from .. import _SireWrappers + + from .. import _isVerbose, _SireWrappers + from .._Exceptions import StreamError as _StreamError from .._SireWrappers._sire_wrapper import SireWrapper as _SireWrapper # Validate input. @@ -91,13 +91,14 @@ def load(file): file : str The path to the binary file containing the streamed object. """ + import os as _os + from sire import stream as _NewSireStream + from sire import system as _NewSireSystem from sire.legacy import Mol as _SireMol + + from .. import _isVerbose, _SireWrappers from .._Exceptions import StreamError as _StreamError - from .. import _isVerbose - from sire import system as _NewSireSystem - from .. import _SireWrappers - import os as _os # Validate input. @@ -151,9 +152,10 @@ def getMetadata(file): The metadata associated with the file. If none is present, then an empty dictionary will be returned. """ - from sire import stream as _NewSireStream import os as _os + from sire import stream as _NewSireStream + if not _os.path.isfile(file): raise ValueError(f"Unable to locate stream file: {file}") @@ -182,9 +184,10 @@ def getSireMetadata(file): The Sire metadata associated with the file. If none is present, then an empty dictionary will be returned. """ - from sire import stream as _NewSireStream import os as _os + from sire import stream as _NewSireStream + if not _os.path.isfile(file): raise ValueError(f"Unable to locate stream file: {file}") @@ -242,6 +245,7 @@ def _add_metadata(sire_object): The metadata associated with the object. """ from sire import stream as _NewSireStream + from .. import _SireWrappers from .._SireWrappers._sire_wrapper import SireWrapper as _SireWrapper @@ -252,9 +256,10 @@ def _add_metadata(sire_object): "'sire_object' must be of type 'BioSimSpace._SireWrappers.SireWrapper'." ) - from sire import __version__ as _sire_version from sire import __revisionid__ as _sire_revisionid - from .. import _version + from sire import __version__ as _sire_version + + from .._version import __version__ as _bss_full_version # Work out the name of the Sandpit. try: @@ -263,10 +268,10 @@ def _add_metadata(sire_object): sandpit = "None" # Extract the BioSimSpace version and revision ID. - _bss_version = _version.get_versions()["version"].split("+")[0] - _bss_revisionid = _version.get_versions()["full-revisionid"] - if _bss_revisionid is not None: - _bss_revisionid = _bss_revisionid[0:7] + _bss_version = _bss_full_version.split("+")[0] + # Extract revision from version string (e.g., "1.0+5.gabcdef" -> "abcdef") + if "+" in _bss_full_version and ".g" in _bss_full_version: + _bss_revisionid = _bss_full_version.split(".g")[-1].split(".")[0] else: _bss_revisionid = "None" diff --git a/python/BioSimSpace/Trajectory/__init__.py b/src/BioSimSpace/Trajectory/__init__.py similarity index 100% rename from python/BioSimSpace/Trajectory/__init__.py rename to src/BioSimSpace/Trajectory/__init__.py diff --git a/python/BioSimSpace/Trajectory/_trajectory.py b/src/BioSimSpace/Trajectory/_trajectory.py similarity index 99% rename from python/BioSimSpace/Trajectory/_trajectory.py rename to src/BioSimSpace/Trajectory/_trajectory.py index 5366ff509..535dc986d 100644 --- a/python/BioSimSpace/Trajectory/_trajectory.py +++ b/src/BioSimSpace/Trajectory/_trajectory.py @@ -81,16 +81,17 @@ def getFrame(trajectory, topology, index, system=None, property_map={}): frame : :class:`System ` The System object of the corresponding frame. """ - from .. import _isVerbose import os as _os - from sire._load import _resolve_path + import uuid as _uuid import warnings as _warnings + from sire import load as _sire_load + from sire._load import _resolve_path from sire.legacy import IO as _SireIO - import uuid as _uuid from sire.legacy import Mol as _SireMol + + from .. import _isVerbose, _Utils from .._SireWrappers import System as _System - from .. import _Utils if not isinstance(trajectory, str): raise TypeError("'trajectory' must be of type 'str'") @@ -98,7 +99,7 @@ def getFrame(trajectory, topology, index, system=None, property_map={}): if not isinstance(topology, str): raise TypeError("'topology' must be of type 'str'") - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'") if not isinstance(property_map, dict): @@ -362,13 +363,15 @@ def __init__( own naming scheme, e.g. { "charge" : "my-charge" } """ import os as _os - from sire._load import _resolve_path - from ..Process._process import Process as _Process import warnings as _warnings + + from sire._load import _resolve_path from sire.legacy import IO as _SireIO from sire.legacy import Mol as _SireMol - from .._SireWrappers import System as _System + from .. import _Utils + from .._SireWrappers import System as _System + from ..Process import _process # Set default member variables. self._process = None @@ -388,7 +391,7 @@ def __init__( ) # Both use cases active. Default to process. - if not process is None and not trajectory is None: + if process is not None and trajectory is not None: _warnings.warn( "Both a process and trajectory file are specified! Defaulting to 'process'." ) @@ -396,7 +399,7 @@ def __init__( # BioSimSpace process. if process is not None: - if isinstance(process, _Process): + if isinstance(process, _process.Process): self._process = process process_name = process.__class__.__name__ # Check that the process can generate a trajectory. @@ -537,13 +540,15 @@ def getTrajectory(self, format="auto"): trajectory : mdtraj.core.trajectory.Trajectory, MDAnalysis.core.universe.Universe The trajectory in MDTraj or MDAnalysis format. """ - import shutil as _shutil import copy as _copy import os as _os - from .._Exceptions import IncompatibleError as _IncompatibleError + import shutil as _shutil + import uuid as _uuid import warnings as _warnings + from sire import load as _sire_load - import uuid as _uuid + + from .._Exceptions import IncompatibleError as _IncompatibleError if not isinstance(format, str): raise TypeError("'format' must be of type 'str'") @@ -685,14 +690,16 @@ def getFrames(self, indices=None): frames : [:class:`System `] The list of System objects. """ - from .. import _isVerbose - from ..Types import Time as _Time import os as _os - from .._Exceptions import IncompatibleError as _IncompatibleError + import uuid as _uuid import warnings as _warnings + from sire.legacy import IO as _SireIO - import uuid as _uuid + + from .. import _isVerbose + from .._Exceptions import IncompatibleError as _IncompatibleError from .._SireWrappers import System as _System + from ..Types import Time as _Time # The process is running. Grab the latest trajectory. if self._process is not None and self._process.isRunning(): @@ -1012,7 +1019,7 @@ def rmsd(self, frame=None, atoms=None): if frame is None: frame = 0 else: - if not type(frame) is int: + if type(frame) is not int: raise TypeError("'frame' must be of type 'int'") else: # Store the number of frames. @@ -1132,14 +1139,16 @@ def _split_molecules(frame, pdb, reference, work_dir, property_map={}): is_squashed : bool Whether the passed frame was squashed. """ - from sire.legacy import Vol as _SireVol - from ..Align._squash import _squash, _unsquash - from .. import _isVerbose import os as _os - from sire.legacy import Units as _SireUnits - from sire.legacy import IO as _SireIO import uuid as _uuid + + from sire.legacy import IO as _SireIO + from sire.legacy import Units as _SireUnits + from sire.legacy import Vol as _SireVol + + from .. import _isVerbose from .._SireWrappers import System as _System + from ..Align._squash import _squash, _unsquash if not isinstance(frame, (_SireIO.AmberRst7, _SireIO.Gro87)): raise TypeError( @@ -1354,10 +1363,12 @@ def _update_water_topology(system, topology, trajectory, property_map): system : :class:`System ` The passed system with updated water topology. """ - from .._SireWrappers import System as _System - from sire.legacy import IO as _SireIO import os as _os + from sire.legacy import IO as _SireIO + + from .._SireWrappers import System as _System + if not isinstance(system, _System): raise TypeError("'system' must be of type 'BioSimSpace._SireWrappers.System'") diff --git a/python/BioSimSpace/Types/__init__.py b/src/BioSimSpace/Types/__init__.py similarity index 100% rename from python/BioSimSpace/Types/__init__.py rename to src/BioSimSpace/Types/__init__.py index 19f34e385..c1412dd0e 100644 --- a/python/BioSimSpace/Types/__init__.py +++ b/src/BioSimSpace/Types/__init__.py @@ -52,6 +52,10 @@ from ._charge import * from ._coordinate import * from ._energy import * + +# Hide GeneralUnit since it will be automatically created from combinations +# of the unit based types above. +from ._general_unit import GeneralUnit as _GeneralUnit from ._length import * from ._mass import * from ._pressure import * @@ -59,7 +63,3 @@ from ._time import * from ._vector import * from ._volume import * - -# Hide GeneralUnit since it will be automatically created from combinations -# of the unit based types above. -from ._general_unit import GeneralUnit as _GeneralUnit diff --git a/python/BioSimSpace/Types/_angle.py b/src/BioSimSpace/Types/_angle.py similarity index 100% rename from python/BioSimSpace/Types/_angle.py rename to src/BioSimSpace/Types/_angle.py diff --git a/python/BioSimSpace/Types/_area.py b/src/BioSimSpace/Types/_area.py similarity index 100% rename from python/BioSimSpace/Types/_area.py rename to src/BioSimSpace/Types/_area.py diff --git a/python/BioSimSpace/Types/_base_units.py b/src/BioSimSpace/Types/_base_units.py similarity index 100% rename from python/BioSimSpace/Types/_base_units.py rename to src/BioSimSpace/Types/_base_units.py index 990417caa..29cdb8ce9 100644 --- a/python/BioSimSpace/Types/_base_units.py +++ b/src/BioSimSpace/Types/_base_units.py @@ -34,8 +34,8 @@ from ._pressure import * from ._temperature import * from ._time import * -from ._volume import * from ._type import Type as _Type +from ._volume import * _namespace = _sys.modules[__name__] diff --git a/python/BioSimSpace/Types/_charge.py b/src/BioSimSpace/Types/_charge.py similarity index 100% rename from python/BioSimSpace/Types/_charge.py rename to src/BioSimSpace/Types/_charge.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_coordinate.py b/src/BioSimSpace/Types/_coordinate.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_coordinate.py rename to src/BioSimSpace/Types/_coordinate.py index 3d73b4e98..2ab03f4fb 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_coordinate.py +++ b/src/BioSimSpace/Types/_coordinate.py @@ -46,8 +46,8 @@ def __init__(self, x, y, z): z : :class: `Length ` The z position. """ - from ._vector import Vector as _Vector from ._length import Length as _Length + from ._vector import Vector as _Vector if not isinstance(x, _Length): raise TypeError("'x' must be of type 'BioSimSpace.Types.Length'") @@ -95,8 +95,8 @@ def __add__(self, other): result : :class: `Coordinate ` The sum of the two coordinates. """ - from ._vector import Vector as _Vector from ._length import Length as _Length + from ._vector import Vector as _Vector if isinstance(other, Coordinate): return self.fromVector(self._vector + other._vector, _Length(1, "A")) @@ -132,8 +132,8 @@ def __sub__(self, other): result : :class: `Coordinate ` The difference of the two coordinates. """ - from ._vector import Vector as _Vector from ._length import Length as _Length + from ._vector import Vector as _Vector if isinstance(other, Coordinate): return self.fromVector(self._vector - other._vector, _Length(1, "A")) @@ -262,8 +262,8 @@ def fromVector(vector, unit): unit : :class: `Length ` The coordinate unit. """ - from ._vector import Vector as _Vector from ._length import Length as _Length + from ._vector import Vector as _Vector if not isinstance(vector, _Vector): raise TypeError("'vector' must be of type 'BioSimSpace.Types.Vector'") diff --git a/python/BioSimSpace/Types/_energy.py b/src/BioSimSpace/Types/_energy.py similarity index 100% rename from python/BioSimSpace/Types/_energy.py rename to src/BioSimSpace/Types/_energy.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py b/src/BioSimSpace/Types/_general_unit.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py rename to src/BioSimSpace/Types/_general_unit.py index 07ad85c8b..3af0aa4a7 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py +++ b/src/BioSimSpace/Types/_general_unit.py @@ -813,7 +813,7 @@ def _from_string(cls, string): # Create and return a new object. return GeneralUnit(general_unit) - except Exception as e: + except Exception: raise ValueError( f"Could not infer GeneralUnit from string '{string}'" ) from None diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_length.py b/src/BioSimSpace/Types/_length.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_length.py rename to src/BioSimSpace/Types/_length.py index 151a55225..021512e30 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_length.py +++ b/src/BioSimSpace/Types/_length.py @@ -135,8 +135,8 @@ def __init__(self, *args): def __mul__(self, other): """Multiplication operator.""" - from ._volume import Volume as _Volume from ._area import Area as _Area + from ._volume import Volume as _Volume # Handle containers by converting each item in the container to # this type. diff --git a/python/BioSimSpace/Types/_mass.py b/src/BioSimSpace/Types/_mass.py similarity index 100% rename from python/BioSimSpace/Types/_mass.py rename to src/BioSimSpace/Types/_mass.py diff --git a/python/BioSimSpace/Types/_pressure.py b/src/BioSimSpace/Types/_pressure.py similarity index 100% rename from python/BioSimSpace/Types/_pressure.py rename to src/BioSimSpace/Types/_pressure.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py b/src/BioSimSpace/Types/_temperature.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py rename to src/BioSimSpace/Types/_temperature.py index a33dd6eaa..77356b718 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_temperature.py +++ b/src/BioSimSpace/Types/_temperature.py @@ -410,7 +410,7 @@ def _validate_unit(cls, unit): elif unit in cls._abbreviations: return cls._abbreviations[unit] elif len(unit) == 0: - raise ValueError(f"Unit is not given. You must supply the unit.") + raise ValueError("Unit is not given. You must supply the unit.") else: raise ValueError( "Unsupported unit '%s'. Supported units are: '%s'" diff --git a/python/BioSimSpace/Types/_time.py b/src/BioSimSpace/Types/_time.py similarity index 100% rename from python/BioSimSpace/Types/_time.py rename to src/BioSimSpace/Types/_time.py diff --git a/python/BioSimSpace/Types/_type.py b/src/BioSimSpace/Types/_type.py similarity index 100% rename from python/BioSimSpace/Types/_type.py rename to src/BioSimSpace/Types/_type.py diff --git a/python/BioSimSpace/Types/_vector.py b/src/BioSimSpace/Types/_vector.py similarity index 100% rename from python/BioSimSpace/Types/_vector.py rename to src/BioSimSpace/Types/_vector.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_volume.py b/src/BioSimSpace/Types/_volume.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/Types/_volume.py rename to src/BioSimSpace/Types/_volume.py index be7b90c06..f3d2bde88 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_volume.py +++ b/src/BioSimSpace/Types/_volume.py @@ -121,8 +121,8 @@ def __init__(self, *args): def __truediv__(self, other): """Division operator.""" - from ._length import Length as _Length from ._area import Area as _Area + from ._length import Length as _Length # Convert int to float. if type(other) is int: diff --git a/python/BioSimSpace/Units/Angle/__init__.py b/src/BioSimSpace/Units/Angle/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Angle/__init__.py rename to src/BioSimSpace/Units/Angle/__init__.py diff --git a/python/BioSimSpace/Units/Area/__init__.py b/src/BioSimSpace/Units/Area/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Area/__init__.py rename to src/BioSimSpace/Units/Area/__init__.py diff --git a/python/BioSimSpace/Units/Charge/__init__.py b/src/BioSimSpace/Units/Charge/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Charge/__init__.py rename to src/BioSimSpace/Units/Charge/__init__.py diff --git a/python/BioSimSpace/Units/Energy/__init__.py b/src/BioSimSpace/Units/Energy/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Energy/__init__.py rename to src/BioSimSpace/Units/Energy/__init__.py diff --git a/python/BioSimSpace/Units/Length/__init__.py b/src/BioSimSpace/Units/Length/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Length/__init__.py rename to src/BioSimSpace/Units/Length/__init__.py diff --git a/python/BioSimSpace/Units/Mass/__init__.py b/src/BioSimSpace/Units/Mass/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Mass/__init__.py rename to src/BioSimSpace/Units/Mass/__init__.py diff --git a/python/BioSimSpace/Units/Pressure/__init__.py b/src/BioSimSpace/Units/Pressure/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Pressure/__init__.py rename to src/BioSimSpace/Units/Pressure/__init__.py diff --git a/python/BioSimSpace/Units/Temperature/__init__.py b/src/BioSimSpace/Units/Temperature/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Temperature/__init__.py rename to src/BioSimSpace/Units/Temperature/__init__.py diff --git a/python/BioSimSpace/Units/Time/__init__.py b/src/BioSimSpace/Units/Time/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Time/__init__.py rename to src/BioSimSpace/Units/Time/__init__.py diff --git a/python/BioSimSpace/Units/Volume/__init__.py b/src/BioSimSpace/Units/Volume/__init__.py similarity index 100% rename from python/BioSimSpace/Units/Volume/__init__.py rename to src/BioSimSpace/Units/Volume/__init__.py diff --git a/python/BioSimSpace/Units/__init__.py b/src/BioSimSpace/Units/__init__.py similarity index 92% rename from python/BioSimSpace/Units/__init__.py rename to src/BioSimSpace/Units/__init__.py index 691f52307..7ebeabc95 100644 --- a/python/BioSimSpace/Units/__init__.py +++ b/src/BioSimSpace/Units/__init__.py @@ -137,16 +137,18 @@ _sr.use_new_api() del _sr -from . import Angle -from . import Area -from . import Charge -from . import Energy -from . import Length -from . import Mass -from . import Pressure -from . import Temperature -from . import Time -from . import Volume +from . import ( + Angle, + Area, + Charge, + Energy, + Length, + Mass, + Pressure, + Temperature, + Time, + Volume, +) # Whether to allow operations between offset units, see here for details: # http://pint.readthedocs.io/en/latest/nonmult.html diff --git a/python/BioSimSpace/_Config/__init__.py b/src/BioSimSpace/_Config/__init__.py similarity index 100% rename from python/BioSimSpace/_Config/__init__.py rename to src/BioSimSpace/_Config/__init__.py diff --git a/python/BioSimSpace/_Config/_amber.py b/src/BioSimSpace/_Config/_amber.py similarity index 99% rename from python/BioSimSpace/_Config/_amber.py rename to src/BioSimSpace/_Config/_amber.py index ffb321694..846de73e0 100644 --- a/python/BioSimSpace/_Config/_amber.py +++ b/src/BioSimSpace/_Config/_amber.py @@ -92,13 +92,15 @@ def createConfig( config : [str] The list of AMBER format configuration strings. """ - from ..Protocol._position_restraint_mixin import _PositionRestraintMixin - from .. import Protocol as _Protocol - from sire.legacy import Units as _SireUnits - from ..Protocol._free_energy_mixin import _FreeEnergyMixin import math as _math import warnings as _warnings + + from sire.legacy import Units as _SireUnits + + from .. import Protocol as _Protocol from ..Align._squash import _squashed_atom_mapping + from ..Protocol._free_energy_mixin import _FreeEnergyMixin + from ..Protocol._position_restraint_mixin import _PositionRestraintMixin # Validate input. diff --git a/python/BioSimSpace/_Config/_config.py b/src/BioSimSpace/_Config/_config.py similarity index 99% rename from python/BioSimSpace/_Config/_config.py rename to src/BioSimSpace/_Config/_config.py index d2b096223..5e312089c 100644 --- a/python/BioSimSpace/_Config/_config.py +++ b/src/BioSimSpace/_Config/_config.py @@ -95,9 +95,10 @@ def hasBox(system, property_map={}): has_box : bool Whether the system has a simulation box. """ - from .._SireWrappers import System as _System import warnings as _warnings + from .._SireWrappers import System as _System + if not isinstance(system, _System): raise TypeError( "'system' must be of type 'BioSimSpace._SireWrappers.System'" @@ -212,6 +213,7 @@ def steps(self): The number of integration steps. """ import math as _math + from .. import Protocol as _Protocol if isinstance(self._protocol, _Protocol.Minimisation): diff --git a/python/BioSimSpace/_Config/_gromacs.py b/src/BioSimSpace/_Config/_gromacs.py similarity index 99% rename from python/BioSimSpace/_Config/_gromacs.py rename to src/BioSimSpace/_Config/_gromacs.py index e158e5fb1..8728f3af7 100644 --- a/python/BioSimSpace/_Config/_gromacs.py +++ b/src/BioSimSpace/_Config/_gromacs.py @@ -75,10 +75,11 @@ def createConfig(self, version=None, extra_options={}, extra_lines=[]): config : [str] The list of AMBER format configuration strings. """ - import warnings as _warnings import math as _math - from ..Protocol._free_energy_mixin import _FreeEnergyMixin + import warnings as _warnings + from .. import Protocol as _Protocol + from ..Protocol._free_energy_mixin import _FreeEnergyMixin from ..Protocol._position_restraint_mixin import _PositionRestraintMixin # Validate input. diff --git a/python/BioSimSpace/_Config/_somd.py b/src/BioSimSpace/_Config/_somd.py similarity index 99% rename from python/BioSimSpace/_Config/_somd.py rename to src/BioSimSpace/_Config/_somd.py index 33d375546..b85118b3f 100644 --- a/python/BioSimSpace/_Config/_somd.py +++ b/src/BioSimSpace/_Config/_somd.py @@ -72,12 +72,13 @@ def createConfig(self, extra_options={}, extra_lines=[]): config : [str] The list of SOMD format configuration strings. """ - from ..Protocol._free_energy_mixin import _FreeEnergyMixin import math as _math - from ..Protocol._position_restraint_mixin import _PositionRestraintMixin - from .. import Protocol as _Protocol import warnings as _warnings + + from .. import Protocol as _Protocol from .._Exceptions import IncompatibleError as _IncompatibleError + from ..Protocol._free_energy_mixin import _FreeEnergyMixin + from ..Protocol._position_restraint_mixin import _PositionRestraintMixin # Validate input. diff --git a/python/BioSimSpace/_Exceptions/__init__.py b/src/BioSimSpace/_Exceptions/__init__.py similarity index 100% rename from python/BioSimSpace/_Exceptions/__init__.py rename to src/BioSimSpace/_Exceptions/__init__.py diff --git a/python/BioSimSpace/_Exceptions/_exceptions.py b/src/BioSimSpace/_Exceptions/_exceptions.py similarity index 100% rename from python/BioSimSpace/_Exceptions/_exceptions.py rename to src/BioSimSpace/_Exceptions/_exceptions.py diff --git a/python/BioSimSpace/_SireWrappers/__init__.py b/src/BioSimSpace/_SireWrappers/__init__.py similarity index 100% rename from python/BioSimSpace/_SireWrappers/__init__.py rename to src/BioSimSpace/_SireWrappers/__init__.py index 6a9f76699..6b84c5297 100644 --- a/python/BioSimSpace/_SireWrappers/__init__.py +++ b/src/BioSimSpace/_SireWrappers/__init__.py @@ -47,7 +47,7 @@ from ._bond import * from ._molecule import * from ._molecules import * +from ._replica_system import * from ._residue import * from ._search_result import * from ._system import * -from ._replica_system import * diff --git a/python/BioSimSpace/_SireWrappers/_atom.py b/src/BioSimSpace/_SireWrappers/_atom.py similarity index 100% rename from python/BioSimSpace/_SireWrappers/_atom.py rename to src/BioSimSpace/_SireWrappers/_atom.py index 9223ca287..a9a1b7567 100644 --- a/python/BioSimSpace/_SireWrappers/_atom.py +++ b/src/BioSimSpace/_SireWrappers/_atom.py @@ -49,7 +49,6 @@ def __init__(self, atom): from sire.legacy import Mol as _SireMol # Check that the atom is valid. - # A Sire Atom object. if isinstance(atom, _SireMol._Mol.Atom): sire_object = atom @@ -196,9 +195,10 @@ def toMolecule(self): system : :class:`Molecule ` """ - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule + return _Molecule( _SireMol.PartialMolecule(self._sire_object).extract().molecule() ) diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py b/src/BioSimSpace/_SireWrappers/_bond.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py rename to src/BioSimSpace/_SireWrappers/_bond.py index 4930a622e..c30efa810 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_bond.py +++ b/src/BioSimSpace/_SireWrappers/_bond.py @@ -49,7 +49,6 @@ def __init__(self, bond): from sire.legacy import MM as _SireMM # Check that the bond is valid. - # A Sire Bond object. if isinstance(bond, _SireMM._MM.Bond): sire_object = bond @@ -323,9 +322,10 @@ def toMolecule(self): system : :class:`Molecule ` """ - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule + return _Molecule( _SireMol.PartialMolecule(self._sire_object).extract().molecule() ) @@ -362,8 +362,9 @@ def search(self, query, property_map={}): >>> result = bond.search("atomidx 23") """ - from .. import _isVerbose from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): diff --git a/python/BioSimSpace/_SireWrappers/_molecule.py b/src/BioSimSpace/_SireWrappers/_molecule.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_molecule.py rename to src/BioSimSpace/_SireWrappers/_molecule.py index e74738ad5..75880eddb 100644 --- a/python/BioSimSpace/_SireWrappers/_molecule.py +++ b/src/BioSimSpace/_SireWrappers/_molecule.py @@ -117,8 +117,8 @@ def __repr__(self): def __add__(self, other): """Addition operator.""" - from ._system import System as _System from ._molecules import Molecules as _Molecules + from ._system import System as _System # Convert tuple to a list. if isinstance(other, tuple): @@ -229,8 +229,8 @@ def coordinates(self, property_map={}): [coordinates] : [class:`Coordinate `] The coordinates of the atoms in the molecule. """ - from ..Types import Length as _Length from ..Types import Coordinate as _Coordinate + from ..Types import Length as _Length prop = property_map.get("coordinates", "coordinates") @@ -311,14 +311,14 @@ def extract(self, indices, renumber=False, property_map={}): molecule : :class:`Molecule ` The extracted molecule. """ - from .. import _isVerbose - from sire.legacy import Mol as _SireMol from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from .._Exceptions import IncompatibleError as _IncompatibleError # TODO: This method is slow for large molecules. Re-write in pure C++ # and provide a suitable wrapper function. - # Convert tuple to list. if isinstance(indices, tuple): indices = list(indices) @@ -334,7 +334,7 @@ def extract(self, indices, renumber=False, property_map={}): for x in indices: # Check type. - if not type(x) is int: + if type(x) is not int: raise TypeError("'indices' must be a list of 'int' types.") # Map index back to range. @@ -631,8 +631,9 @@ def search(self, query, property_map={}): >>> result = molecule.search("atomidx 23") """ - from .. import _isVerbose from sire.legacy import Mol as _SireMol + + from .. import _isVerbose from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): @@ -698,13 +699,14 @@ def makeCompatibleWith( verbose : bool Whether to report status updates to stdout. """ + from sire.legacy import IO as _SireIO from sire.legacy import MM as _SireMM - from .._Exceptions import IncompatibleError as _IncompatibleError from sire.legacy import Base as _SireBase - from sire.legacy import IO as _SireIO + from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem + from .. import _isVerbose - from sire.legacy import Mol as _SireMol + from .._Exceptions import IncompatibleError as _IncompatibleError from ._system import System as _System # Validate input. @@ -811,10 +813,10 @@ def makeCompatibleWith( # See if any of the new properties are in the map, add them if not. for prop in props0: - if not prop in _property_map: + if prop not in _property_map: _property_map[prop] = prop for prop in props1: - if not prop in _property_map: + if prop not in _property_map: _property_map[prop] = prop # Make the molecule editable. @@ -1353,9 +1355,10 @@ def translate(self, vector, property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from ..Types import Length as _Length from sire.legacy import Maths as _SireMaths + from ..Types import Length as _Length + # Convert tuple to a list. if isinstance(vector, tuple): vector = list(vector) @@ -1456,8 +1459,8 @@ def repartitionHydrogenMass( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Base as _SireBase from sire.legacy import IO as _SireIO + from sire.legacy import Base as _SireBase # Convert int to float. if type(factor) is int: @@ -1589,9 +1592,11 @@ def _fixCharge(self, property_map={}): user defined values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ + from math import isclose as _isclose + from sire.legacy import Units as _SireUnits + from .._Exceptions import IncompatibleError as _IncompatibleError - from math import isclose as _isclose # Get the user defined charge property. prop = property_map.get("charge", "charge") @@ -1668,10 +1673,11 @@ def _toRegularMolecule( molecule : BioSimSpace._SireWrappers.Molecule The molecule at the chosen end state. """ - from sire.legacy import Mol as _SireMol + from sire.legacy import IO as _SireIO from sire.legacy import Base as _SireBase + from sire.legacy import Mol as _SireMol + from ._system import System as _System - from sire.legacy import IO as _SireIO if not isinstance(is_lambda1, bool): raise TypeError("'is_lambda1' must be of type 'bool'") diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py b/src/BioSimSpace/_SireWrappers/_molecules.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py rename to src/BioSimSpace/_SireWrappers/_molecules.py index f7907a8c3..2ce4bc8a7 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_molecules.py +++ b/src/BioSimSpace/_SireWrappers/_molecules.py @@ -49,13 +49,13 @@ def __init__(self, molecules): A Sire Molecues object, a Sire or BioSimSpace System object, or a list of BioSimSpace Molecule objects. """ + from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem + from ._molecule import Molecule as _Molecule from ._system import System as _System - from sire.legacy import Mol as _SireMol # Check that the molecules argument is valid. - # Convert tuple to list. if isinstance(molecules, tuple): molecules = list(molecules) @@ -181,9 +181,10 @@ def __add__(self, other): def __getitem__(self, key): """Get a molecule from the container.""" - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule + # Slice. if isinstance(key, slice): # Create a list to hold the molecules. @@ -399,8 +400,8 @@ def search(self, query): >>> result = molecule.search("atomidx 23") """ - from ._search_result import SearchResult as _SearchResult from .. import _isVerbose + from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): raise TypeError("'query' must be of type 'str'") diff --git a/python/BioSimSpace/_SireWrappers/_replica_system.py b/src/BioSimSpace/_SireWrappers/_replica_system.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_replica_system.py rename to src/BioSimSpace/_SireWrappers/_replica_system.py index c42a0a414..780b3d173 100644 --- a/python/BioSimSpace/_SireWrappers/_replica_system.py +++ b/src/BioSimSpace/_SireWrappers/_replica_system.py @@ -65,9 +65,10 @@ def __init__( format. """ + from sire.legacy.System import System as _SireSystem from sire.mol._trajectory import TrajectoryIterator as _TrajectoryIterator from sire.system import System as _NewSireSystem - from sire.legacy.System import System as _SireSystem + from ._system import System as _System # Check that the system is valid. @@ -136,6 +137,7 @@ def __init__( if not is_traj_iterator: import os as _os from tempfile import NamedTemporaryFile as _NamedTemporaryFile + from .. import _isVerbose if not _os.path.isfile(trajectory): @@ -218,8 +220,10 @@ def __init__( import os as _os from tempfile import TemporaryDirectory as _TemporaryDirectory + from sire import load as _load from sire import save as _save + from .. import _isVerbose with _TemporaryDirectory() as tmp_dir: @@ -227,7 +231,7 @@ def __init__( # Write out the current coordinates the specified number of times. try: # Write the first file only. - tmp_file = _os.path.join(tmp_dir, f"replica_0000.gro") + tmp_file = _os.path.join(tmp_dir, "replica_0000.gro") if self._is_perturbable and self._is_squashed: _save( _NewSireSystem(self._squashed_system), tmp_file, silent=True @@ -239,7 +243,7 @@ def __init__( # Copy the first file for the remaining replicas. for i in range(1, num_replicas): tmp_file = _os.path.join(tmp_dir, f"replica_{i:04d}.gro") - _os.link(_os.path.join(tmp_dir, f"replica_0000.gro"), tmp_file) + _os.link(_os.path.join(tmp_dir, "replica_0000.gro"), tmp_file) filenames.append(tmp_file) except Exception as e: msg = "Failed to write temporary files for replica duplication." @@ -364,6 +368,7 @@ def save(self, filename, save_velocities=False): from sire import save as _save from sire.stream import save as _save_stream + from .. import _isVerbose if not isinstance(filename, str): @@ -437,6 +442,7 @@ def load(stream, trajectory): """ from sire.stream import load as _load + from .. import _isVerbose if not isinstance(stream, str): @@ -482,9 +488,10 @@ def getReplica(self, index, is_lambda1=False, property_map={}): The requested replica as a BioSimSpace System object. """ - from ._system import System as _System from sire.morph import link_to_perturbed as _link_to_perturbed + from ._system import System as _System + if not isinstance(index, int): raise TypeError("'index' must be an integer.") @@ -555,6 +562,7 @@ def saveReplicas(self, filenames, save_velocities=False, is_lambda1=False): """ from sire import save as _save + from .. import _isVerbose if not isinstance(filenames, list): @@ -638,8 +646,10 @@ def loadReplicas(replica_system, filenames): import os as _os from tempfile import NamedTemporaryFile as _NamedTemporaryFile + from sire import load as _load from sire import save as _save + from .. import _isVerbose if not isinstance(replica_system, ReplicaSystem): diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py b/src/BioSimSpace/_SireWrappers/_residue.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py rename to src/BioSimSpace/_SireWrappers/_residue.py index 073a778e1..f4c4b0bef 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_residue.py +++ b/src/BioSimSpace/_SireWrappers/_residue.py @@ -49,7 +49,6 @@ def __init__(self, residue): from sire.legacy import Mol as _SireMol # Check that the residue is valid. - # A Sire Residue object. if isinstance(residue, _SireMol._Mol.Residue): sire_object = residue @@ -276,9 +275,10 @@ def toMolecule(self): system : :class:`Molecule ` """ - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule + return _Molecule( _SireMol.PartialMolecule(self._sire_object).extract().molecule() ) @@ -315,9 +315,10 @@ def search(self, query, property_map={}): >>> result = residue.search("atomidx 23") """ + from sire.legacy import Mol as _SireMol + from .. import _isVerbose from ._search_result import SearchResult as _SearchResult - from sire.legacy import Mol as _SireMol if not isinstance(query, str): raise TypeError("'query' must be of type 'str'") diff --git a/python/BioSimSpace/_SireWrappers/_search_result.py b/src/BioSimSpace/_SireWrappers/_search_result.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_search_result.py rename to src/BioSimSpace/_SireWrappers/_search_result.py index ccf2f1656..98655bd75 100644 --- a/python/BioSimSpace/_SireWrappers/_search_result.py +++ b/src/BioSimSpace/_SireWrappers/_search_result.py @@ -102,11 +102,12 @@ def __hash__(self): def __getitem__(self, key): """Get a search result from the container.""" + import sire.legacy as _Sire + from ._atom import Atom as _Atom - from ._molecule import Molecule as _Molecule from ._bond import Bond as _Bond + from ._molecule import Molecule as _Molecule from ._residue import Residue as _Residue - import sire.legacy as _Sire # Slice. if type(key) is slice: diff --git a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py b/src/BioSimSpace/_SireWrappers/_sire_wrapper.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py rename to src/BioSimSpace/_SireWrappers/_sire_wrapper.py index 076863bd9..91175c5a7 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_SireWrappers/_sire_wrapper.py +++ b/src/BioSimSpace/_SireWrappers/_sire_wrapper.py @@ -171,10 +171,11 @@ def translate(self, vector, property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ + from sire.legacy import Maths as _SireMaths + from .. import _isVerbose - from ..Types import Length as _Length from .._Exceptions import IncompatibleError as _IncompatibleError - from sire.legacy import Maths as _SireMaths + from ..Types import Length as _Length # Convert tuple to a list. if isinstance(vector, tuple): @@ -290,9 +291,10 @@ def _getCenterOfMass(self, space=None, property_map={}): com: [:class:`Length `] The center of mass of the object. """ - from .. import Units as _Units from sire.legacy import Vol as _SireVol + from .. import Units as _Units + if space is None: space_prop = property_map.get("space", "space") try: @@ -313,7 +315,6 @@ def _getCenterOfMass(self, space=None, property_map={}): # Whether this is an atom, molecule or residue, or system. is_atom = False - is_mol_res = False is_system = False # Get the first atom in the object. @@ -323,7 +324,6 @@ def _getCenterOfMass(self, space=None, property_map={}): except: try: atom = self.getAtoms()[0] - is_mol_res = True except: atom = self is_atom = True @@ -447,9 +447,10 @@ def _getAABox(self, property_map={}): aabox : Sire.Vol.AABox The axis-aligned bounding box for the object. """ + from sire.legacy import Vol as _SireVol + from .. import _isVerbose from .._Exceptions import IncompatibleError as _IncompatibleError - from sire.legacy import Vol as _SireVol # Initialise the coordinates vector. coord = [] diff --git a/python/BioSimSpace/_SireWrappers/_system.py b/src/BioSimSpace/_SireWrappers/_system.py similarity index 99% rename from python/BioSimSpace/_SireWrappers/_system.py rename to src/BioSimSpace/_SireWrappers/_system.py index b6bc2102f..9c236e1ec 100644 --- a/python/BioSimSpace/_SireWrappers/_system.py +++ b/src/BioSimSpace/_SireWrappers/_system.py @@ -30,10 +30,9 @@ __all__ = ["System"] +from .. import Units as _Units from ..Types import Angle as _Angle from ..Types import Coordinate as _Coordinate -from .. import Units as _Units - from ._sire_wrapper import SireWrapper as _SireWrapper @@ -54,13 +53,13 @@ def __init__(self, system): A Sire or BioSimSpace System object, a Sire or BioSimSpace Molecule object, a BioSimSpace Molecules object, or a list of BioSimSpace molecule objects. """ - from ._molecule import Molecule as _Molecule from sire.legacy import Mol as _SireMol from sire.legacy import System as _SireSystem + + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules # Check that the system is valid. - # Convert tuple to a list. if isinstance(system, tuple): system = list(system) @@ -179,9 +178,9 @@ def __sub__(self, other): def __contains__(self, other): """Return whether other is in self.""" - from ._residue import Residue as _Residue - from ._molecule import Molecule as _Molecule from ._atom import Atom as _Atom + from ._molecule import Molecule as _Molecule + from ._residue import Residue as _Residue if not isinstance(other, (_Molecule, _Atom, _Residue)): raise TypeError( @@ -195,6 +194,7 @@ def __contains__(self, other): def __getitem__(self, key): """Get a molecule from the system.""" from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules @@ -273,6 +273,7 @@ def copy(self, renumber=False): A copy of the object. """ from sire.legacy import Mol as _SireMol + from ._molecules import Molecules as _Molecules if not isinstance(renumber, bool): @@ -529,7 +530,7 @@ def _object_compare(object0, object1): name0 = inv_prop_map0.get(p0, p0) # Skip if excluded. - if not name0 in _excluded_properties: + if name0 not in _excluded_properties: # Get the property name in other. name1 = property_map1.get(name0, name0) @@ -564,7 +565,7 @@ def _object_compare(object0, object1): for p1 in props1: name1 = inv_prop_map1.get(p1, p1) # This is a property unique to object1, so they differ. - if not name1 in _excluded_properties and name1 not in props0: + if name1 not in _excluded_properties and name1 not in props0: return False # If we get this far, then the objects are the same. @@ -606,15 +607,15 @@ def addMolecules(self, molecules): A Molecule, Molecules object, a list of Molecule objects, a System, or a SearchResult containing molecules. """ - from ._search_result import SearchResult as _SearchResult - from sire.legacy import IO as _SireIO import warnings as _warnings + + from sire.legacy import IO as _SireIO from sire.legacy import Mol as _SireMol + from sire.legacy.Mol import SelectorMol as _SelectorMol + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules - from ._search_result import SearchResult as _SearchResult - from sire.legacy.Mol import SelectorMol as _SelectorMol # Whether this is a selector mol object. is_selector_mol = False @@ -705,7 +706,7 @@ def addMolecules(self, molecules): # Search for molecules with a velocity property. try: mols_with_velocities = self.search( - f"mols with property velocity" + "mols with property velocity" ).molecules() num_vels = len(mols_with_velocities) except: @@ -762,6 +763,7 @@ def removeMolecules(self, molecules): A Molecule, Molecules object, or list of Molecule objects. """ from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule from ._molecules import Molecules as _Molecules @@ -835,9 +837,10 @@ def updateMolecule(self, index, molecule): molecule : :class:`Molecule ` The updated (or replacement) molecule. """ - from ._molecule import Molecule as _Molecule from sire.legacy import IO as _SireIO + from ._molecule import Molecule as _Molecule + if type(index) is not int: raise TypeError("'index' must be of type 'int'") @@ -884,9 +887,10 @@ def updateMolecules(self, molecules): [:class:`Molecule `] A Molecule, or list of Molecule objects. """ + from sire.legacy import IO as _SireIO from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule - from sire.legacy import IO as _SireIO # Convert tuple to a list. if isinstance(molecules, tuple): @@ -985,6 +989,7 @@ def getMolecules(self, group="all"): The list of molecules in the group. """ from sire.legacy import Mol as _SireMol + from ._molecules import Molecules as _Molecules if not isinstance(group, str): @@ -1030,7 +1035,7 @@ def getAtom(self, index): atom : :class:`Atom ` The atom at the specified index. """ - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Set the MolNum to atom index mapping. @@ -1086,7 +1091,7 @@ def getResidue(self, index): residue : :class:`Residue ` The residue at the specified index. """ - if not type(index) is int: + if type(index) is not int: raise TypeError("'index' must be of type 'int'.") # Set the MolNum to residue index mapping. @@ -1257,10 +1262,10 @@ def setCoordinates( values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from .. import _isVerbose + import numpy as _np from sire.legacy import IO as _SireIO - import numpy as _np + from .. import _isVerbose # Validate input. if not isinstance(coordinates, _np.ndarray): @@ -1607,8 +1612,9 @@ def search(self, query, property_map={}): >>> result = system.search("molidx 10 and atomidx 23") """ - from .. import _isVerbose from sire.mol import Select as _Select + + from .. import _isVerbose from ._search_result import SearchResult as _SearchResult if not isinstance(query, str): @@ -1653,9 +1659,9 @@ def getIndex(self, item): index : int, [int] The absolute index of the atom/residue/molecule in the system. """ - from ._residue import Residue as _Residue - from ._molecule import Molecule as _Molecule from ._atom import Atom as _Atom + from ._molecule import Molecule as _Molecule + from ._residue import Residue as _Residue # Convert single object to list. if not isinstance(item, (tuple, list)): @@ -1755,10 +1761,11 @@ def setBox(self, box, angles=3 * [_Angle(90, "degree")], property_map={}): values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } """ - from sire.legacy import Vol as _SireVol from sire.legacy import Maths as _SireMaths - from ..Types import Length as _Length from sire.legacy import Units as _SireUnits + from sire.legacy import Vol as _SireVol + + from ..Types import Length as _Length # Convert tuples to lists. if isinstance(box, tuple): @@ -1838,6 +1845,7 @@ def getBox(self, property_map={}): The box vector angles: yz, xz, and xy. """ from sire.legacy import Vol as _SireVol + from ..Types import Length as _Length if not isinstance(property_map, dict): @@ -2008,8 +2016,8 @@ def getRestraintAtoms( indices : [int] A list of the backbone atom indices. """ - from ._utils import _prot_res, _nucl_res, _ions from .._Exceptions import IncompatibleError as _IncompatibleError + from ._utils import _ions, _nucl_res, _prot_res if not isinstance(restraint, str): raise TypeError("'restraint' must be of type 'str'.") @@ -2022,7 +2030,7 @@ def getRestraintAtoms( if restraint not in allowed: raise ValueError(f"'restraint' must be one of: {allowed}") - if mol_index is not None and not type(mol_index) is int: + if mol_index is not None and type(mol_index) is not int: raise TypeError("'mol_index' must be of type 'int'.") if not isinstance(is_absolute, bool): @@ -2373,6 +2381,7 @@ def _getAABox(self, property_map={}): The axis-aligned bounding box for the molecule. """ from sire.legacy import Vol as _SireVol + from .. import _isVerbose from .._Exceptions import IncompatibleError as _IncompatibleError @@ -2426,6 +2435,7 @@ def _renumberMolecules(self, molecules, is_rebuild=False): The renumber list of molecule objects. """ from sire.legacy import Mol as _SireMol + from ._molecule import Molecule as _Molecule # Renumber everything. diff --git a/python/BioSimSpace/_SireWrappers/_utils.py b/src/BioSimSpace/_SireWrappers/_utils.py similarity index 100% rename from python/BioSimSpace/_SireWrappers/_utils.py rename to src/BioSimSpace/_SireWrappers/_utils.py diff --git a/python/BioSimSpace/_Utils/__init__.py b/src/BioSimSpace/_Utils/__init__.py similarity index 100% rename from python/BioSimSpace/_Utils/__init__.py rename to src/BioSimSpace/_Utils/__init__.py diff --git a/python/BioSimSpace/_Utils/_command_split.py b/src/BioSimSpace/_Utils/_command_split.py similarity index 100% rename from python/BioSimSpace/_Utils/_command_split.py rename to src/BioSimSpace/_Utils/_command_split.py diff --git a/python/BioSimSpace/_Utils/_contextmanagers.py b/src/BioSimSpace/_Utils/_contextmanagers.py similarity index 99% rename from python/BioSimSpace/_Utils/_contextmanagers.py rename to src/BioSimSpace/_Utils/_contextmanagers.py index 70c7b2fb0..29e2a894b 100644 --- a/python/BioSimSpace/_Utils/_contextmanagers.py +++ b/src/BioSimSpace/_Utils/_contextmanagers.py @@ -41,9 +41,10 @@ def cd(work_dir): work_dir : str The working directory for the context. """ - from ._workdir import WorkDir as _WorkDir import os as _os + from ._workdir import WorkDir as _WorkDir + # Validate the input. if not isinstance(work_dir, (str, _WorkDir)): raise TypeError( diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py b/src/BioSimSpace/_Utils/_module_stub.py similarity index 99% rename from python/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py rename to src/BioSimSpace/_Utils/_module_stub.py index d8522ffb3..e048eae7e 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_module_stub.py +++ b/src/BioSimSpace/_Utils/_module_stub.py @@ -121,7 +121,7 @@ def _try_import(name: str, install_command: str = None): try: m = importlib.import_module(name) - except Exception as e: + except Exception: m = _ModuleStub(name=name, install_command=install_command) _failed_modules[name] = m diff --git a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_workdir.py b/src/BioSimSpace/_Utils/_workdir.py similarity index 100% rename from python/BioSimSpace/Sandpit/Exscientia/_Utils/_workdir.py rename to src/BioSimSpace/_Utils/_workdir.py index e2fd7ec15..4c211bb16 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/_Utils/_workdir.py +++ b/src/BioSimSpace/_Utils/_workdir.py @@ -41,8 +41,8 @@ def __init__(self, work_dir=None): The working directory for the context. If None, then a temporary working directory will be created. """ - import tempfile as _tempfile import os as _os + import tempfile as _tempfile # Validate the input. if work_dir and not isinstance(work_dir, str): diff --git a/python/BioSimSpace/__init__.py b/src/BioSimSpace/__init__.py similarity index 92% rename from python/BioSimSpace/__init__.py rename to src/BioSimSpace/__init__.py index 57247600d..e82999159 100644 --- a/python/BioSimSpace/__init__.py +++ b/src/BioSimSpace/__init__.py @@ -134,9 +134,10 @@ def _isVerbose(): else: _amber_home = None +from os import path as _path + # Check to see if GROMACS is installed. from sire.legacy import Base as _SireBase -from os import path as _path # First, let the user tell us where to find GROMACS. This # assumes that gromacs is installed in $GROMACSHOME/bin/gmx. @@ -259,38 +260,35 @@ def _isVerbose(): Units = _lazy_import.lazy_module("BioSimSpace.Units") _SireWrappers = _lazy_import.lazy_module("BioSimSpace._SireWrappers") - from . import _Exceptions - from . import _Utils + from . import _Exceptions, _Utils del _lazy_import else: - from . import Align - from . import Box - from . import Convert - from . import FreeEnergy - from . import Gateway - from . import IO - from . import Metadynamics - from . import MD - from . import Node - from . import Notebook - from . import Parameters - from . import Process - from . import Protocol - from . import Solvent - from . import Stream - from . import Trajectory - from . import Types - from . import Units - - from . import _Exceptions - from . import _SireWrappers - from . import _Utils + from . import ( + IO, + MD, + Align, + Box, + Convert, + FreeEnergy, + Gateway, + Metadynamics, + Node, + Notebook, + Parameters, + Process, + Protocol, + Solvent, + Stream, + Trajectory, + Types, + Units, + _Exceptions, + _SireWrappers, + _Utils, + ) del _can_lazy_import del _environ -from . import _version - -__version__ = _version.get_versions()["version"] -del _version +from ._version import __version__ diff --git a/tests/Align/test_align.py b/tests/Align/test_align.py index ef8c29cb5..b154b5d6b 100644 --- a/tests/Align/test_align.py +++ b/tests/Align/test_align.py @@ -1,11 +1,11 @@ -import pytest import sys +import pytest from sire.legacy.MM import InternalFF, IntraCLJFF, IntraFF from sire.legacy.Mol import AtomIdx, Element, PartialMolecule -from tests.conftest import has_amber import BioSimSpace as BSS +from tests.conftest import has_amber # Store the tutorial URL. url = BSS.tutorialUrl() diff --git a/tests/Align/test_squash.py b/tests/Align/test_squash.py index ac829a2fc..66a2d9e5c 100644 --- a/tests/Align/test_squash.py +++ b/tests/Align/test_squash.py @@ -1,10 +1,9 @@ import os -import numpy as np import pickle -import pytest +import numpy as np +import pytest import sire - from sire.maths import Vector import BioSimSpace as BSS @@ -60,7 +59,7 @@ def dual_topology_system(): @pytest.fixture def perturbed_tripeptide(): - return pickle.load(open(f"tests/input/merged_tripeptide.pickle", "rb")) + return pickle.load(open("tests/input/merged_tripeptide.pickle", "rb")) @pytest.mark.skipif(has_amber is False, reason="Requires AMBER to be installed.") diff --git a/tests/Convert/test_convert.py b/tests/Convert/test_convert.py index 70ec99c0e..fdd191a45 100644 --- a/tests/Convert/test_convert.py +++ b/tests/Convert/test_convert.py @@ -1,8 +1,7 @@ -import BioSimSpace as BSS - +import pytest from sire.legacy import Mol as SireMol -import pytest +import BioSimSpace as BSS def test_system(system): @@ -98,6 +97,7 @@ def test_sdf_stereo(lig): import tempfile from rdkit import Chem + from tests.conftest import url # Load the molecule. diff --git a/tests/FreeEnergy/test_atm.py b/tests/FreeEnergy/test_atm.py index f2a9b0183..c68963fbb 100644 --- a/tests/FreeEnergy/test_atm.py +++ b/tests/FreeEnergy/test_atm.py @@ -1,17 +1,14 @@ -import math -import pytest -import requests -import tarfile -import tempfile import json -import pandas as pd import os +import tempfile + +import pandas as pd +import pytest import BioSimSpace as BSS def test_makeSystem(TEMOA_host, TEMOA_lig1, TEMOA_lig2): - atm_generator = BSS.FreeEnergy.ATMSetup( receptor=TEMOA_host, ligand_bound=TEMOA_lig1, ligand_free=TEMOA_lig2 ) diff --git a/tests/FreeEnergy/test_relative.py b/tests/FreeEnergy/test_relative.py index 112cbfffa..f3fccd873 100644 --- a/tests/FreeEnergy/test_relative.py +++ b/tests/FreeEnergy/test_relative.py @@ -1,12 +1,12 @@ import math -import pytest -import requests import tarfile import tempfile -import BioSimSpace as BSS +import pytest +import requests -from tests.conftest import url, has_alchemlyb, has_gromacs +import BioSimSpace as BSS +from tests.conftest import has_alchemlyb, has_gromacs, url @pytest.fixture(scope="module") diff --git a/tests/Gateway/test_node.py b/tests/Gateway/test_node.py index cc419baaf..38179aba1 100644 --- a/tests/Gateway/test_node.py +++ b/tests/Gateway/test_node.py @@ -1,8 +1,8 @@ -import pytest import subprocess -import shlex import sys +import pytest + import BioSimSpace as BSS # Store the name of the test script. diff --git a/tests/IO/test_file_cache.py b/tests/IO/test_file_cache.py index a431cfc03..0fa9035f9 100644 --- a/tests/IO/test_file_cache.py +++ b/tests/IO/test_file_cache.py @@ -1,10 +1,10 @@ import glob import os -import pytest import tempfile -import BioSimSpace as BSS +import pytest +import BioSimSpace as BSS from tests.conftest import has_amber, has_openff diff --git a/tests/IO/test_openff_gromacs.py b/tests/IO/test_openff_gromacs.py index 8a943a7ed..b556c430d 100644 --- a/tests/IO/test_openff_gromacs.py +++ b/tests/IO/test_openff_gromacs.py @@ -1,7 +1,6 @@ import pytest import BioSimSpace as BSS - from tests.conftest import has_amber, has_gromacs, has_openff diff --git a/tests/IO/test_perturbable.py b/tests/IO/test_perturbable.py index d33646a8e..a47da7568 100644 --- a/tests/IO/test_perturbable.py +++ b/tests/IO/test_perturbable.py @@ -1,7 +1,6 @@ import pytest import BioSimSpace as BSS - from tests.conftest import url diff --git a/tests/MD/test_md.py b/tests/MD/test_md.py index 019d2d522..d1f158cb9 100644 --- a/tests/MD/test_md.py +++ b/tests/MD/test_md.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace as BSS - -from tests.conftest import url, has_amber, has_gromacs, has_namd +from tests.conftest import has_amber, has_gromacs, has_namd, url @pytest.mark.skipif(has_amber is False, reason="Requires AMBER to be installed.") diff --git a/tests/Metadynamics/test_metadynamics.py b/tests/Metadynamics/test_metadynamics.py index 78a234d6b..ebf35ad29 100644 --- a/tests/Metadynamics/test_metadynamics.py +++ b/tests/Metadynamics/test_metadynamics.py @@ -1,6 +1,7 @@ -import pytest import socket +import pytest + import BioSimSpace as BSS @@ -45,7 +46,6 @@ def test_metadynamics(system): reason="Local test requiring PLUMED patched GROMACS.", ) def test_steering(system): - # Create a reference containing the first and third molecule from the system. reference = (system[0] + system[2]).toSystem() diff --git a/tests/Parameters/test_parameters.py b/tests/Parameters/test_parameters.py index d969a0d8c..a744cda19 100644 --- a/tests/Parameters/test_parameters.py +++ b/tests/Parameters/test_parameters.py @@ -1,9 +1,9 @@ -import pytest import tempfile -import BioSimSpace as BSS +import pytest -from tests.conftest import url, has_openff, has_tleap, has_antechamber +import BioSimSpace as BSS +from tests.conftest import has_antechamber, has_openff, has_tleap, url @pytest.fixture(scope="session") @@ -169,7 +169,7 @@ def test_smiles_stereo(): assert rdmol0_smiles == rdmol1_smiles -# This test is currently skipped since it fails with AnteChamber verssion +# This test is currently skipped since it fails with AnteChamber version # 24.0 and above and there is no way to query the version number from # the command-line. (The version output has been removed.) @pytest.mark.skipif( @@ -210,6 +210,10 @@ def test_broken_sdf_formal_charge(): assert isclose(charge.value(), 0.0, abs_tol=1e-6) +@pytest.mark.skipif( + has_tleap is False, + reason="Requires AmberTools and tLEaP to be installed.", +) def test_ff19SB(): """ Test that the ff19SB force field can be used to parameterise a molecule. diff --git a/tests/Process/test_amber.py b/tests/Process/test_amber.py index 09f54b4a6..7ef851cf5 100644 --- a/tests/Process/test_amber.py +++ b/tests/Process/test_amber.py @@ -1,13 +1,12 @@ -from collections import OrderedDict - import math -import pytest import shutil import socket +from collections import OrderedDict -import BioSimSpace as BSS +import pytest -from tests.conftest import url, has_amber +import BioSimSpace as BSS +from tests.conftest import has_amber # Store the allowed restraints. restraints = BSS.Protocol._position_restraint_mixin._PositionRestraintMixin.restraints() diff --git a/tests/Process/test_gromacs.py b/tests/Process/test_gromacs.py index d81f8f14a..5a4b59daa 100644 --- a/tests/Process/test_gromacs.py +++ b/tests/Process/test_gromacs.py @@ -1,19 +1,16 @@ import math -import numpy as np import shutil + +import numpy as np import pytest import BioSimSpace as BSS - -from BioSimSpace.Units.Angle import radian -from BioSimSpace.Units.Energy import kcal_per_mol, kj_per_mol -from BioSimSpace.Units.Length import angstrom +from BioSimSpace.Units.Energy import kj_per_mol from BioSimSpace.Units.Pressure import bar from BioSimSpace.Units.Temperature import kelvin from BioSimSpace.Units.Time import picosecond from BioSimSpace.Units.Volume import nanometer3 - -from tests.conftest import url, has_amber, has_gromacs, has_openff +from tests.conftest import has_amber, has_gromacs, has_openff # Store the allowed restraints. restraints = BSS.Protocol._position_restraint_mixin._PositionRestraintMixin.restraints() diff --git a/tests/Process/test_namd.py b/tests/Process/test_namd.py index 5c2ab3aef..9226285f2 100644 --- a/tests/Process/test_namd.py +++ b/tests/Process/test_namd.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace as BSS - -from tests.conftest import url, has_namd +from tests.conftest import has_namd # Store the allowed restraints. restraints = BSS.Protocol._position_restraint_mixin._PositionRestraintMixin.restraints() @@ -14,8 +13,8 @@ def namd_system(): return BSS.IO.readMolecules( [ "tests/input/alanin.psf", - f"tests/input/alanin.pdb", - f"tests/input/alanin.params", + "tests/input/alanin.pdb", + "tests/input/alanin.params", ] ) diff --git a/tests/Process/test_openmm.py b/tests/Process/test_openmm.py index f67a78bbc..f57fd1852 100644 --- a/tests/Process/test_openmm.py +++ b/tests/Process/test_openmm.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace as BSS - -from tests.conftest import url, has_amber, has_gromacs, has_openff +from tests.conftest import has_amber, has_gromacs, has_openff, url # Store the allowed restraints. restraints = BSS.Protocol._position_restraint_mixin._PositionRestraintMixin.restraints() diff --git a/tests/Process/test_single_point_energy.py b/tests/Process/test_single_point_energy.py index d81405c60..99c6e501f 100644 --- a/tests/Process/test_single_point_energy.py +++ b/tests/Process/test_single_point_energy.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace as BSS - -from tests.conftest import url, has_amber, has_gromacs +from tests.conftest import has_amber, has_gromacs, url @pytest.fixture(scope="module") diff --git a/tests/Process/test_somd.py b/tests/Process/test_somd.py index 489680959..129f052a2 100644 --- a/tests/Process/test_somd.py +++ b/tests/Process/test_somd.py @@ -1,8 +1,9 @@ import filecmp import os -import pytest import warnings +import pytest + import BioSimSpace as BSS # Store the tutorial URL. diff --git a/tests/Protocol/test_atm.py b/tests/Protocol/test_atm.py index c2f066bc4..e61476709 100644 --- a/tests/Protocol/test_atm.py +++ b/tests/Protocol/test_atm.py @@ -1,4 +1,5 @@ import pytest + import BioSimSpace as BSS diff --git a/tests/Protocol/test_protocol.py b/tests/Protocol/test_protocol.py index 9c9963599..0fed3595b 100644 --- a/tests/Protocol/test_protocol.py +++ b/tests/Protocol/test_protocol.py @@ -1,5 +1,3 @@ -import pytest - import BioSimSpace as BSS # Unit tests for equivalence of protocol settings when instantiated diff --git a/tests/Sandpit/Exscientia/Align/test_alchemical_ion.py b/tests/Sandpit/Exscientia/Align/test_alchemical_ion.py index f06471e6a..f0aa016fd 100644 --- a/tests/Sandpit/Exscientia/Align/test_alchemical_ion.py +++ b/tests/Sandpit/Exscientia/Align/test_alchemical_ion.py @@ -1,11 +1,11 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS +from BioSimSpace.Sandpit.Exscientia._SireWrappers import Atom from BioSimSpace.Sandpit.Exscientia.Align._alch_ion import ( _get_protein_com_idx, _mark_alchemical_ion, ) -from BioSimSpace.Sandpit.Exscientia._SireWrappers import Atom from tests.conftest import has_gromacs, root_fp diff --git a/tests/Sandpit/Exscientia/Align/test_align.py b/tests/Sandpit/Exscientia/Align/test_align.py index 9c5dccc0e..0fe2547d1 100644 --- a/tests/Sandpit/Exscientia/Align/test_align.py +++ b/tests/Sandpit/Exscientia/Align/test_align.py @@ -1,13 +1,12 @@ -import pytest import sys +import pytest +from sire.legacy.Maths import Vector from sire.legacy.MM import InternalFF, IntraCLJFF, IntraFF from sire.legacy.Mol import AtomIdx, Element, PartialMolecule -from sire.legacy.Maths import Vector import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_antechamber, has_openff +from tests.Sandpit.Exscientia.conftest import has_antechamber, has_openff, url @pytest.fixture(scope="session") @@ -729,6 +728,7 @@ def test_hydrogen_mass_repartitioning(): def test_ion_merge(): from sire.legacy.IO import createSodiumIon + from tests.conftest import root_fp # Extract a water molecule from the system. diff --git a/tests/Sandpit/Exscientia/Align/test_decouple.py b/tests/Sandpit/Exscientia/Align/test_decouple.py index 480ff8d44..ad06a9b94 100644 --- a/tests/Sandpit/Exscientia/Align/test_decouple.py +++ b/tests/Sandpit/Exscientia/Align/test_decouple.py @@ -1,11 +1,7 @@ import pytest -from sire.legacy import Mol as _SireMol -from sire.legacy import MM as _SireMM -from sire.legacy import Units as _SireUnits - -from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple import BioSimSpace.Sandpit.Exscientia as BSS +from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple from tests.conftest import root_fp # Store the tutorial URL. diff --git a/tests/Sandpit/Exscientia/Align/test_merge.py b/tests/Sandpit/Exscientia/Align/test_merge.py index f521951b1..2481198e7 100644 --- a/tests/Sandpit/Exscientia/Align/test_merge.py +++ b/tests/Sandpit/Exscientia/Align/test_merge.py @@ -1,9 +1,6 @@ import pytest -import BioSimSpace.Sandpit.Exscientia as BSS - from BioSimSpace.Sandpit.Exscientia.Align._merge import _removeDummies - from tests.Sandpit.Exscientia.conftest import ( get_energy, has_alchemlyb, diff --git a/tests/Sandpit/Exscientia/Convert/test_convert.py b/tests/Sandpit/Exscientia/Convert/test_convert.py index 87a3496a6..c102fd484 100644 --- a/tests/Sandpit/Exscientia/Convert/test_convert.py +++ b/tests/Sandpit/Exscientia/Convert/test_convert.py @@ -1,5 +1,4 @@ import pytest - from sire.legacy import Mol as SireMol import BioSimSpace.Sandpit.Exscientia as BSS @@ -106,6 +105,7 @@ def test_sdf_stereo(lig): import tempfile from rdkit import Chem + from tests.conftest import url # Load the molecule. diff --git a/tests/Sandpit/Exscientia/FreeEnergy/test_alchemical_free_energy.py b/tests/Sandpit/Exscientia/FreeEnergy/test_alchemical_free_energy.py index 5aa89d5b4..6deaa54a1 100644 --- a/tests/Sandpit/Exscientia/FreeEnergy/test_alchemical_free_energy.py +++ b/tests/Sandpit/Exscientia/FreeEnergy/test_alchemical_free_energy.py @@ -1,31 +1,30 @@ import bz2 -from math import exp -import pandas as pd -import pathlib -import pytest -import numpy as np import os +import pathlib import shutil import time -from tests.Sandpit.Exscientia.conftest import ( - has_alchemlyb, - has_alchemlyb_parquet, - has_alchemtest, - has_gromacs, - url, -) -from tests.conftest import root_fp +import numpy as np +import pandas as pd +import pytest import BioSimSpace.Sandpit.Exscientia as BSS -from BioSimSpace.Sandpit.Exscientia.Protocol import FreeEnergyEquilibration -from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple from BioSimSpace.Sandpit.Exscientia import Types as _Types +from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple from BioSimSpace.Sandpit.Exscientia.FreeEnergy import Restraint -from BioSimSpace.Sandpit.Exscientia.Units.Angle import radian, degree +from BioSimSpace.Sandpit.Exscientia.Protocol import FreeEnergyEquilibration +from BioSimSpace.Sandpit.Exscientia.Units.Angle import degree, radian from BioSimSpace.Sandpit.Exscientia.Units.Energy import kcal_per_mol from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin +from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import ( + has_alchemlyb, + has_alchemlyb_parquet, + has_alchemtest, + has_gromacs, + url, +) @pytest.mark.skipif( @@ -319,4 +318,4 @@ def test_correct_conf_file(self, freenrg): lines = f.readlines() assert "lambda array = 0.0, 0.5, 1.0\n" in lines assert f"lambda_val = {float(lam):.1f}\n" in lines - assert f"perturbed residue number = 1\n" in lines + assert "perturbed residue number = 1\n" in lines diff --git a/tests/Sandpit/Exscientia/FreeEnergy/test_restraint.py b/tests/Sandpit/Exscientia/FreeEnergy/test_restraint.py index 8beadf8f9..fa4bbe76f 100644 --- a/tests/Sandpit/Exscientia/FreeEnergy/test_restraint.py +++ b/tests/Sandpit/Exscientia/FreeEnergy/test_restraint.py @@ -1,11 +1,9 @@ import numpy as np import pytest -from sire.legacy.Units import ( - angstrom3 as _Sire_angstrom3, - k_boltz as _k_boltz, - meter3 as _Sire_meter3, - mole as _Sire_mole, -) +from sire.legacy.Units import angstrom3 as _Sire_angstrom3 +from sire.legacy.Units import k_boltz as _k_boltz +from sire.legacy.Units import meter3 as _Sire_meter3 +from sire.legacy.Units import mole as _Sire_mole import BioSimSpace.Sandpit.Exscientia as BSS from BioSimSpace.Sandpit.Exscientia.Align import decouple diff --git a/tests/Sandpit/Exscientia/FreeEnergy/test_restraint_search.py b/tests/Sandpit/Exscientia/FreeEnergy/test_restraint_search.py index 28906dbbc..39af9b323 100644 --- a/tests/Sandpit/Exscientia/FreeEnergy/test_restraint_search.py +++ b/tests/Sandpit/Exscientia/FreeEnergy/test_restraint_search.py @@ -1,27 +1,24 @@ -import pytest +from functools import partial import numpy as np - -from functools import partial +import pytest import BioSimSpace.Sandpit.Exscientia as BSS -from BioSimSpace.Sandpit.Exscientia.Align import decouple from BioSimSpace.Sandpit.Exscientia._Exceptions import AnalysisError +from BioSimSpace.Sandpit.Exscientia.Align import decouple from BioSimSpace.Sandpit.Exscientia.FreeEnergy import ( - RestraintSearch, Restraint, + RestraintSearch, ) from BioSimSpace.Sandpit.Exscientia.Trajectory import Trajectory from BioSimSpace.Sandpit.Exscientia.Units.Angle import degree from BioSimSpace.Sandpit.Exscientia.Units.Energy import kcal_per_mol -from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom -from BioSimSpace.Sandpit.Exscientia.Units.Length import nanometer - +from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom, nanometer from tests.Sandpit.Exscientia.conftest import ( - url, has_gromacs, has_mdanalysis, has_mdrestraints_generator, + url, ) diff --git a/tests/Sandpit/Exscientia/Gateway/test_node.py b/tests/Sandpit/Exscientia/Gateway/test_node.py index 61e9ff047..c77e0b9f0 100644 --- a/tests/Sandpit/Exscientia/Gateway/test_node.py +++ b/tests/Sandpit/Exscientia/Gateway/test_node.py @@ -1,8 +1,8 @@ -import pytest import subprocess -import shlex import sys +import pytest + import BioSimSpace.Sandpit.Exscientia as BSS from tests.conftest import root_fp diff --git a/tests/Sandpit/Exscientia/IO/test_file_cache.py b/tests/Sandpit/Exscientia/IO/test_file_cache.py index 6e292b66c..23fc03446 100644 --- a/tests/Sandpit/Exscientia/IO/test_file_cache.py +++ b/tests/Sandpit/Exscientia/IO/test_file_cache.py @@ -1,12 +1,12 @@ import glob import os -import pytest import tempfile -import BioSimSpace.Sandpit.Exscientia as BSS +import pytest -from tests.Sandpit.Exscientia.conftest import has_amber, has_openff +import BioSimSpace.Sandpit.Exscientia as BSS from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_openff def test_file_cache(): diff --git a/tests/Sandpit/Exscientia/IO/test_openff_gromacs.py b/tests/Sandpit/Exscientia/IO/test_openff_gromacs.py index 12aa73b07..14c9cb659 100644 --- a/tests/Sandpit/Exscientia/IO/test_openff_gromacs.py +++ b/tests/Sandpit/Exscientia/IO/test_openff_gromacs.py @@ -1,8 +1,6 @@ -import pandas import pytest import BioSimSpace.Sandpit.Exscientia as BSS - from tests.Sandpit.Exscientia.conftest import ( has_amber, has_gromacs, diff --git a/tests/Sandpit/Exscientia/IO/test_perturbable.py b/tests/Sandpit/Exscientia/IO/test_perturbable.py index a3541c8ae..875e22022 100644 --- a/tests/Sandpit/Exscientia/IO/test_perturbable.py +++ b/tests/Sandpit/Exscientia/IO/test_perturbable.py @@ -1,7 +1,6 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS - from tests.Sandpit.Exscientia.conftest import url diff --git a/tests/Sandpit/Exscientia/MD/test_md.py b/tests/Sandpit/Exscientia/MD/test_md.py index f2afe28db..d7fb5c5a3 100644 --- a/tests/Sandpit/Exscientia/MD/test_md.py +++ b/tests/Sandpit/Exscientia/MD/test_md.py @@ -1,9 +1,8 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_amber, has_gromacs, has_namd from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs, has_namd, url @pytest.mark.skipif(has_amber is False, reason="Requires AMBER to be installed.") diff --git a/tests/Sandpit/Exscientia/Parameters/test_parameters.py b/tests/Sandpit/Exscientia/Parameters/test_parameters.py index abed5b485..a512ff8d9 100644 --- a/tests/Sandpit/Exscientia/Parameters/test_parameters.py +++ b/tests/Sandpit/Exscientia/Parameters/test_parameters.py @@ -1,13 +1,13 @@ -import pytest import tempfile -import BioSimSpace.Sandpit.Exscientia as BSS +import pytest +import BioSimSpace.Sandpit.Exscientia as BSS from tests.Sandpit.Exscientia.conftest import ( - url, + has_antechamber, has_openff, has_tleap, - has_antechamber, + url, ) @@ -215,6 +215,10 @@ def test_broken_sdf_formal_charge(): assert isclose(charge.value(), 0.0, abs_tol=1e-6) +@pytest.mark.skipif( + has_tleap is False, + reason="Requires AmberTools and tLEaP to be installed.", +) def test_ff19SB(): """ Test that the ff19SB force field can be used to parameterise a molecule. diff --git a/tests/Sandpit/Exscientia/Process/test_amber.py b/tests/Sandpit/Exscientia/Process/test_amber.py index 02ad1239a..bc8ed40b8 100644 --- a/tests/Sandpit/Exscientia/Process/test_amber.py +++ b/tests/Sandpit/Exscientia/Process/test_amber.py @@ -8,12 +8,12 @@ import BioSimSpace.Sandpit.Exscientia as BSS from BioSimSpace.Sandpit.Exscientia._Exceptions import IncompatibleError +from tests.conftest import root_fp from tests.Sandpit.Exscientia.conftest import ( has_amber, has_pyarrow, url, ) -from tests.conftest import root_fp @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_dummy_protocol.py b/tests/Sandpit/Exscientia/Process/test_dummy_protocol.py index fa063d427..016ab6e8d 100644 --- a/tests/Sandpit/Exscientia/Process/test_dummy_protocol.py +++ b/tests/Sandpit/Exscientia/Process/test_dummy_protocol.py @@ -1,10 +1,9 @@ import pytest -from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs -from tests.conftest import root_fp - import BioSimSpace.Sandpit.Exscientia as BSS from BioSimSpace.Sandpit.Exscientia.Process._process import Process +from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_gromacs.py b/tests/Sandpit/Exscientia/Process/test_gromacs.py index 78ccfe726..d74965de6 100644 --- a/tests/Sandpit/Exscientia/Process/test_gromacs.py +++ b/tests/Sandpit/Exscientia/Process/test_gromacs.py @@ -17,6 +17,7 @@ from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin from BioSimSpace.Sandpit.Exscientia.Units.Time import picosecond from BioSimSpace.Sandpit.Exscientia.Units.Volume import centimeter3, nanometer3 +from tests.conftest import root_fp from tests.Sandpit.Exscientia.conftest import ( has_alchemtest, has_amber, @@ -25,7 +26,6 @@ has_pyarrow, url, ) -from tests.conftest import root_fp @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_namd.py b/tests/Sandpit/Exscientia/Process/test_namd.py index 3ad97f742..e6ddd0f59 100644 --- a/tests/Sandpit/Exscientia/Process/test_namd.py +++ b/tests/Sandpit/Exscientia/Process/test_namd.py @@ -1,9 +1,8 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_namd from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_namd @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_openmm.py b/tests/Sandpit/Exscientia/Process/test_openmm.py index aec8406af..0a83ee671 100644 --- a/tests/Sandpit/Exscientia/Process/test_openmm.py +++ b/tests/Sandpit/Exscientia/Process/test_openmm.py @@ -1,10 +1,10 @@ import math + import pytest import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_amber, has_gromacs, has_openff from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs, has_openff, url @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_position_restraint.py b/tests/Sandpit/Exscientia/Process/test_position_restraint.py index 0883024f4..bb5583d14 100644 --- a/tests/Sandpit/Exscientia/Process/test_position_restraint.py +++ b/tests/Sandpit/Exscientia/Process/test_position_restraint.py @@ -9,12 +9,12 @@ from sire.legacy.IO import AmberRst import BioSimSpace.Sandpit.Exscientia as BSS +from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule from BioSimSpace.Sandpit.Exscientia.Align._alch_ion import _mark_alchemical_ion from BioSimSpace.Sandpit.Exscientia.Units.Energy import kj_per_mol from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom -from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule -from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs, has_openff from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs, has_openff @pytest.fixture @@ -195,7 +195,7 @@ def test_gromacs_lipid(system, tmp_path, lipid): else: assert not (tmp_path / "posre_0001.itp").is_file() with open(tmp_path / "gromacs.top", "r") as f: - assert not "posre_0001.itp" in f.read() + assert "posre_0001.itp" not in f.read() @pytest.mark.skipif( diff --git a/tests/Sandpit/Exscientia/Process/test_restart.py b/tests/Sandpit/Exscientia/Process/test_restart.py index 6376d87d0..ec09718b0 100644 --- a/tests/Sandpit/Exscientia/Process/test_restart.py +++ b/tests/Sandpit/Exscientia/Process/test_restart.py @@ -1,10 +1,10 @@ import itertools + import pandas as pd import pytest import BioSimSpace.Sandpit.Exscientia as BSS from BioSimSpace.Sandpit.Exscientia.Process._process import Process - from tests.Sandpit.Exscientia.conftest import ( has_amber, has_antechamber, diff --git a/tests/Sandpit/Exscientia/Process/test_single_point_energy.py b/tests/Sandpit/Exscientia/Process/test_single_point_energy.py index 2ccf121b9..3fe986c0d 100644 --- a/tests/Sandpit/Exscientia/Process/test_single_point_energy.py +++ b/tests/Sandpit/Exscientia/Process/test_single_point_energy.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_amber, has_gromacs, has_pyarrow +from tests.Sandpit.Exscientia.conftest import has_amber, has_gromacs, has_pyarrow, url @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Process/test_somd.py b/tests/Sandpit/Exscientia/Process/test_somd.py index eeb81472b..b7a31c9f9 100644 --- a/tests/Sandpit/Exscientia/Process/test_somd.py +++ b/tests/Sandpit/Exscientia/Process/test_somd.py @@ -1,17 +1,16 @@ -import BioSimSpace.Sandpit.Exscientia as BSS -from BioSimSpace.Sandpit.Exscientia.Align import decouple -from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom -from BioSimSpace.Sandpit.Exscientia.Units.Angle import radian -from BioSimSpace.Sandpit.Exscientia.Units.Energy import kcal_per_mol -from BioSimSpace.Sandpit.Exscientia.FreeEnergy import Restraint -from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin - import filecmp import os -import pytest import warnings +import pytest + import BioSimSpace.Sandpit.Exscientia as BSS +from BioSimSpace.Sandpit.Exscientia.Align import decouple +from BioSimSpace.Sandpit.Exscientia.FreeEnergy import Restraint +from BioSimSpace.Sandpit.Exscientia.Units.Angle import radian +from BioSimSpace.Sandpit.Exscientia.Units.Energy import kcal_per_mol +from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom +from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin from tests.conftest import root_fp # Store the tutorial URL. diff --git a/tests/Sandpit/Exscientia/Protocol/test_config.py b/tests/Sandpit/Exscientia/Protocol/test_config.py index 5963d819e..9ecd3ca86 100644 --- a/tests/Sandpit/Exscientia/Protocol/test_config.py +++ b/tests/Sandpit/Exscientia/Protocol/test_config.py @@ -2,7 +2,9 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS +from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple +from BioSimSpace.Sandpit.Exscientia.FreeEnergy import Restraint from BioSimSpace.Sandpit.Exscientia.Protocol import ( ConfigFactory, Equilibration, @@ -11,22 +13,15 @@ FreeEnergyMinimisation, Production, ) - -from BioSimSpace.Sandpit.Exscientia.Align._decouple import decouple -from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom -from BioSimSpace.Sandpit.Exscientia.Units.Angle import radian, degree +from BioSimSpace.Sandpit.Exscientia.Units.Angle import degree, radian from BioSimSpace.Sandpit.Exscientia.Units.Energy import kcal_per_mol +from BioSimSpace.Sandpit.Exscientia.Units.Length import angstrom from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin -from BioSimSpace.Sandpit.Exscientia.FreeEnergy import Restraint -from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule -from BioSimSpace.Sandpit.Exscientia._Utils import _try_import, _have_imported - - from tests.Sandpit.Exscientia.conftest import ( - url, - has_gromacs, has_antechamber, + has_gromacs, has_openff, + url, ) @@ -216,10 +211,6 @@ def test_staged_fep_df(self, system): assert "init-lambda-state = 6" in mdp_text -@pytest.mark.skipif( - has_antechamber is False or has_openff is False, - reason="Requires ambertools/antechamber and openff to be installed", -) @pytest.fixture(scope="module") def system_and_mdr_restraint(): # Benzene. @@ -375,6 +366,10 @@ def test_annihilate_vdw2q(self, system): assert "couple-lambda1 = q" in mdp_text assert "couple-intramol = no" in mdp_text + @pytest.mark.skipif( + has_antechamber is False or has_openff is False, + reason="Requires ambertools/antechamber and openff to be installed", + ) @pytest.mark.skipif( has_gromacs is False, reason="Requires GROMACS to be installed." ) @@ -530,6 +525,10 @@ def test_turn_on_restraint_boresch(self, system_and_boresch_restraint): for line in lines: assert line in pert_text + @pytest.mark.skipif( + has_antechamber is False or has_openff is False, + reason="Requires ambertools/antechamber and openff to be installed", + ) def test_turn_on_restraint_mdr(self, system_and_mdr_restraint): """Test for turning on the mdr restraint""" system, restraint = system_and_mdr_restraint @@ -573,6 +572,10 @@ def test_turn_on_restraint_mdr(self, system_and_mdr_restraint): for line in lines: assert line in pert_text + @pytest.mark.skipif( + has_antechamber is False or has_openff is False, + reason="Requires ambertools/antechamber and openff to be installed", + ) def test_release_restraint_mdr(self, system_and_mdr_restraint): """Test for releasing the non-permanent mdr restraints""" system, restraint = system_and_mdr_restraint diff --git a/tests/Sandpit/Exscientia/Protocol/test_free_energy_mixin.py b/tests/Sandpit/Exscientia/Protocol/test_free_energy_mixin.py index e4484789e..ac06e35c8 100644 --- a/tests/Sandpit/Exscientia/Protocol/test_free_energy_mixin.py +++ b/tests/Sandpit/Exscientia/Protocol/test_free_energy_mixin.py @@ -1,6 +1,6 @@ +import numpy as np import pandas as pd import pytest -import numpy as np from BioSimSpace.Sandpit.Exscientia.Protocol import _FreeEnergyMixin diff --git a/tests/Sandpit/Exscientia/Solvent/test_solvent.py b/tests/Sandpit/Exscientia/Solvent/test_solvent.py index 7e6f7de25..9e1a8ccf8 100644 --- a/tests/Sandpit/Exscientia/Solvent/test_solvent.py +++ b/tests/Sandpit/Exscientia/Solvent/test_solvent.py @@ -1,12 +1,9 @@ -import pytest import tempfile - from functools import partial -from sire.legacy.IO import GroTop +import pytest import BioSimSpace.Sandpit.Exscientia as BSS - from tests.Sandpit.Exscientia.conftest import has_gromacs diff --git a/tests/Sandpit/Exscientia/Stream/test_stream.py b/tests/Sandpit/Exscientia/Stream/test_stream.py index 432110cbc..7b6a2f5c9 100644 --- a/tests/Sandpit/Exscientia/Stream/test_stream.py +++ b/tests/Sandpit/Exscientia/Stream/test_stream.py @@ -1,4 +1,5 @@ import os + import pytest import BioSimSpace.Sandpit.Exscientia as BSS diff --git a/tests/Sandpit/Exscientia/Trajectory/test_trajectory.py b/tests/Sandpit/Exscientia/Trajectory/test_trajectory.py index 53568dab9..d10c8b2a1 100644 --- a/tests/Sandpit/Exscientia/Trajectory/test_trajectory.py +++ b/tests/Sandpit/Exscientia/Trajectory/test_trajectory.py @@ -10,8 +10,8 @@ def wrap(arg): return arg -from tests.Sandpit.Exscientia.conftest import has_mdanalysis, has_mdtraj from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_mdanalysis, has_mdtraj @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/Types/test_general_unit.py b/tests/Sandpit/Exscientia/Types/test_general_unit.py index efc3cd4e1..cfe632968 100644 --- a/tests/Sandpit/Exscientia/Types/test_general_unit.py +++ b/tests/Sandpit/Exscientia/Types/test_general_unit.py @@ -1,10 +1,9 @@ import pytest +import sire as sr import BioSimSpace.Sandpit.Exscientia.Types as Types import BioSimSpace.Sandpit.Exscientia.Units as Units -import sire as sr - @pytest.mark.parametrize( "string, dimensions", diff --git a/tests/Sandpit/Exscientia/Types/test_types.py b/tests/Sandpit/Exscientia/Types/test_types.py index b3cc909f5..651aa7540 100644 --- a/tests/Sandpit/Exscientia/Types/test_types.py +++ b/tests/Sandpit/Exscientia/Types/test_types.py @@ -1,6 +1,7 @@ -import pytest import random +import pytest + import BioSimSpace.Sandpit.Exscientia.Types as Types # Create a list of the Type classes. diff --git a/tests/Sandpit/Exscientia/_SireWrappers/test_molecule.py b/tests/Sandpit/Exscientia/_SireWrappers/test_molecule.py index 15fe4ae49..89ae620a4 100644 --- a/tests/Sandpit/Exscientia/_SireWrappers/test_molecule.py +++ b/tests/Sandpit/Exscientia/_SireWrappers/test_molecule.py @@ -1,9 +1,8 @@ import pytest import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_amber, has_openff, has_pyarrow from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_openff, has_pyarrow, url @pytest.fixture(scope="session") diff --git a/tests/Sandpit/Exscientia/_SireWrappers/test_replica_system.py b/tests/Sandpit/Exscientia/_SireWrappers/test_replica_system.py index f8ae6aa67..8ec908e09 100644 --- a/tests/Sandpit/Exscientia/_SireWrappers/test_replica_system.py +++ b/tests/Sandpit/Exscientia/_SireWrappers/test_replica_system.py @@ -1,10 +1,11 @@ import os -import pytest +import sys import tempfile -import BioSimSpace as BSS -from BioSimSpace._SireWrappers import System, ReplicaSystem +import pytest +import BioSimSpace as BSS +from BioSimSpace._SireWrappers import ReplicaSystem, System from tests.Sandpit.Exscientia.conftest import url @@ -72,6 +73,9 @@ def test_get_replica(rs, request): replica_system.getReplica(-11) +@pytest.mark.skipif( + sys.platform == "win32", reason="File locking prevents temp cleanup" +) @pytest.mark.parametrize("rs", ["replica_system", "perturbable_replica_system"]) def test_stream(rs, request): """Test streaming the replica system to a file.""" @@ -134,6 +138,9 @@ def test_save_load_replicas(rs, request): assert rs.nReplicas() == 5 +@pytest.mark.skipif( + sys.platform == "win32", reason="File locking prevents temp cleanup" +) def test_squashed_representation(squashed_perturbable_replica_system): """Test that the internal squashed trajectory representation works.""" # Check that the number of atoms in the internal system is less diff --git a/tests/Sandpit/Exscientia/_SireWrappers/test_system.py b/tests/Sandpit/Exscientia/_SireWrappers/test_system.py index 72620203e..009c85fd8 100644 --- a/tests/Sandpit/Exscientia/_SireWrappers/test_system.py +++ b/tests/Sandpit/Exscientia/_SireWrappers/test_system.py @@ -1,13 +1,12 @@ import math + import numpy as np import pytest - from sire.legacy.Vol import TriclinicBox import BioSimSpace.Sandpit.Exscientia as BSS - -from tests.Sandpit.Exscientia.conftest import url, has_amber, has_openff from tests.conftest import root_fp +from tests.Sandpit.Exscientia.conftest import has_amber, has_openff, url @pytest.fixture(scope="session") @@ -508,7 +507,7 @@ def test_remove_box(system): system.removeBox() # Make sure the box is removed. - assert not "space" in system._sire_object.property_keys() + assert "space" not in system._sire_object.property_keys() def test_renumber(system): diff --git a/tests/Sandpit/Exscientia/conftest.py b/tests/Sandpit/Exscientia/conftest.py index f85184d4c..cc4cebb38 100644 --- a/tests/Sandpit/Exscientia/conftest.py +++ b/tests/Sandpit/Exscientia/conftest.py @@ -1,18 +1,16 @@ +import os from typing import Dict, Optional -import os import pandas import pytest from BioSimSpace.Sandpit import Exscientia as BSS - +from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule +from BioSimSpace.Sandpit.Exscientia._Utils import _have_imported, _try_import from BioSimSpace.Sandpit.Exscientia.Process import Gromacs from BioSimSpace.Sandpit.Exscientia.Protocol import Production from BioSimSpace.Sandpit.Exscientia.Units.Temperature import kelvin from BioSimSpace.Sandpit.Exscientia.Units.Time import femtosecond -from BioSimSpace.Sandpit.Exscientia._SireWrappers import Molecule - -from BioSimSpace.Sandpit.Exscientia._Utils import _try_import, _have_imported # Turn on verbose error messages. BSS.setVerbose(True) @@ -34,13 +32,18 @@ has_amber = False # Make sure NAMD is installed. -try: - from sire.legacy.Base import findExe +from sire.legacy.Base import findExe - findExe("namd2") - has_namd = True -except: - has_namd = False +exes = ["namd3", "namd2"] +has_namd = False + +for exe in exes: + try: + findExe(exe) + has_namd = True + break + except Exception: + pass # Check whether AMBER parameterisation executables are installed. has_tleap = BSS.Parameters._Protocol._amber._tleap_exe is not None @@ -80,8 +83,8 @@ # Check for alchemtest. try: - from alchemtest.gmx import load_ABFE from alchemtest.amber import load_bace_example + from alchemtest.gmx import load_ABFE has_alchemtest = True except ModuleNotFoundError: diff --git a/tests/Sandpit/Exscientia/output/amber_fep_min.out b/tests/Sandpit/Exscientia/output/amber_fep_min.out index ab624de02..ec440964b 100644 --- a/tests/Sandpit/Exscientia/output/amber_fep_min.out +++ b/tests/Sandpit/Exscientia/output/amber_fep_min.out @@ -19,70 +19,70 @@ [-O]verwriting output File Assignments: -| MDIN: amber.cfg -| MDOUT: amber.out -| INPCRD: amber.rst7 -| PARM: amber.prm7 -| RESTRT: amber.crd -| REFC: refc -| MDVEL: mdvel -| MDEN: mden -| MDCRD: mdcrd -| MDINFO: amber.nrg -| MDFRC: mdfrc +| MDIN: amber.cfg +| MDOUT: amber.out +| INPCRD: amber.rst7 +| PARM: amber.prm7 +| RESTRT: amber.crd +| REFC: refc +| MDVEL: mdvel +| MDEN: mden +| MDCRD: mdcrd +| MDINFO: amber.nrg +| MDFRC: mdfrc Here is the input file: -FreeEnergyMinimisation -&cntrl - ntpr=200, - ntxo=2, - irest=0, - ntx=1, - imin=1, - ntmin=2, - maxcyc=10000, - ncyc=1000, - cut=8.0, - iwrap=1, - icfe=1, - ifsc=1, - ntf=1, - mbar_states=11, +FreeEnergyMinimisation +&cntrl + ntpr=200, + ntxo=2, + irest=0, + ntx=1, + imin=1, + ntmin=2, + maxcyc=10000, + ncyc=1000, + cut=8.0, + iwrap=1, + icfe=1, + ifsc=1, + ntf=1, + mbar_states=11, mbar_lambda=0.00000, 0.10000, 0.20000, 0.30000, 0.40000, 0.50000, 0.60000, 0 - clambda=0.00000, - timask1="@6481-6485", - timask2="@6486-6491", - scmask1="", - scmask2="@6491", - noshakemask="", -/ + clambda=0.00000, + timask1="@6481-6485", + timask2="@6486-6491", + scmask1="", + scmask2="@6491", + noshakemask="", +/ -Note: ig = -1. Setting random seed to 54474 based on wallclock time in +Note: ig = -1. Setting random seed to 54474 based on wallclock time in microseconds. | irandom = 1, using AMBER's internal random number generator (default). - + |--------------------- INFORMATION ---------------------- | GPU (CUDA) Version of PMEMD in use: NVIDIA GPU IN USE. | Version 18.0.0 -| +| | 03/25/2018 -| +| | Implementation by: | Ross C. Walker (SDSC) | Scott Le Grand (nVIDIA) -| +| | Version 18 performance extensions by: | David Cerutti (Rutgers) -| +| | Precision model in use: | [SPFP] - Single Precision Forces, 64-bit Fixed Point | Accumulation. (Default) -| +| |-------------------------------------------------------- - + |----------------- CITATION INFORMATION ----------------- | | When publishing work that utilized the CUDA version @@ -109,13 +109,13 @@ Note: ig = -1. Setting random seed to 54474 based on wallclock time in | pp374-380, DOI: 10.1016/j.cpc.2012.09.022 | | When publishing work that utilized the CUDA version -| of TI, BAR, MBAR or FEP please cite the following -| publications in addition to the regular AMBER +| of TI, BAR, MBAR or FEP please cite the following +| publications in addition to the regular AMBER | GPU citations: | -| - Daniel J. Mermelstein; Charles Lin; Gard Nelson; +| - Daniel J. Mermelstein; Charles Lin; Gard Nelson; | Rachael Kretsch; J. Andrew McCammon; Ross C. Walker -| "Fast and Flexible GPU Accelerated Binding +| "Fast and Flexible GPU Accelerated Binding | Free Energy Calculations within the AMBER Molecular | Dynamics Package" J. Comp. Chem., 2018, | DOI: 10.1002/jcc.25187 @@ -129,7 +129,7 @@ Note: ig = -1. Setting random seed to 54474 based on wallclock time in | | |-------------------------------------------------------- - + |------------------- GPU DEVICE INFO -------------------- | | CUDA_VISIBLE_DEVICES: not set @@ -141,8 +141,8 @@ Note: ig = -1. Setting random seed to 54474 based on wallclock time in | CUDA Device Core Freq: 1.71 GHz | |-------------------------------------------------------- - - + + | Conditional Compilation Defines Used: | PUBFFT | BINTRAJ @@ -162,7 +162,7 @@ Note: ig = -1. Setting random seed to 54474 based on wallclock time in | Duplicated 0 dihedrals -------------------------------------------------------------------------------- - 1. RESOURCE USE: + 1. RESOURCE USE: -------------------------------------------------------------------------------- getting new box info from bottom of inpcrd @@ -183,7 +183,7 @@ Note: ig = -1. Setting random seed to 54474 based on wallclock time in 2. CONTROL DATA FOR THE RUN -------------------------------------------------------------------------------- - + General flags: imin = 1, nmropt = 0 @@ -250,10 +250,10 @@ Ewald parameters: 3. ATOMIC COORDINATES AND VELOCITIES -------------------------------------------------------------------------------- - + begin time read from input coords = 0.000 ps - + Number of triangulated 3-point waters found: 2160 Number of shake restraints removed in TI region 1 : 0 Number of shake restraints removed in TI region 2 : 0 diff --git a/tests/Solvent/test_solvent.py b/tests/Solvent/test_solvent.py index 02afe1f06..1e07dc23f 100644 --- a/tests/Solvent/test_solvent.py +++ b/tests/Solvent/test_solvent.py @@ -1,12 +1,9 @@ -import pytest import tempfile - from functools import partial -from sire.legacy.IO import GroTop +import pytest import BioSimSpace as BSS - from tests.conftest import has_gromacs diff --git a/tests/Stream/test_stream.py b/tests/Stream/test_stream.py index 73788bd7e..c9b449885 100644 --- a/tests/Stream/test_stream.py +++ b/tests/Stream/test_stream.py @@ -1,4 +1,5 @@ import os + import pytest import BioSimSpace as BSS diff --git a/tests/Trajectory/test_trajectory.py b/tests/Trajectory/test_trajectory.py index 57d88e319..ff2b515ca 100644 --- a/tests/Trajectory/test_trajectory.py +++ b/tests/Trajectory/test_trajectory.py @@ -10,7 +10,7 @@ def wrap(arg): return arg -from tests.conftest import url, has_mdanalysis, has_mdtraj +from tests.conftest import has_mdanalysis, has_mdtraj @pytest.fixture(scope="session") diff --git a/tests/Types/test_general_unit.py b/tests/Types/test_general_unit.py index ec630d060..2faf77f8c 100644 --- a/tests/Types/test_general_unit.py +++ b/tests/Types/test_general_unit.py @@ -1,10 +1,9 @@ import pytest +import sire as sr import BioSimSpace.Types as Types import BioSimSpace.Units as Units -import sire as sr - @pytest.mark.parametrize( "string, dimensions", diff --git a/tests/Types/test_types.py b/tests/Types/test_types.py index 5aa9a7b78..051fb9ff8 100644 --- a/tests/Types/test_types.py +++ b/tests/Types/test_types.py @@ -1,6 +1,7 @@ -import pytest import random +import pytest + import BioSimSpace.Types as Types # Create a list of the Type classes. diff --git a/tests/_SireWrappers/test_bond.py b/tests/_SireWrappers/test_bond.py index 87dd6f09d..7b9235538 100644 --- a/tests/_SireWrappers/test_bond.py +++ b/tests/_SireWrappers/test_bond.py @@ -1,7 +1,7 @@ -import BioSimSpace as BSS - import pytest +import BioSimSpace as BSS + def test_bonds(): system = BSS.IO.readMolecules(["tests/input/ala.top", "tests/input/ala.crd"]) diff --git a/tests/_SireWrappers/test_molecule.py b/tests/_SireWrappers/test_molecule.py index 72aff7f12..bb447ec6e 100644 --- a/tests/_SireWrappers/test_molecule.py +++ b/tests/_SireWrappers/test_molecule.py @@ -1,8 +1,7 @@ import pytest import BioSimSpace as BSS - -from tests.conftest import url, has_amber +from tests.conftest import has_amber, url @pytest.mark.skipif(has_amber is False, reason="Requires AMBER to be installed.") diff --git a/tests/_SireWrappers/test_replica_system.py b/tests/_SireWrappers/test_replica_system.py index 2bfa6030f..a63015107 100644 --- a/tests/_SireWrappers/test_replica_system.py +++ b/tests/_SireWrappers/test_replica_system.py @@ -1,8 +1,10 @@ import os -import pytest +import sys import tempfile -from BioSimSpace._SireWrappers import System, ReplicaSystem +import pytest + +from BioSimSpace._SireWrappers import ReplicaSystem, System @pytest.fixture(scope="module") @@ -52,6 +54,9 @@ def test_get_replica(rs, request): replica_system.getReplica(-11) +@pytest.mark.skipif( + sys.platform == "win32", reason="File locking prevents temp cleanup" +) @pytest.mark.parametrize("rs", ["replica_system", "perturbable_replica_system"]) def test_stream(rs, request): """Test streaming the replica system to a file.""" @@ -114,6 +119,9 @@ def test_save_load_replicas(rs, request): assert rs.nReplicas() == 5 +@pytest.mark.skipif( + sys.platform == "win32", reason="File locking prevents temp cleanup" +) def test_squashed_representation(squashed_perturbable_replica_system): """Test that the internal squashed trajectory representation works.""" # Check that the number of atoms in the internal system is less diff --git a/tests/_SireWrappers/test_search_result.py b/tests/_SireWrappers/test_search_result.py index 55aeda098..f647b5889 100644 --- a/tests/_SireWrappers/test_search_result.py +++ b/tests/_SireWrappers/test_search_result.py @@ -1,7 +1,7 @@ -import BioSimSpace as BSS - import pytest +import BioSimSpace as BSS + # Store the tutorial URL. url = BSS.tutorialUrl() diff --git a/tests/_SireWrappers/test_system.py b/tests/_SireWrappers/test_system.py index 66f5869d2..3bba81af9 100644 --- a/tests/_SireWrappers/test_system.py +++ b/tests/_SireWrappers/test_system.py @@ -1,12 +1,11 @@ import math + import numpy as np import pytest - from sire.legacy.Vol import TriclinicBox import BioSimSpace as BSS - -from tests.conftest import url, has_amber, has_openff +from tests.conftest import has_amber, has_openff, url @pytest.fixture(scope="session") @@ -498,7 +497,7 @@ def test_remove_box(system): system.removeBox() # Make sure the box is removed. - assert not "space" in system._sire_object.property_keys() + assert "space" not in system._sire_object.property_keys() def test_renumber(system): diff --git a/tests/conftest.py b/tests/conftest.py index 76223f9d9..87d65716a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,12 @@ collect_ignore_glob = ["*/out_test*.py"] import os -import pytest - from pathlib import Path -import BioSimSpace as BSS +import pytest -from BioSimSpace._Utils import _try_import, _have_imported +import BioSimSpace as BSS +from BioSimSpace._Utils import _have_imported, _try_import # Turn on verbose error messages. BSS.setVerbose(True) @@ -29,13 +28,18 @@ has_amber = False # Make sure NAMD is installed. -try: - from sire.legacy.Base import findExe - - findExe("namd2") - has_namd = True -except: - has_namd = False +from sire.legacy.Base import findExe + +exes = ["namd3", "namd2"] +has_namd = False + +for exe in exes: + try: + findExe(exe) + has_namd = True + break + except Exception: + pass # Check whether AMBER parameterisation executables are installed. has_tleap = BSS.Parameters._Protocol._amber._tleap_exe is not None