Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provenance default for schema #233

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion devtools/conda-envs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dependencies:
- nomkl
- python
- pint=0.10.0 # technically, qcel has no lower bound for pint version for py36,37 but needs 0.10 for 38
- pydantic=1.2.0 # technically, qcel works with 1.0.0 but c-f doesn't have py38 builds for it
- pydantic=1.5.0

# Testing
- pytest=4.6.4 # technically, qcel works with 4.0.0 but c-f doesn't have py38 builds for it
Expand Down
10 changes: 10 additions & 0 deletions qcelemental/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@
from .molecule import Molecule
from .procedures import Optimization, OptimizationInput, OptimizationResult
from .results import AtomicInput, AtomicResult, AtomicResultProperties, Result, ResultInput, ResultProperties


def qcschema_models():
return [
AtomicInput,
AtomicResult,
BasisSet,
Molecule,
Provenance,
]
2 changes: 1 addition & 1 deletion qcelemental/models/basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class BasisSet(ProtoModel):
A quantum chemistry basis description.
"""

schema_name: constr(strip_whitespace=True, regex="qcschema_basis") = "qcschema_basis"
schema_name: constr(strip_whitespace=True, regex="qcschema_basis") = "qcschema_basis" # type: ignore
schema_version: int = 1

name: str = Field(..., description="A standard basis name if available (e.g., 'cc-pVDZ').")
Expand Down
25 changes: 15 additions & 10 deletions qcelemental/models/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@
import hashlib
import json
import warnings
from functools import partial
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union, cast

import numpy as np
from pydantic import Field, constr, validator

from ..molparse import from_arrays, from_schema, from_string, to_schema, to_string
# molparse imports separated b/c https://github.com/python/mypy/issues/7203
from ..molparse.from_arrays import from_arrays
from ..molparse.from_schema import from_schema
from ..molparse.from_string import from_string
from ..molparse.to_schema import to_schema
from ..molparse.to_string import to_string
from ..periodic_table import periodictable
from ..physical_constants import constants
from ..testing import compare, compare_values
Expand All @@ -23,7 +29,6 @@
if TYPE_CHECKING:
from pydantic.typing import ReprArgs


# Rounding quantities for hashing
GEOMETRY_NOISE = 8
MASS_NOISE = 6
Expand Down Expand Up @@ -225,8 +230,8 @@ class Molecule(ProtoModel):
None, description="Maximal point group symmetry which ``geometry`` should be treated. Lowercase."
)
# Extra
provenance: Provenance = Field( # type: ignore
provenance_stamp(__name__),
provenance: Provenance = Field(
default_factory=partial(provenance_stamp, __name__),
description="The provenance information about how this Molecule (and its attributes) were generated, "
"provided, and manipulated.",
)
Expand Down Expand Up @@ -1042,7 +1047,7 @@ def nuclear_repulsion_energy(self, ifr: int = None) -> float:
Nuclear repulsion energy in entire molecule or in fragment.

"""
Zeff = [z * int(real) for z, real in zip(self.atomic_numbers, self.real)]
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]
atoms = list(range(self.geometry.shape[0]))

if ifr is not None:
Expand All @@ -1068,7 +1073,7 @@ def nelectrons(self, ifr: int = None) -> int:
Number of electrons in entire molecule or in fragment.

"""
Zeff = [z * int(real) for z, real in zip(self.atomic_numbers, self.real)]
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]

if ifr is None:
nel = sum(Zeff) - self.molecular_charge
Expand Down Expand Up @@ -1146,7 +1151,7 @@ def align(
runiq = np.asarray(
[
hashlib.sha1((sym + str(mas)).encode("utf-8")).hexdigest()
for sym, mas in zip(ref_mol.symbols, ref_mol.masses)
for sym, mas in zip(cast(Iterable[str], ref_mol.symbols), ref_mol.masses)
]
)
concern_mol = self
Expand All @@ -1157,7 +1162,7 @@ def align(
cuniq = np.asarray(
[
hashlib.sha1((sym + str(mas)).encode("utf-8")).hexdigest()
for sym, mas in zip(concern_mol.symbols, concern_mol.masses)
for sym, mas in zip(cast(Iterable[str], concern_mol.symbols), concern_mol.masses)
]
)

Expand Down Expand Up @@ -1293,7 +1298,7 @@ def scramble(
runiq = np.asarray(
[
hashlib.sha1((sym + str(mas)).encode("utf-8")).hexdigest()
for sym, mas in zip(ref_mol.symbols, ref_mol.masses)
for sym, mas in zip(cast(Iterable[str], ref_mol.symbols), ref_mol.masses)
]
)
nat = rgeom.shape[0]
Expand Down
5 changes: 4 additions & 1 deletion qcelemental/models/results.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from enum import Enum
from functools import partial
from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Union

import numpy as np
Expand Down Expand Up @@ -347,7 +348,9 @@ class AtomicInput(ProtoModel):

extras: Dict[str, Any] = Field({}, description="Extra fields that are not part of the schema.")

provenance: Provenance = Field(Provenance(**provenance_stamp(__name__)), description=str(Provenance.__base_doc__))
provenance: Provenance = Field(
default_factory=partial(provenance_stamp, __name__), description=str(Provenance.__base_doc__)
)

def __repr_args__(self) -> "ReprArgs":
return [
Expand Down
4 changes: 2 additions & 2 deletions qcelemental/molparse/chgmult.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ def validate_and_fill_chgmult(
cgmp_rules.append("4")
for ifr in range(nfr):
cgmp_range.append(
lambda c, fc, m, fm, ifr=ifr: _sufficient_electrons_for_mult(fzel[ifr], fc[ifr], fm[ifr])
) # type: ignore
lambda c, fc, m, fm, ifr=ifr: _sufficient_electrons_for_mult(fzel[ifr], fc[ifr], fm[ifr]) # type: ignore
)
cgmp_rules.append("4-" + str(ifr))

# * (R5) require total parity consistent among neutral_electrons, chg, and mult
Expand Down
2 changes: 1 addition & 1 deletion qcelemental/molparse/to_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def to_dict(self) -> Dict:

atom_format = "{elem}"
ghost_format = "@{elem}"
umap = {"bohr": True, "angstrom": False}
umap = {"bohr": "True", "angstrom": "False"}

atoms = _atoms_formatter(molrec, geom, atom_format, ghost_format, width, prec, 2)

Expand Down
4 changes: 2 additions & 2 deletions qcelemental/molutil/molecular_formula.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import collections
import re
from typing import List
from typing import Dict, List


def order_molecular_formula(formula: str, order: str = "alphabetical") -> str:
Expand All @@ -23,7 +23,7 @@ def order_molecular_formula(formula: str, order: str = "alphabetical") -> str:
matches = re.findall(r"[A-Z][^A-Z]*", formula)
if not "".join(matches) == formula:
raise ValueError(f"{formula} is not a valid molecular formula.")
count = collections.defaultdict(int)
count: Dict[str, int] = collections.defaultdict(int)
for match in matches:
match_n = re.match(r"(\D+)(\d*)", match)
assert match_n
Expand Down
8 changes: 4 additions & 4 deletions qcelemental/tests/test_molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,14 +651,14 @@ def test_show():

def test_molecule_connectivity():
data = {"geometry": np.random.rand(5, 3), "symbols": ["he"] * 5, "validate": False}
mol = Molecule(**data, connectivity=None)
Molecule(**data, connectivity=None)

connectivity = [[n, n + 1, 1] for n in range(4)]
mol = Molecule(**data, connectivity=connectivity)
Molecule(**data, connectivity=connectivity)

connectivity[0][0] = -1
with pytest.raises(ValueError):
mol = Molecule(**data, connectivity=connectivity)
Molecule(**data, connectivity=connectivity)


def test_orient_nomasses():
Expand Down Expand Up @@ -719,7 +719,7 @@ def test_sparse_molecule_connectivity():


def test_bad_isotope_spec():
with pytest.raises(NotAnElementError) as e:
with pytest.raises(NotAnElementError):
qcel.models.Molecule(symbols=["He3"], geometry=[0, 0, 0])


Expand Down
4 changes: 2 additions & 2 deletions qcelemental/util/importing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import shutil
import sys
from typing import Union
from typing import List, Union


def which_import(
Expand All @@ -12,7 +12,7 @@ def which_import(
raise_msg: str = None,
package: str = None,
namespace_ok: bool = False,
) -> Union[bool, None, str]:
) -> Union[bool, None, str, List[str]]:
"""Tests to see if a Python module is available.

Returns
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
package_data={'': [os.path.join('qcelemental', 'data', '*.json')]},
setup_requires=[] + pytest_runner,
python_requires='>=3.6',
install_requires=['numpy >= 1.12.0', 'pint >= 0.10.0', 'pydantic >= 1.0.0'],
install_requires=["numpy >= 1.12.0", "pint >= 0.10.0", "pydantic >= 1.5.0"],
extras_require={
'docs': [
'numpydoc',
Expand Down