Source code for tests.conftest

import importlib
import logging
import os
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch

import click
import numpy as np
import pytest
import rdkit.Chem.rdDistGeom as rdDistGeom
import yaml
from click.testing import CliRunner
from pytest_mock import MockerFixture
from rdkit import Chem

from chemsmart.cli.gaussian.gaussian import gaussian
from chemsmart.cli.job import click_folder_options
from chemsmart.cli.thermochemistry.thermochemistry import thermochemistry
from chemsmart.io.molecules.structure import Molecule
from chemsmart.jobs.gaussian.runner import FakeGaussianJobRunner
from chemsmart.jobs.iterate.runner import IterateJobRunner
from chemsmart.jobs.mol.runner import (
    PyMOLAlignJobRunner,
    PyMOLHybridVisualizationJobRunner,
    PyMOLIRCMovieJobRunner,
    PyMOLMOJobRunner,
    PyMOLMovieJobRunner,
    PyMOLVisualizationJobRunner,
)
from chemsmart.jobs.nciplot.runner import FakeNCIPLOTJobRunner
from chemsmart.jobs.orca.runner import FakeORCAJobRunner
from chemsmart.settings.server import Server

thermochemistry_cli_module = importlib.import_module(
    "chemsmart.cli.thermochemistry.thermochemistry"
)

mol_cli_module = importlib.import_module("chemsmart.cli.mol.mol")


############ Thermochemistry Mock Fixtures ##################
[docs] @pytest.fixture() def make_thermochemistry_mock(): """Factory fixture that creates a MagicMock mimicking a Thermochemistry instance. Returns a callable that accepts the attributes accessed by ``Thermochemistry.cleaned_frequencies`` and returns a properly configured mock, so test methods stay free of direct ``MagicMock`` construction. Usage:: def test_something(make_thermochemistry_mock): mock = make_thermochemistry_mock( vibrational_frequencies=[-50.0, 100.0], jobtype="opt", check_imaginary_frequencies=False, ) result = Thermochemistry.cleaned_frequencies.fget(mock) assert result == [100.0, 100.0] """ from chemsmart.analysis.thermochemistry import Thermochemistry def _factory( vibrational_frequencies, jobtype="opt", check_imaginary_frequencies=True, s_freq_cutoff_cm=None, h_freq_cutoff_cm=None, ): mock = MagicMock(spec=Thermochemistry) mock.vibrational_frequencies = vibrational_frequencies mock.jobtype = jobtype mock.check_imaginary_frequencies = check_imaginary_frequencies mock.s_freq_cutoff_cm = s_freq_cutoff_cm mock.h_freq_cutoff_cm = h_freq_cutoff_cm mock.filename = "dummy.log" return mock return _factory
############ CLI Fixtures ##################
[docs] @pytest.fixture() def make_cli_ctx_obj(): """Factory for the minimal Click context object.""" def _make(jobrunner): return {"jobrunner": jobrunner} return _make
[docs] @pytest.fixture() def invoke_config_server(): """Return a callable that invokes 'chemsmart config server' via Click's CliRunner. Usage in tests:: def test_something(invoke_config_server): result = invoke_config_server() assert result.exit_code == 0 """ from chemsmart.cli.config import config def _invoke(args=None): runner = CliRunner() return runner.invoke(config, ["server"] + (args or [])) return _invoke
[docs] @pytest.fixture() def invoke_folder_command(): """Fixture that returns a callable to invoke a folder command with options.""" @click.command() @click_folder_options @click.pass_context def _folder_cmd(ctx, directory, filetype, program): """Minimal command used only to inspect registered options.""" ctx.ensure_object(dict) ctx.obj["directory"] = directory ctx.obj["filetype"] = filetype ctx.obj["program"] = program def _invoke(args=None): runner = CliRunner() result = runner.invoke(_folder_cmd, args or []) return result return _invoke
[docs] @pytest.fixture() def run_thermochemistry_and_capture_settings(): """Run the thermochemistry CLI with mocked job construction.""" def _run(extra_args=None, ctx_obj=None): runner = CliRunner() captured_settings = None mock_job = MagicMock() base_args = ["-f", "dummy.log", "-T", "298.15"] cli_args = base_args + (extra_args or []) with ( patch.object( thermochemistry_cli_module, "get_program_type_from_file", return_value="gaussian", ), patch.object( thermochemistry_cli_module.ThermochemistryJob, "from_filename", return_value=mock_job, ) as mock_from_filename, ): result = runner.invoke( thermochemistry, cli_args, obj=ctx_obj or {}, catch_exceptions=False, ) if mock_from_filename.call_args is not None: captured_settings = mock_from_filename.call_args[1].get( "settings" ) return result, captured_settings return _run
[docs] @pytest.fixture() def run_thermochemistry_with_directory(): """Fixture to invoke thermochemistry CLI with directory options and mocked folder. Patches ``BaseFolder`` so that ``get_all_output_files_in_current_folder_by_program``, ``get_all_files_in_current_folder_by_suffix``, and ``get_all_files_in_current_folder_by_program_and_suffix`` all return the caller-supplied ``mock_files`` list. Also patches ``ThermochemistryJob.from_filename`` to avoid real job execution. Usage:: def test_something(run_thermochemistry_with_directory, tmp_path): result, mock_from_filename = run_thermochemistry_with_directory( ["-d", str(tmp_path), "-p", "gaussian", "-T", "298.15"], mock_files=["/fake/a.log", "/fake/b.log"], ) assert result.exit_code == 0 assert mock_from_filename.call_count == 2 """ def _invoke(extra_args, mock_files=None): if mock_files is None: mock_files = ["/fake/dir/mol1.log"] runner = CliRunner() mock_job = MagicMock() mock_job.label = "mol1" with ( patch.object( thermochemistry_cli_module, "BaseFolder" ) as mock_folder_cls, patch.object( thermochemistry_cli_module.ThermochemistryJob, "from_filename" ) as mock_from_filename, ): mock_folder = MagicMock() # Configure every discovery method to return the caller-supplied list mock_folder.get_all_output_files_in_current_folder_by_program.return_value = ( mock_files ) mock_folder.get_all_files_in_current_folder_by_suffix.return_value = ( mock_files ) mock_folder.get_all_files_in_current_folder_by_program_and_suffix.return_value = ( mock_files ) mock_folder_cls.return_value = mock_folder mock_from_filename.return_value = mock_job result = runner.invoke(thermochemistry, extra_args) return result, mock_from_filename return _invoke
[docs] @pytest.fixture() def run_gaussian_and_capture_settings(): """Run the gaussian CLI with a patched job class and capture settings.""" def _run(job_class_path, cli_args, ctx_obj): runner = CliRunner() captured_settings = None with patch(job_class_path) as mock_job_cls: mock_job_cls.return_value = MagicMock() result = runner.invoke( gaussian, cli_args, obj=ctx_obj, catch_exceptions=False, ) if mock_job_cls.call_args is not None: captured_settings = mock_job_cls.call_args[1].get("settings") return result, captured_settings return _run
[docs] @pytest.fixture() def run_orca_and_capture_settings(): """Run the orca CLI with a patched job class and capture settings.""" from chemsmart.cli.orca.orca import orca as orca_cli def _run(job_class_path, cli_args, ctx_obj=None): if ctx_obj is None: ctx_obj = {} runner = CliRunner() captured_settings = None with patch(job_class_path) as mock_job_cls: mock_job_cls.return_value = MagicMock() result = runner.invoke( orca_cli, cli_args, obj=ctx_obj, catch_exceptions=False, ) if mock_job_cls.call_args is not None: captured_settings = mock_job_cls.call_args[1].get("settings") return result, captured_settings return _run
[docs] @pytest.fixture def invoke_mol_with_visualize(): """Invoke ``mol … visualize`` with all PyMOL job execution mocked out.""" from chemsmart.cli.mol.mol import mol as mol_group def _invoke(cli_args, ctx_obj=None): runner = CliRunner() if ctx_obj is None: ctx_obj = {} @mol_group.command("_test_noop") @click.pass_context def _noop(ctx): pass try: with ( patch.object( mol_cli_module, "Molecule", MagicMock(), ) as mock_molecule_cls, patch.object( mol_cli_module, "BaseFolder", MagicMock(), ) as mock_folder_cls, ): # Setup folder mock to return mock files mock_folder_instance = MagicMock() mock_folder_instance.get_all_output_files_in_current_folder_by_program.return_value = [ "/fake/dir/mol.log" ] mock_folder_cls.return_value = mock_folder_instance # Setup molecule mock mock_molecule_cls.from_filepath.return_value = MagicMock() result = runner.invoke( mol_group, cli_args + ["_test_noop"], obj=ctx_obj, catch_exceptions=False, ) finally: mol_group.commands.pop("_test_noop", None) return result return _invoke
[docs] @pytest.fixture def invoke_mol_cli(): """Invoke ``mol`` CLI with provided args.""" from chemsmart.cli.mol.mol import mol as mol_group def _invoke(cli_args, ctx_obj=None): runner = CliRunner() if ctx_obj is None: ctx_obj = {} return runner.invoke( mol_group, cli_args, obj=ctx_obj, catch_exceptions=False ) return _invoke
[docs] @pytest.fixture() def chemsmart_templates_config(mocker): """ Point USER_CONFIG_DIR to the local templates directory. This avoids creating a mock directory and instead uses the provided templates. """ # Locate templates: chemsmart/settings/templates/.chemsmart package_root = Path(__file__).resolve().parent.parent template_dir = ( package_root / "chemsmart" / "settings" / "templates" / ".chemsmart" ) if not template_dir.exists(): raise FileNotFoundError( f"Template directory not found: {template_dir}" ) # Patch the Class attribute mocker.patch( "chemsmart.settings.user.ChemsmartUserSettings.USER_CONFIG_DIR", str(template_dir), ) # Patch the global instance in runner.py from chemsmart.settings.user import ChemsmartUserSettings new_settings = ChemsmartUserSettings() mocker.patch("chemsmart.jobs.runner.user_settings", new_settings) # Patch other module-level user_settings singletons used by the CLI path mocker.patch("chemsmart.settings.server.user_settings", new_settings) mocker.patch("chemsmart.settings.executable.user_settings", new_settings) return template_dir
############ Gaussian Fixtures ##################
[docs] @pytest.fixture() def test_data_directory(): current_directory = os.path.dirname(os.path.abspath(__file__)) return os.path.abspath(os.path.join(current_directory, "data"))
# master gaussian test directory
[docs] @pytest.fixture() def gaussian_test_directory(test_data_directory): return os.path.join(test_data_directory, "GaussianTests")
# Gaussian folder for semiempirical calculations
[docs] @pytest.fixture() def gaussian_semiempirical_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "semiempirical")
[docs] @pytest.fixture() def gaussian_semiempirical_pm6_output_file( gaussian_semiempirical_test_directory, ): return os.path.join( gaussian_semiempirical_test_directory, "DBU_PM6_opt.log" )
# Gaussian output file from outputs folder
[docs] @pytest.fixture() def outputs_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "outputs")
[docs] @pytest.fixture() def wbi_outputfile(outputs_test_directory): wbi_outputfile = os.path.join( outputs_test_directory, "TS_5coord_XIII_wbi.log" ) return wbi_outputfile
# Gaussian input files
[docs] @pytest.fixture() def gaussian_inputs_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "inputs")
[docs] @pytest.fixture() def gaussian_opt_inputfile(gaussian_inputs_test_directory): gaussian_opt_input = os.path.join( gaussian_inputs_test_directory, "model_opt_input.com" ) return gaussian_opt_input
[docs] @pytest.fixture() def gaussian_frozen_opt_inputfile(gaussian_inputs_test_directory): gaussian_frozen_opt_inputfile = os.path.join( gaussian_inputs_test_directory, "frozen_coordinates_opt.com" ) return gaussian_frozen_opt_inputfile
[docs] @pytest.fixture() def gaussian_modred_inputfile(gaussian_inputs_test_directory): gaussian_modred_inputfile = os.path.join( gaussian_inputs_test_directory, "model_modred_input.com" ) return gaussian_modred_inputfile
[docs] @pytest.fixture() def gaussian_scan_inputfile(gaussian_inputs_test_directory): gaussian_scan_inputfile = os.path.join( gaussian_inputs_test_directory, "model_scan_input.com" ) return gaussian_scan_inputfile
[docs] @pytest.fixture() def hf_com_filepath(gaussian_inputs_test_directory): return os.path.join(gaussian_inputs_test_directory, "hf.com")
# Gaussian input files for genecp
[docs] @pytest.fixture() def gaussian_inputs_genecp_directory(gaussian_inputs_test_directory): return os.path.join(gaussian_inputs_test_directory, "genecp")
[docs] @pytest.fixture() def gaussian_opt_genecp_inputfile(gaussian_inputs_genecp_directory): gaussian_opt_genecp_input = os.path.join( gaussian_inputs_genecp_directory, "opt_genecp.com" ) return gaussian_opt_genecp_input
[docs] @pytest.fixture() def modred_gen_inputfile(gaussian_inputs_genecp_directory): return os.path.join(gaussian_inputs_genecp_directory, "modred_gen.com")
[docs] @pytest.fixture() def modred_genecp_inputfile(gaussian_inputs_genecp_directory): return os.path.join(gaussian_inputs_genecp_directory, "modred_genecp.com")
[docs] @pytest.fixture() def modred_genecp_custom_solvent_inputfile(gaussian_inputs_genecp_directory): return os.path.join( gaussian_inputs_genecp_directory, "modred_genecp_custom_solvent.com" )
# Gaussian input files for link jobs # Gaussian output files for link jobs
[docs] @pytest.fixture() def gaussian_qmmm_input_test_directory(gaussian_inputs_test_directory): return os.path.join(gaussian_inputs_test_directory, "qmmm")
[docs] @pytest.fixture() def gaussian_qmmm_inputfile_2layer(gaussian_qmmm_input_test_directory): return os.path.join(gaussian_qmmm_input_test_directory, "CH3CH3.com")
[docs] @pytest.fixture() def gaussian_qmmm_inputfile_3layer(gaussian_qmmm_input_test_directory): return os.path.join(gaussian_qmmm_input_test_directory, "CH3COOH.com")
# Gaussian output files
[docs] @pytest.fixture() def gaussian_outputs_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "outputs")
[docs] @pytest.fixture() def gaussian_singlet_opt_outfile(gaussian_outputs_test_directory): gaussian_singlet_opt_output = os.path.join( gaussian_outputs_test_directory, "nhc_neutral_singlet.log" ) return gaussian_singlet_opt_output
[docs] @pytest.fixture() def gaussian_triplet_opt_outfile(gaussian_outputs_test_directory): gaussian_triplet_opt_outfile = os.path.join( gaussian_outputs_test_directory, "iron_neutral_triplet.log" ) return gaussian_triplet_opt_outfile
[docs] @pytest.fixture() def gaussian_quintet_opt_outfile(gaussian_outputs_test_directory): gaussian_quintet_opt_outfile = os.path.join( gaussian_outputs_test_directory, "iron_neutral_quintet.log" ) return gaussian_quintet_opt_outfile
# Gaussian output files for genecp
[docs] @pytest.fixture() def gaussian_ts_genecp_outfile(gaussian_outputs_test_directory): gaussian_ts_genecp_output = os.path.join( gaussian_outputs_test_directory, "pd_genecp_ts.log" ) return gaussian_ts_genecp_output
[docs] @pytest.fixture() def gaussian_pd_insertion_ts_r_outfile(gaussian_outputs_test_directory): return os.path.join( gaussian_outputs_test_directory, "Pd_insertion_ts_r.log" )
# Gaussian output file for frozen coordinates
[docs] @pytest.fixture() def gaussian_frozen_opt_outfile(gaussian_outputs_test_directory): gaussian_frozen_opt_outfile = os.path.join( gaussian_outputs_test_directory, "frozen_coordinates_opt.log" ) return gaussian_frozen_opt_outfile
# Gaussian output file for modred
[docs] @pytest.fixture() def gaussian_failed_modred_outfile(gaussian_outputs_test_directory): gaussian_modred_outfile = os.path.join( gaussian_outputs_test_directory, "cage_free_failed_modred.log" ) return gaussian_modred_outfile
# Gaussian output for scan
[docs] @pytest.fixture() def gaussian_failed_scan_outfile(gaussian_outputs_test_directory): gaussian_scan_outfile = os.path.join( gaussian_outputs_test_directory, "cationic_failed_scan.log" ) return gaussian_scan_outfile
# Gaussian output file for Hirshfeld charges
[docs] @pytest.fixture() def gaussian_hirshfeld_outfile(gaussian_outputs_test_directory): gaussian_hirshfeld_outfile = os.path.join( gaussian_outputs_test_directory, "oxetane_hirshfeld_sp_smd_n_n-DiMethylFormamide.log", ) return gaussian_hirshfeld_outfile
[docs] @pytest.fixture() def gaussian_rc_hirshfeld_outfile(gaussian_outputs_test_directory): gaussian_hirshfeld_outfile = os.path.join( gaussian_outputs_test_directory, "oxetane_rc_hirshfeld_sp_smd_n_n-DiMethylFormamide.log", ) return gaussian_hirshfeld_outfile
[docs] @pytest.fixture() def gaussian_ozone_opt_outfile(gaussian_outputs_test_directory): gaussian_ozone_opt_outfile = os.path.join( gaussian_outputs_test_directory, "ozone.log" ) return gaussian_ozone_opt_outfile
[docs] @pytest.fixture() def gaussian_co2_opt_outfile(gaussian_outputs_test_directory): gaussian_co2_opt_outfile = os.path.join( gaussian_outputs_test_directory, "co2.log" ) return gaussian_co2_opt_outfile
[docs] @pytest.fixture() def gaussian_he_opt_outfile(gaussian_outputs_test_directory): gaussian_he_opt_outfile = os.path.join( gaussian_outputs_test_directory, "he.log" ) return gaussian_he_opt_outfile
[docs] @pytest.fixture() def gaussian_acetone_opt_outfile(gaussian_outputs_test_directory): gaussian_acetone_opt_outfile = os.path.join( gaussian_outputs_test_directory, "acetone.log" ) return gaussian_acetone_opt_outfile
[docs] @pytest.fixture() def gaussian_benzene_opt_outfile(gaussian_outputs_test_directory): gaussian_benzene_opt_outfile = os.path.join( gaussian_outputs_test_directory, "benzene.log" ) return gaussian_benzene_opt_outfile
# Gaussian output file for MP2 calculations
[docs] @pytest.fixture() def gaussian_mp2_outputfile(gaussian_outputs_test_directory): gaussian_mp2_outfile = os.path.join( gaussian_outputs_test_directory, "water_mp2.log" ) return gaussian_mp2_outfile
# Gaussian output file for (failed) ONIOM calculations
[docs] @pytest.fixture() def gaussian_oniom_outputfile(gaussian_outputs_test_directory): gaussian_oniom_outfile = os.path.join( gaussian_outputs_test_directory, "failed_oniom_b3lypd3_in_uff.log" ) return gaussian_oniom_outfile
# Gaussian pbc input files
[docs] @pytest.fixture() def gaussian_pbc_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "pbc")
[docs] @pytest.fixture() def gaussian_pbc_inputs_test_directory(gaussian_pbc_test_directory): return os.path.join(gaussian_pbc_test_directory, "com")
[docs] @pytest.fixture() def gaussian_pbc_1d_inputfile(gaussian_pbc_inputs_test_directory): gaussian_pbc_1d_inputfile = os.path.join( gaussian_pbc_inputs_test_directory, "neoprene_1d.com" ) return gaussian_pbc_1d_inputfile
# Gaussian PBC output files
[docs] @pytest.fixture() def gaussian_pbc_outputs_test_directory(gaussian_pbc_test_directory): return os.path.join(gaussian_pbc_test_directory, "log")
[docs] @pytest.fixture() def gaussian_pbc_2d_outputfile(gaussian_pbc_outputs_test_directory): gaussian_pbc_2d_outputfile = os.path.join( gaussian_pbc_outputs_test_directory, "graphite_2d_opt.log" ) return gaussian_pbc_2d_outputfile
[docs] @pytest.fixture() def gaussian_pbc_3d_outputfile(gaussian_pbc_outputs_test_directory): gaussian_pbc_3d_outputfile = os.path.join( gaussian_pbc_outputs_test_directory, "gallium_arsenide_3d.log" ) return gaussian_pbc_3d_outputfile
# text path and associated files
[docs] @pytest.fixture() def txt_path(gaussian_test_directory): test_txt_path = os.path.join(gaussian_test_directory, "text") return os.path.abspath(test_txt_path)
[docs] @pytest.fixture() def reference_genecp_txt_file_from_api(txt_path): return os.path.join(txt_path, "genecp_txt_from_api.txt")
[docs] @pytest.fixture() def genecp_txt_file_from_web(txt_path): return os.path.join(txt_path, "test_genecp.txt")
[docs] @pytest.fixture() def gen_txt_file_from_web(txt_path): return os.path.join(txt_path, "test_gen.txt")
[docs] @pytest.fixture() def smd_TBME_solvent_parameters_txt_file(txt_path): return os.path.join(txt_path, "smd_TBME.txt")
[docs] @pytest.fixture() def Ni_def2tzvp_PCHOSi_svp_txt_file(txt_path): return os.path.join(txt_path, "Ni_def2tzvp_PCHOSi_svp.txt")
# Gaussian output file from TDDFT
[docs] @pytest.fixture() def tddft_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "tddft")
[docs] @pytest.fixture() def td_outputfile(tddft_test_directory): td_outputfile = os.path.join( tddft_test_directory, "tddft_r1s50_gas_radical_anion.log" ) return td_outputfile
# Gaussian cube files
[docs] @pytest.fixture() def cube_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "cubes")
[docs] @pytest.fixture() def spin_cube_file(cube_test_directory): spin_cube_file = os.path.join(cube_test_directory, "n2_dens.cube") return spin_cube_file
[docs] @pytest.fixture() def esp_cube_file(cube_test_directory): esp_cube_file = os.path.join(cube_test_directory, "n2_esp.cube") return esp_cube_file
# gaussian yaml files
[docs] @pytest.fixture() def gaussian_yaml_settings_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "project_yaml")
[docs] @pytest.fixture() def gaussian_yaml_settings_defaults(gaussian_yaml_settings_directory): return os.path.join(gaussian_yaml_settings_directory, "defaults.yaml")
[docs] @pytest.fixture() def gaussian_yaml_settings_gas_solv(gaussian_yaml_settings_directory): return os.path.join(gaussian_yaml_settings_directory, "gas_solv.yaml")
[docs] @pytest.fixture() def gaussian_yaml_settings_gas_solv_project_name( gaussian_yaml_settings_directory, ): return os.path.join(gaussian_yaml_settings_directory, "gas_solv")
[docs] @pytest.fixture() def gaussian_yaml_settings_solv(gaussian_yaml_settings_directory): return os.path.join(gaussian_yaml_settings_directory, "solv.yaml")
[docs] @pytest.fixture() def gaussian_yaml_settings_qmmm(gaussian_yaml_settings_directory): return os.path.join(gaussian_yaml_settings_directory, "qmmm.yaml")
[docs] @pytest.fixture() def gaussian_yaml_settings_qmmm_project_name( gaussian_yaml_settings_directory, ): return os.path.join(gaussian_yaml_settings_directory, "qmmm")
# gaussian written files
[docs] @pytest.fixture() def gaussian_written_files_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "written_files")
[docs] @pytest.fixture() def gaussian_written_opt_file(gaussian_written_files_directory): return os.path.join(gaussian_written_files_directory, "gaussian_opt.com")
[docs] @pytest.fixture() def gaussian_written_pm6_opt_file(gaussian_written_files_directory): return os.path.join( gaussian_written_files_directory, "gaussian_pm6_opt.com" )
[docs] @pytest.fixture() def gaussian_written_opt_file_with_route(gaussian_written_files_directory): return os.path.join( gaussian_written_files_directory, "gaussian_opt_with_route.com" )
[docs] @pytest.fixture() def gaussian_written_modred_file(gaussian_written_files_directory): return os.path.join( gaussian_written_files_directory, "gaussian_modred.com" )
[docs] @pytest.fixture() def gaussian_written_scan_single_degree_of_freedom_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_scan_single_degree_of_freedom.com", )
[docs] @pytest.fixture() def gaussian_written_scan_multiple_degrees_of_freedom_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_scan_multiple_degrees_of_freedom.com", )
[docs] @pytest.fixture() def gaussian_written_scan_multiple_degrees_of_freedom_with_constraints_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_scan_multiple_degrees_of_freedom_with_constraints.com", )
[docs] @pytest.fixture() def gaussian_written_ts_file(gaussian_written_files_directory): return os.path.join(gaussian_written_files_directory, "gaussian_ts.com")
[docs] @pytest.fixture() def gaussian_written_qmmm_file(gaussian_written_files_directory): return os.path.join(gaussian_written_files_directory, "gaussian_qmmm.com")
[docs] @pytest.fixture() def gaussian_written_qmmm_log_file(gaussian_written_files_directory): return os.path.join( gaussian_written_files_directory, "gaussian_qmmm_from_log.com" )
[docs] @pytest.fixture() def gaussian_written_ts_from_nhc_singlet_log_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_ts_from_log.com" )
[docs] @pytest.fixture() def gaussian_written_sp_from_nhc_singlet_log_with_solvent_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_sp_from_log_with_solvent.com", )
[docs] @pytest.fixture() def gaussian_written_sp_from_nhc_singlet_log_with_custom_solvent_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_sp_from_log_with_custom_solvent.com", )
[docs] @pytest.fixture() def gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_sp_from_log_with_custom_basis.com", )
[docs] @pytest.fixture() def gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_from_api_file( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_sp_from_log_with_custom_basis_from_api.com", )
[docs] @pytest.fixture() def gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_from_api_file_v2( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_sp_from_log_with_custom_basis_from_api_v2.com", )
[docs] @pytest.fixture() def gaussian_modred_with_custom_basis_for_all_atoms_from_api( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "gaussian_modred_with_custom_basis_for_all_atoms_from_api.com", )
[docs] @pytest.fixture() def gaussian_written_opt_from_graphite_2d_pbc_log( gaussian_written_files_directory, ): return os.path.join( gaussian_written_files_directory, "graphite_2d_opt_from_log.com" )
[docs] @pytest.fixture() def qmmm_written_xyz_file(gaussian_written_files_directory): return os.path.join(gaussian_written_files_directory, "qmmm_written.xyz")
[docs] @pytest.fixture() def qmmm_written_xyz_only_file(gaussian_written_files_directory): return os.path.join( gaussian_written_files_directory, "qmmm_written_xyz_only.xyz" )
# Gaussian folder for thermochemistry analysis
[docs] @pytest.fixture() def gaussian_thermochem_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "thermochem")
[docs] @pytest.fixture() def gaussian_co2_pressure1p5_outfile(gaussian_thermochem_test_directory): gaussian_co2_pressure1p5_outfile = os.path.join( gaussian_thermochem_test_directory, "co2_pressure1p5.log" ) return gaussian_co2_pressure1p5_outfile
[docs] @pytest.fixture() def gaussian_co2_pressure3_outfile(gaussian_thermochem_test_directory): gaussian_co2_pressure3_outfile = os.path.join( gaussian_thermochem_test_directory, "co2_pressure3.log" ) return gaussian_co2_pressure3_outfile
# Gaussian folder for boltzmann weighting
[docs] @pytest.fixture() def gaussian_boltzmann_test_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "boltzmann")
[docs] @pytest.fixture() def gaussian_conformer1_outfile(gaussian_boltzmann_test_directory): gaussian_conformer1_outfile = os.path.join( gaussian_boltzmann_test_directory, "udc3_mCF3_monomer_c1.log" ) return gaussian_conformer1_outfile
[docs] @pytest.fixture() def gaussian_conformer2_outfile(gaussian_boltzmann_test_directory): gaussian_conformer2_outfile = os.path.join( gaussian_boltzmann_test_directory, "udc3_mCF3_monomer_c4.log" ) return gaussian_conformer2_outfile
# text path and associated files
[docs] @pytest.fixture() def text_directory(gaussian_test_directory): return os.path.join(gaussian_test_directory, "text")
[docs] @pytest.fixture() def genecp_text_file_from_web(text_directory): return os.path.join(text_directory, "test_genecp.txt")
[docs] @pytest.fixture() def gen_text_file_from_web(text_directory): return os.path.join(txt_path, "test_gen.txt")
[docs] @pytest.fixture() def smd_TBME_solvent_parameters_text_file(txt_path): return os.path.join(txt_path, "smd_TBME.txt")
[docs] @pytest.fixture() def Ni_def2tzvp_PCHOSi_svp_text_file(txt_path): return os.path.join(txt_path, "Ni_def2tzvp_PCHOSi_svp.txt")
############ Orca Fixtures ################## # master orca test directory
[docs] @pytest.fixture() def orca_test_directory(test_data_directory): return os.path.join(test_data_directory, "ORCATests")
# orca input files path and associated files
[docs] @pytest.fixture() def inpfile_path(orca_test_directory): test_inpfile_path = os.path.join(orca_test_directory, "inputs") return os.path.abspath(test_inpfile_path)
# specific input files
[docs] @pytest.fixture() def water_sp_input_path(inpfile_path): return os.path.join(inpfile_path, "water_sp.inp")
[docs] @pytest.fixture() def water_opt_input_path(inpfile_path): return os.path.join(inpfile_path, "water_opt.inp")
[docs] @pytest.fixture() def sdf_file(test_data_directory): return os.path.join( test_data_directory, "AtomsWrapperTest", "structure.sdf" )
# orca input files path and associated files
[docs] @pytest.fixture() def orca_inputs_directory(orca_test_directory): orca_inputs_directory = os.path.join(orca_test_directory, "inputs") return os.path.abspath(orca_inputs_directory)
[docs] @pytest.fixture() def orca_inputs_xyz_directory(orca_inputs_directory): """Returns the absolute path to the orca inputs that specifies xyz files.""" orca_inputs_xyz_directory = os.path.join(orca_inputs_directory, "xyz") return os.path.abspath(orca_inputs_xyz_directory)
[docs] @pytest.fixture() def orca_input_nebts_file(orca_inputs_xyz_directory): """Returns the absolute path to the orca input file for NEB with TS optimization.""" return os.path.join(orca_inputs_xyz_directory, "neb_TS_rot1.inp")
[docs] @pytest.fixture() def orca_input_nebts_reactant_xyz_file(orca_inputs_xyz_directory): """Returns the absolute path to the orca input file for NEB with TS optimization.""" return os.path.join(orca_inputs_xyz_directory, "R-1a_opt.xyz")
[docs] @pytest.fixture() def orca_input_nebts_product_xyz_file(orca_inputs_xyz_directory): """Returns the absolute path to the orca input file for NEB with TS optimization.""" return os.path.join(orca_inputs_xyz_directory, "S-1a_opt.xyz")
[docs] @pytest.fixture() def orca_input_nebts_ts_xyz_file(orca_inputs_xyz_directory): """Returns the absolute path to the orca input file for NEB with TS optimization.""" return os.path.join(orca_inputs_xyz_directory, "TS_rot1.xyz")
[docs] @pytest.fixture() def orca_dias_directory(orca_test_directory): orca_dias_directory = os.path.join(orca_test_directory, "dias") return os.path.abspath(orca_dias_directory)
[docs] @pytest.fixture() def water_sp_gas_input_path(orca_inputs_directory): return os.path.join(orca_inputs_directory, "water_dlpno_ccsdt_sp.inp")
[docs] @pytest.fixture() def water_sp_solv_input_path(orca_inputs_directory): return os.path.join(orca_inputs_directory, "water_dlpno_ccsdt_sp_solv.inp")
[docs] @pytest.fixture() def orca_epr_solv(orca_inputs_directory): return os.path.join(orca_inputs_directory, "ORCA_Test_0829.inp")
[docs] @pytest.fixture() def orca_faulty_solv(orca_inputs_directory): return os.path.join(orca_inputs_directory, "faulty_solv.inp")
[docs] @pytest.fixture() def orca_qmmm_input_file(orca_inputs_directory): return os.path.join(orca_inputs_directory, "dna_qmmm.inp")
[docs] @pytest.fixture() def orca_outputs_directory(orca_test_directory): orca_outputs_directory = os.path.join(orca_test_directory, "outputs") return os.path.abspath(orca_outputs_directory)
[docs] @pytest.fixture() def water_sp_gas_path(orca_outputs_directory): return os.path.join(orca_outputs_directory, "water_dlpno_ccsdt_sp.out")
[docs] @pytest.fixture() def water_sp_solv_path(orca_outputs_directory): return os.path.join( orca_outputs_directory, "water_dlpno_ccsdt_sp_solv.out" )
[docs] @pytest.fixture() def water_output_gas_path(orca_outputs_directory): return os.path.join(orca_outputs_directory, "water_opt.out")
[docs] @pytest.fixture() def orca_he_output_freq(orca_outputs_directory): return os.path.join(orca_outputs_directory, "He_freq.out")
[docs] @pytest.fixture() def orca_co2_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "CO2.out")
[docs] @pytest.fixture() def orca_sn2_ts_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "sn2_ts.out")
[docs] @pytest.fixture() def dlpno_ccsdt_sp_full_print(orca_outputs_directory): return os.path.join( orca_outputs_directory, "dlpno_ccsdt_singlepoint_neutral_in_cpcm.out" )
[docs] @pytest.fixture() def hirshfeld_full_print(orca_outputs_directory): return os.path.join( orca_outputs_directory, "udc3_ts1_c15_sp_hirshfeld.out" )
[docs] @pytest.fixture() def fe2_singlet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe2_singlet.out")
[docs] @pytest.fixture() def fe2_triplet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe2_triplet.out")
[docs] @pytest.fixture() def fe2_quintet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe2_quintet.out")
[docs] @pytest.fixture() def fe3_doublet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe3_doublet.out")
[docs] @pytest.fixture() def fe3_quartet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe3_quartet.out")
[docs] @pytest.fixture() def fe3_sextet_output(orca_outputs_directory): return os.path.join(orca_outputs_directory, "fe3_sextet.out")
[docs] @pytest.fixture() def water_engrad_path(orca_outputs_directory): return os.path.join(orca_outputs_directory, "water_opt.engrad")
[docs] @pytest.fixture() def orca_fixed_atoms(orca_outputs_directory): return os.path.join(orca_outputs_directory, "phenol_fixed_atoms.out")
[docs] @pytest.fixture() def orca_fixed_bonds_and_angles(orca_outputs_directory): return os.path.join( orca_outputs_directory, "phenol_fixed_bond_and_angles.out" )
[docs] @pytest.fixture() def orca_fixed_dihedral(orca_outputs_directory): return os.path.join( orca_outputs_directory, "phenylalanine_fixed_dihedral.out" )
[docs] @pytest.fixture() def orca_two_layer_qmmmm_output_file(orca_outputs_directory): return os.path.join(orca_outputs_directory, "methanol_ethane_qmmm.out")
[docs] @pytest.fixture() def orca_neb_output_file(orca_outputs_directory): return os.path.join(orca_outputs_directory, "neb_R-TS1-Si.out")
[docs] @pytest.fixture() def orca_errors_directory(orca_test_directory): orca_errors_directory = os.path.join(orca_test_directory, "error_files") return os.path.abspath(orca_errors_directory)
[docs] @pytest.fixture() def gtoint_errfile(orca_errors_directory): return os.path.join(orca_errors_directory, "GTOInt_error.out")
# orca written files
[docs] @pytest.fixture() def orca_written_files_directory(orca_test_directory): orca_written_files = os.path.join(orca_test_directory, "written_files") return orca_written_files
[docs] @pytest.fixture() def orca_written_opt_file(orca_written_files_directory): return os.path.join(orca_written_files_directory, "orca_opt.inp")
[docs] @pytest.fixture() def orca_written_opt_file_with_route(orca_written_files_directory): return os.path.join( orca_written_files_directory, "orca_opt_with_route.inp" )
[docs] @pytest.fixture() def orca_written_modred_file(orca_written_files_directory): return os.path.join(orca_written_files_directory, "orca_modred.inp")
[docs] @pytest.fixture() def orca_written_scan_single_degree_of_freedom_file( orca_written_files_directory, ): return os.path.join( orca_written_files_directory, "orca_scan_single_degree_of_freedom.inp" )
[docs] @pytest.fixture() def orca_written_scan_multiple_degrees_of_freedom_file( orca_written_files_directory, ): return os.path.join( orca_written_files_directory, "orca_scan_multiple_degrees_of_freedom.inp", )
[docs] @pytest.fixture() def orca_written_scan_multiple_degrees_of_freedom_with_constraints_file( orca_written_files_directory, ): return os.path.join( orca_written_files_directory, "orca_scan_multiple_degrees_of_freedom_with_constraints.inp", )
[docs] @pytest.fixture() def orca_written_ts_file(orca_written_files_directory): return os.path.join(orca_written_files_directory, "orca_ts.inp")
[docs] @pytest.fixture() def orca_written_ts_from_nhc_singlet_log_file(orca_written_files_directory): return os.path.join(orca_written_files_directory, "orca_ts_from_log.inp")
[docs] @pytest.fixture() def orca_written_sp_from_nhc_singlet_log_with_solvent_file( orca_written_files_directory, ): return os.path.join( orca_written_files_directory, "orca_sp_from_log_with_solvent.inp" )
[docs] @pytest.fixture() def orca_written_he_monoatomic_opt_file(orca_written_files_directory): return os.path.join( orca_written_files_directory, "orca_he_monoatomic_opt.inp" )
[docs] @pytest.fixture() def orca_written_neb_file(orca_written_files_directory): return os.path.join(orca_written_files_directory, "orca_neb_TS_rot1.inp")
# orca yaml files
[docs] @pytest.fixture() def orca_yaml_settings_directory(orca_test_directory): return os.path.join(orca_test_directory, "project_yaml")
[docs] @pytest.fixture() def orca_yaml_settings_defaults(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "defaults.yaml")
[docs] @pytest.fixture() def orca_yaml_settings_gas_solv(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "gas_solv.yaml")
[docs] @pytest.fixture() def orca_yaml_settings_solv(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "solv.yaml")
[docs] @pytest.fixture() def orca_yaml_settings_gas_solv_project_name(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "gas_solv")
[docs] @pytest.fixture() def orca_yaml_settings_solv_project_name(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "solv")
[docs] @pytest.fixture() def orca_yaml_settings_orca_project_name(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "orca")
[docs] @pytest.fixture() def orca_yaml_settings_neb_project_name(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "neb")
[docs] @pytest.fixture() def orca_yaml_settings_custom_solv_project_name(orca_yaml_settings_directory): return os.path.join(orca_yaml_settings_directory, "custom_solv")
[docs] @pytest.fixture() def orca_yaml_settings_custom_solv_cosmors_project_name( orca_yaml_settings_directory, ): return os.path.join(orca_yaml_settings_directory, "custom_solv_cosmors")
# test for structure.py
[docs] @pytest.fixture() def structure_test_directory(test_data_directory): return os.path.join(test_data_directory, "StructuresTests")
[docs] @pytest.fixture() def xyz_directory(structure_test_directory): return os.path.join(structure_test_directory, "xyz")
[docs] @pytest.fixture() def ts_conformers_log_directory(structure_test_directory): """Directory containing TS conformer log files (ch_1c_para_c1.log to c5.log).""" return os.path.join(structure_test_directory, "conformers", "log")
[docs] @pytest.fixture() def single_molecule_xyz_file(xyz_directory): return os.path.join(xyz_directory, "crest_best.xyz")
[docs] @pytest.fixture() def multiple_molecules_xyz_file(xyz_directory): return os.path.join(xyz_directory, "crest_conformers.xyz")
[docs] @pytest.fixture() def two_rotated_molecules_xyz_file(xyz_directory): return os.path.join(xyz_directory, "two_rotated_molecules.xyz")
[docs] @pytest.fixture() def xtb_optimized_xyz_file(xyz_directory): return os.path.join(xyz_directory, "ts_xtbopt.xyz")
[docs] @pytest.fixture() def chemsmart_generated_xyz_file(xyz_directory): return os.path.join(xyz_directory, "frozen_coordinates_opt.xyz")
[docs] @pytest.fixture() def extended_xyz_file(xyz_directory): return os.path.join(xyz_directory, "crystal.extxyz")
[docs] @pytest.fixture() def dna_hybrid_visualized_xyz_file(xyz_directory): return os.path.join(xyz_directory, "dna_hybrid.xyz")
[docs] @pytest.fixture() def chemdraw_directory(structure_test_directory): return os.path.join(structure_test_directory, "chemdraw")
[docs] @pytest.fixture() def single_molecule_cdxml_file_benzene(chemdraw_directory): return os.path.join(chemdraw_directory, "benzene.cdxml")
[docs] @pytest.fixture() def single_molecule_cdxml_file_methane(chemdraw_directory): return os.path.join(chemdraw_directory, "methane.cdxml")
[docs] @pytest.fixture() def multi_molecule_cdxml_file(chemdraw_directory): return os.path.join(chemdraw_directory, "two_molecules.cdxml")
[docs] @pytest.fixture() def single_molecule_cdx_file_imidazole(chemdraw_directory): return os.path.join(chemdraw_directory, "imidazole.cdx")
[docs] @pytest.fixture() def complex_molecule_cdxml_file(chemdraw_directory): return os.path.join(chemdraw_directory, "complex_molecule.cdxml")
[docs] @pytest.fixture() def chemdraw_expected_directory(chemdraw_directory): return os.path.join(chemdraw_directory, "expected")
[docs] @pytest.fixture() def expected_methane_xyz(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "methane.xyz")
[docs] @pytest.fixture() def expected_benzene_xyz(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "benzene.xyz")
[docs] @pytest.fixture() def expected_imidazole_xyz(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "imidazole.xyz")
[docs] @pytest.fixture() def expected_two_molecules_1_xyz(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "two_molecules_1.xyz")
[docs] @pytest.fixture() def expected_two_molecules_2_xyz(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "two_molecules_2.xyz")
[docs] @pytest.fixture() def expected_benzene_com(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "benzene.com")
[docs] @pytest.fixture() def expected_methane_com(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "methane.com")
[docs] @pytest.fixture() def expected_two_molecules_1_com(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "two_molecules_1.com")
[docs] @pytest.fixture() def expected_two_molecules_2_com(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "two_molecules_2.com")
[docs] @pytest.fixture() def expected_complex_molecule_com(chemdraw_expected_directory): return os.path.join(chemdraw_expected_directory, "complex_molecule.com")
[docs] @pytest.fixture() def metal_ligand_molecules_cdxml_file(chemdraw_directory): return os.path.join(chemdraw_directory, "metal_ligands.cdxml")
[docs] @pytest.fixture() def utils_test_directory(test_data_directory): return os.path.join(test_data_directory, "YAMLTests")
[docs] @pytest.fixture() def server_yaml_file(utils_test_directory): return os.path.join(utils_test_directory, "server.yaml")
### Server and JobRunner fixtures
[docs] @pytest.fixture() def pbs_server(server_yaml_file): return Server.from_yaml(server_yaml_file)
[docs] @pytest.fixture() def gaussian_jobrunner_no_scratch(pbs_server): return FakeGaussianJobRunner(server=pbs_server, scratch=False, fake=True)
[docs] @pytest.fixture() def gaussian_jobrunner_scratch(tmpdir, pbs_server): return FakeGaussianJobRunner( scratch_dir=tmpdir, server=pbs_server, scratch=True, fake=True )
[docs] @pytest.fixture() def orca_jobrunner_no_scratch(pbs_server): return FakeORCAJobRunner(server=pbs_server, scratch=False, fake=True)
[docs] @pytest.fixture() def orca_jobrunner_scratch(tmpdir, pbs_server): return FakeORCAJobRunner( scratch_dir=tmpdir, server=pbs_server, scratch=True, fake=True )
[docs] @pytest.fixture() def pymol_visualization_jobrunner(pbs_server): return PyMOLVisualizationJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def pymol_hybrid_visualization_jobrunner(pbs_server): return PyMOLHybridVisualizationJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def pymol_movie_jobrunner(pbs_server): return PyMOLMovieJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def nciplot_jobrunner_no_scratch(pbs_server): return FakeNCIPLOTJobRunner(server=pbs_server, scratch=False, fake=True)
[docs] @pytest.fixture() def nciplot_jobrunner_scratch(tmpdir, pbs_server): return FakeNCIPLOTJobRunner( scratch_dir=tmpdir, server=pbs_server, scratch=True, fake=True )
[docs] @pytest.fixture() def pymol_align_jobrunner(pbs_server): return PyMOLAlignJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def pymol_ircmovie_jobrunner(pbs_server): return PyMOLIRCMovieJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def pymol_mo_jobrunner(pbs_server): return PyMOLMOJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def iterate_jobrunner(pbs_server): return IterateJobRunner(server=pbs_server, scratch=False)
[docs] @pytest.fixture() def fake_iterate_jobrunner(pbs_server): return IterateJobRunner(server=pbs_server, scratch=False, fake=True)
## pytest fixtures for molecules
[docs] @pytest.fixture() def methanol_molecule(): symbols = ["C", "O", "H", "H", "H", "H"] coords = np.array( [ [0.000000, 0.000000, 0.000000], # C [1.430000, 0.000000, 0.000000], # O [1.109545, 0.904936, 0.000000], # H (hydroxyl) [-0.363849, 1.027479, 0.000000], # H [-0.363849, -0.513740, 0.889823], # H [-0.363849, -0.513740, -0.889823], # H ], dtype=float, ) methanol = Molecule(symbols=symbols, positions=coords) return methanol
[docs] @pytest.fixture() def ethanol_molecule(): symbols = ["O", "C", "C", "H", "H", "H", "H", "H", "H"] coords = np.array( [ [-1.1712, 0.2997, 0.0000], [-0.0463, -0.5665, 0.0000], [1.2175, 0.2668, 0.0000], [-0.0958, -1.2120, 0.8819], [-0.0952, -1.1938, -0.8946], [2.1050, -0.3720, -0.0177], [1.2426, 0.9307, -0.8704], [1.2616, 0.9052, 0.8886], [-1.1291, 0.8364, 0.8099], ], dtype=float, ) ethanol = Molecule(symbols=symbols, positions=coords) return ethanol
[docs] @pytest.fixture() def methanol_molecules(methanol_molecule): methanol = methanol_molecule # rotated methanol ase_atoms = methanol.to_ase() ase_atoms.rotate(90, [0, 0, 1]) methanol_rot1 = Molecule.from_ase_atoms(ase_atoms) ase_atoms = methanol.to_ase() ase_atoms.rotate(20, [1, 1, 1]) methanol_rot2 = Molecule.from_ase_atoms(ase_atoms) methanol_molecules = [methanol, methanol_rot1, methanol_rot2] return methanol_molecules
[docs] @pytest.fixture() def methyl3hexane_molecule(): symbols = [ "C", "C", "C", "C", "C", "C", "C", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", ] coords = np.array( [ [0.828, -0.5939, -0.4105], [-0.6074, -0.1292, -0.7341], [1.6188, 0.3738, 0.4896], [-1.5335, 0.0189, 0.4761], [0.8379, -1.9975, 0.2043], [1.7539, 1.7749, -0.0888], [-2.8977, 0.553, 0.0634], [1.3601, -0.6621, -1.3694], [-1.0561, -0.849, -1.4317], [-0.5655, 0.8214, -1.2791], [2.6287, -0.0297, 0.6378], [1.1655, 0.4353, 1.4856], [-1.0999, 0.707, 1.2088], [-1.6692, -0.9475, 0.973], [1.8635, -2.3744, 0.2836], [0.4049, -2.004, 1.2096], [0.2737, -2.7005, -0.4174], [2.1704, 1.7451, -1.1005], [2.4243, 2.3747, 0.5353], [0.7895, 2.2899, -0.1235], [-3.384, -0.1214, -0.6486], [-2.8085, 1.5396, -0.4023], [-3.5477, 0.6486, 0.9389], ] ) methyl3hexane = Molecule(symbols=symbols, positions=coords) return methyl3hexane
[docs] @pytest.fixture() def tetrahydrofuran_molecule(): symbols = ["O", "C", "C", "C", "C", "H", "H", "H", "H", "H", "H", "H", "H"] coords = np.array( [ [1.2328, -0.0005, 0.0000], [-1.0107, -0.7202, -0.2205], [-1.0102, 0.7210, 0.2205], [0.3936, -1.1560, 0.1374], [0.3946, 1.1557, -0.1375], [-1.7823, -1.3279, 0.2593], [-1.1544, -0.7757, -1.3060], [-1.7812, 1.3292, -0.2593], [-1.1537, 0.7766, 1.3061], [0.4518, -1.4889, 1.1792], [0.7622, -1.9589, -0.5071], [0.4532, 1.4885, -1.1793], [0.7639, 1.9583, 0.5070], ] ) thf_molecule = Molecule(symbols=symbols, positions=coords) return thf_molecule
[docs] @pytest.fixture() def constrained_atoms(): """Fixture to create a simple Ar2 dimer with constraints.""" from ase import Atoms from ase.calculators.lj import LennardJones from ase.constraints import FixAtoms, FixBondLength # Simple Ar2 dimer with a reasonable separation r0 = 3.5 # Å atoms = Atoms( "Ar2", positions=[(0.0, 0.0, 0.0), (r0, 0.0, 0.0)], pbc=False ) # Light-weight calculator for tests atoms.calc = LennardJones() # defaults are fine for unit tests # Constraints: # - Fix the first atom in space # - Keep the Ar–Ar bond length fixed at its initial value constraints = [ FixAtoms(indices=[0]), FixBondLength(0, 1), ] # set the constraints on the Atoms object atoms.set_constraint(constraint=constraints) # set velocity atoms.set_velocities([[0, 0, 0], [0, 0, 0]]) # Set zero velocities return atoms
[docs] @pytest.fixture() def methanol_and_ethanol(methanol_molecule, ethanol_molecule): # molecules for testing # methanol methanol = methanol_molecule # ethanol ethanol = ethanol_molecule methanol_and_ethanol = [methanol, ethanol] return methanol_and_ethanol
[docs] @pytest.fixture() def conformers_from_rdkit(): """Generate multiple conformers for a complex molecule using RDKit.""" smiles = "O=C([O-])CCn1c(=O)c(=O)[nH]c2cc([N+](=O)[O-])c(-n3ccc(C=NOCc4ccccc4)c3)cc21" mol = Chem.MolFromSmiles(smiles) mol = Chem.AddHs(mol) # Generate 3D conformers ps = rdDistGeom.ETKDGv3() ps.randomSeed = 0xD06F00D ps.numThreads = 10 conf_ids = rdDistGeom.EmbedMultipleConfs(mol, numConfs=300, params=ps) # Ensure each conformer is extracted into its own unique RDKit Mol object conformers = [] for conf_id in conf_ids: single_conf_mol = Chem.Mol(mol) # Copy molecule structure single_conf_mol.RemoveAllConformers() # Remove all existing conformers single_conf_mol.AddConformer( mol.GetConformer(conf_id), assignId=True ) # Add only this conformer conformers.append(single_conf_mol) # Verify that each conformer contains exactly one conformer for conf in conformers: assert ( conf.GetNumConformers() == 1 ), "Each conformer should contain exactly one conformer." # Convert to Molecule instances conformers_from_rdkit = [ Molecule.from_rdkit_mol(conf) for conf in conformers ] return conformers_from_rdkit
[docs] @pytest.fixture() def io_test_directory(test_data_directory): return os.path.join(test_data_directory, "IOTests")
[docs] @pytest.fixture() def excel_file(io_test_directory): return os.path.join(io_test_directory, "test.xlsx")
[docs] @pytest.fixture() def constrained_pbc_db_file(io_test_directory): """Fixture of a .db file containing constrained PBC database from heterogeneous catalysis.""" return os.path.join( io_test_directory, "heterogenous_pbc_constraints_5images.db" )
## fixtures for mixins
[docs] @pytest.fixture() def temp_text_file(): with tempfile.NamedTemporaryFile("w+", delete=False) as tmp: tmp.write("Line1\nLine2\n") tmp_name = tmp.name yield tmp_name os.remove(tmp_name)
[docs] @pytest.fixture() def dummy_yaml_file(): class DummyYAMLFile: def __init__(self): self.filename = "dummy.yaml" self.content_lines_string = yaml.dump( {"key1": "value1", "key2": "value2"} ) @property def yaml_contents_dict(self): return yaml.safe_load(self.content_lines_string) @property def yaml_contents_keys(self): return self.yaml_contents_dict.keys() @property def yaml_contents_values(self): return self.yaml_contents_dict.values() def yaml_contents_by_key(self, key): return self.yaml_contents_dict.get(key) return DummyYAMLFile()
[docs] @pytest.fixture() def temp_folder_with_files(): with tempfile.TemporaryDirectory() as tmpdir: file1 = os.path.join(tmpdir, "test1.txt") file2 = os.path.join(tmpdir, "test2.log") with open(file1, "w") as f: f.write("Test file 1") with open(file2, "w") as f: f.write("Test file 2") yield tmpdir, file1, file2
# pytest fixtures for Popen
[docs] @pytest.fixture() def mock_popen(mocker): """Fixture to mock subprocess.Popen.""" return mocker.patch("subprocess.Popen")
[docs] @pytest.fixture(scope="session") def session_mocker(pytestconfig): """Session-scoped mocker fixture for patching during the test session.""" from unittest.mock import MagicMock mocker = MockerFixture(pytestconfig) mock = MagicMock() mocker.patch = mock.patch mocker.patch.object = mock.patch.object yield mocker mocker.resetall()
[docs] @pytest.fixture(scope="session") def tests_logger(): """Fixture to configure the root logger for tests.""" logger = logging.getLogger() # Root logger logger.setLevel(logging.INFO) logger.handlers = [] # Clear handlers to avoid conflicts logger.propagate = True # Set environment variable to signal test mode os.environ["TEST_MODE"] = "1" yield logger # Clean up logger.handlers = [] os.environ.pop("TEST_MODE", None)
# Use built-in caplog fixture for capturing log messages
[docs] @pytest.fixture() def capture_log(caplog): """ Fixture to capture log messages. Captures messages from the root logger at DEBUG level by default. """ caplog.set_level(logging.DEBUG, logger="") # "" for root logger return caplog
############ Iterate Fixtures ##################
[docs] @pytest.fixture() def iterate_test_directory(test_data_directory): """Returns the absolute path to tests/data/IterateTests.""" return os.path.join(test_data_directory, "IterateTests")
[docs] @pytest.fixture() def iterate_input_directory(iterate_test_directory): """Returns the absolute path to tests/data/IterateTests/input.""" return os.path.join(iterate_test_directory, "input")
[docs] @pytest.fixture() def iterate_expected_output_directory(iterate_test_directory): """Returns the absolute path to tests/data/IterateTests/expected_output.""" return os.path.join(iterate_test_directory, "expected_output")
[docs] @pytest.fixture() def iterate_configs_directory(iterate_test_directory): """Returns the absolute path to tests/data/IterateTests/configs.""" return os.path.join(iterate_test_directory, "configs")
[docs] @pytest.fixture() def iterate_integration_config_file(iterate_configs_directory): """Returns the absolute path to tests/data/IterateTests/configs/integration_iterate.toml.""" return os.path.join(iterate_configs_directory, "integration_iterate.toml")
[docs] @pytest.fixture() def iterate_timeout_config_file(iterate_configs_directory): """Returns the absolute path to tests/data/IterateTests/configs/timeout_iterate.toml.""" return os.path.join(iterate_configs_directory, "timeout_iterate.toml")
[docs] @pytest.fixture() def iterate_template_file(iterate_configs_directory): """Returns the absolute path to tests/data/IterateTests/configs/iterate_template.toml.""" return os.path.join(iterate_configs_directory, "iterate_template.toml")
[docs] @pytest.fixture() def iterate_expected_output_file(iterate_expected_output_directory): """Returns the absolute path to tests/data/IterateTests/expected_output/ integration_iterate_SLSQP_lagrange_multipliers_96_6.xyz.""" return os.path.join( iterate_expected_output_directory, "integration_iterate_SLSQP_lagrange_multipliers_96_6.xyz", )
# ── InChIKey test data ──
[docs] @pytest.fixture() def inchikey_test_directory(structure_test_directory): return os.path.join(structure_test_directory, "inchikey")
[docs] @pytest.fixture() def inchikey_normal_file(inchikey_test_directory): return os.path.join( inchikey_test_directory, "normal_testing", "inchikey_normal_testing.xyz", )
[docs] @pytest.fixture() def inchikey_r_enantiomer_file(inchikey_test_directory): return os.path.join( inchikey_test_directory, "enantiomer_testing", "inchikey_r_enantiomer.xyz", )
[docs] @pytest.fixture() def inchikey_s_enantiomer_file(inchikey_test_directory): return os.path.join( inchikey_test_directory, "enantiomer_testing", "inchikey_s_enantiomer.xyz", )
[docs] @pytest.fixture() def inchikey_large_molecule_c3_file(inchikey_test_directory): return os.path.join( inchikey_test_directory, "large_molecule_testing", "inchikey_large_molecule_c3.xyz", )
[docs] @pytest.fixture() def inchikey_large_molecule_c2_file(inchikey_test_directory): return os.path.join( inchikey_test_directory, "large_molecule_testing", "inchikey_large_molecule_c2.xyz", )
# ── CXSMILES test data ──
[docs] @pytest.fixture() def cxsmiles_test_directory(structure_test_directory): return os.path.join(structure_test_directory, "cxsmiles")
[docs] @pytest.fixture() def cxsmiles_normal_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "normal_testing", "rotamer_normal_testing.xyz", )
[docs] @pytest.fixture() def cxsmiles_r_enantiomer_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "enantiomer_testing", "rotamer_r_enantiomer.xyz", )
[docs] @pytest.fixture() def cxsmiles_s_enantiomer_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "enantiomer_testing", "rotamer_s_enantiomer.xyz", )
[docs] @pytest.fixture() def cxsmiles_r_rotamer_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "rotamer_testing", "cxsmiles_r_rotamer.xyz", )
[docs] @pytest.fixture() def cxsmiles_s_rotamer_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "rotamer_testing", "cxsmiles_s_rotamer.xyz", )
[docs] @pytest.fixture() def cxsmiles_large_molecule_c2_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "large_molecule_testing", "rotamer_large_molecule_c2.xyz", )
[docs] @pytest.fixture() def cxsmiles_large_molecule_c3_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "large_molecule_testing", "rotamer_large_molecule_c3.xyz", )
[docs] @pytest.fixture() def cxsmiles_expected_large_c2_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "large_molecule_testing", "expected_cxsmiles_c2.txt", )
[docs] @pytest.fixture() def cxsmiles_expected_large_c3_file(cxsmiles_test_directory): return os.path.join( cxsmiles_test_directory, "large_molecule_testing", "expected_cxsmiles_c3.txt", )
############ Molecule Fixtures for RDKit / PDB conversion tests ##################
[docs] @pytest.fixture() def water_molecule(): """H₂O with realistic geometry.""" return Molecule( symbols=["O", "H", "H"], positions=np.array( [ [0.0000, 0.0000, 0.1173], [0.0000, 0.7572, -0.4692], [0.0000, -0.7572, -0.4692], ] ), )
[docs] @pytest.fixture() def methane_molecule(): """CH₄ tetrahedral.""" return Molecule( symbols=["C", "H", "H", "H", "H"], positions=np.array( [ [0.0000, 0.0000, 0.0000], [0.6276, 0.6276, 0.6276], [0.6276, -0.6276, -0.6276], [-0.6276, 0.6276, -0.6276], [-0.6276, -0.6276, 0.6276], ] ), )
[docs] @pytest.fixture() def ethylene_molecule(): """C₂H₄ – contains a C=C double bond.""" return Molecule( symbols=["C", "C", "H", "H", "H", "H"], positions=np.array( [ [0.0000, 0.0000, 0.6695], [0.0000, 0.0000, -0.6695], [0.0000, 0.9289, 1.2321], [0.0000, -0.9289, 1.2321], [0.0000, 0.9289, -1.2321], [0.0000, -0.9289, -1.2321], ] ), )
[docs] @pytest.fixture() def acetylene_molecule(): """C₂H₂ – contains a C≡C triple bond.""" return Molecule( symbols=["C", "C", "H", "H"], positions=np.array( [ [0.0000, 0.0000, 0.6013], [0.0000, 0.0000, -0.6013], [0.0000, 0.0000, 1.6644], [0.0000, 0.0000, -1.6644], ] ), )
[docs] @pytest.fixture() def hydrogen_molecule(): """H₂ – minimal molecule with H-H bond.""" return Molecule( symbols=["H", "H"], positions=np.array( [ [0.0, 0.0, 0.0], [0.74, 0.0, 0.0], ] ), )
[docs] @pytest.fixture() def co2_molecule(): """CO₂ – linear molecule with two C=O double bonds.""" return Molecule( symbols=["C", "O", "O"], positions=np.array( [ [0.0, 0.0, 0.0], [0.0, 0.0, 1.16], [0.0, 0.0, -1.16], ] ), )
[docs] @pytest.fixture() def single_atom_molecule(): """Single argon atom – edge case for bond detection.""" return Molecule( symbols=["Ar"], positions=np.array([[0.0, 0.0, 0.0]]), )
[docs] @pytest.fixture() def water_with_metadata_molecule(): """Water molecule with PDB residue metadata.""" mol = Molecule( symbols=["O", "H", "H"], positions=np.array( [ [0.0, 0.0, 0.0], [0.96, 0.0, 0.0], [-0.24, 0.93, 0.0], ] ), info={ "record_type": ["HETATM", "HETATM", "HETATM"], "atom_name": ["O", "H1", "H2"], "residue_name": ["HOH", "HOH", "HOH"], "residue_number": [1, 1, 1], "chain_id": ["A", "A", "A"], }, ) mol.atom_names = ["O", "H1", "H2"] mol.residue_names = ["HOH", "HOH", "HOH"] mol.residue_numbers = [1, 1, 1] mol.chain_ids = ["A", "A", "A"] return mol
[docs] @pytest.fixture() def chiral_molecule(): """Molecule with a chiral center (C with 4 different substituents).""" return Molecule( symbols=["C", "Cl", "F", "Br", "I"], positions=np.array( [ [0.0, 0.0, 0.0], [1.2, 0.0, -0.5], [-0.6, 1.0, 0.5], [-0.6, -1.0, 0.5], [0.0, 0.0, 1.3], ] ), )
[docs] @pytest.fixture() def single_model_pdb_file(tmpdir): """PDB file with one implicit model (no MODEL/ENDMDL records).""" pdb_content = ( "HETATM 1 O HOH A 7 0.000 0.000 0.000 1.00 0.00 O\n" "HETATM 2 H1 HOH A 7 0.960 0.000 0.000 1.00 0.00 H\n" "HETATM 3 H2 HOH A 7 -0.240 0.930 0.000 1.00 0.00 H\n" "END\n" ) filepath = os.path.join(str(tmpdir), "water.pdb") with open(filepath, "w") as f: f.write(pdb_content) return filepath
[docs] @pytest.fixture() def multi_model_pdb_file(tmpdir): """PDB file with two explicit MODEL/ENDMDL blocks.""" pdb_content = ( "MODEL 1\n" "ATOM 1 O HOH A 1 0.000 0.000 0.000 1.00 0.00 O\n" "ATOM 2 H1 HOH A 1 0.960 0.000 0.000 1.00 0.00 H\n" "ENDMDL\n" "MODEL 2\n" "ATOM 1 O HOH B 2 1.500 2.500 3.500 1.00 0.00 O\n" "ATOM 2 H1 HOH B 2 2.460 2.500 3.500 1.00 0.00 H\n" "ENDMDL\n" "END\n" ) filepath = os.path.join(str(tmpdir), "multi_model.pdb") with open(filepath, "w") as f: f.write(pdb_content) return filepath
[docs] @pytest.fixture() def blank_element_pdb_file(tmpdir): """PDB file where element columns (77-78) are blank, requiring inference.""" pdb_content = ( "HETATM 1 FE HEM A 1 0.000 0.000 0.000 1.00 0.00\n" "HETATM 2 ZN ZN A 2 1.000 0.000 0.000 1.00 0.00\n" "HETATM 3 CL CL A 3 2.000 0.000 0.000 1.00 0.00\n" "ATOM 4 CA ALA A 4 3.000 0.000 0.000 1.00 0.00\n" "END\n" ) filepath = os.path.join(str(tmpdir), "blank_elements.pdb") with open(filepath, "w") as f: f.write(pdb_content) return filepath
[docs] @pytest.fixture() def empty_pdb_file(tmpdir): """PDB file with no ATOM/HETATM records.""" filepath = os.path.join(str(tmpdir), "empty.pdb") with open(filepath, "w") as f: f.write("REMARK This PDB has no atoms.\nEND\n") return filepath