Skip to content

Commit

Permalink
Csse layout 550 error (#357)
Browse files Browse the repository at this point in the history
* remove v2.Result.error field

* convert subresults for error field in procedures

* enforce success in v2. test success

* surveys schema_version and extras

* round out survey checks for now

* atspec no ver

* skip a couple tests on py37

* more fixes

* fix selector

* py37

* another
  • Loading branch information
loriab authored Nov 25, 2024
1 parent b1199ed commit 44556c0
Show file tree
Hide file tree
Showing 17 changed files with 638 additions and 86 deletions.
6 changes: 6 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ New Features

Enhancements
++++++++++++
- (:pr:`357`, :issue:`536`) ``v2.AtomicResult``, ``v2.OptimizationResult``, and ``v2.TorsionDriveResult`` have the ``success`` field enforced to ``True``. Previously it could be set T/F. Now validation errors if not T. Likewise ``v2.FailedOperation.success`` is enforced to ``False``.
- (:pr:`357`, :issue:`536`) ``v2.AtomicResult``, ``v2.OptimizationResult``, and ``v2.TorsionDriveResult`` have the ``error`` field removed. This isn't used now that ``success=True`` and failure should be routed to ``FailedOperation``.
- (:pr:`357`) ``v1.Molecule`` had its schema_version changed to a Literal[2] (remember Mol is one-ahead of general numbering scheme) so new instances will be 2 even if another value is passed in. Ditto ``v2.BasisSet.schema_version=2``. Ditto ``v1.BasisSet.schema_version=1`` Ditto ``v1.QCInputSpecification.schema_version=1`` and ``v1.OptimizationSpecification.schema_version=1``.
- (:pr:`357`) ``v2.AtomicResultProperties``, ``v2.QCInputSpecification``, ``v2.OptimizationSpecification`` lost its schema_version until we see if its really needed.
- (:pr:`357`) ``v2.OptimizationSpecification`` gained extras field
- (:pr:`357`) ``v1.FailedOperation.extras`` and ``v2.FailedOperation.extras`` default changed from None to {}
* Fix a lot of warnings originating in this project.
* `Molecule.extras` now defaults to `{}` rather than None in both v1 and v2. Input None converts to {} upon instantiation.
* ``v2.FailedOperation`` field `id` is becoming `Optional[str]` instead of plain `str` so that the default validates.
Expand Down
2 changes: 1 addition & 1 deletion qcelemental/models/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
DeprecationWarning,
)

# Array = qcelemental.models.v1.Array
Array = qcelemental.models.v1.Array
# ArrayMeta = qcelemental.models.v1.ArrayMeta
# TypedArray = qcelemental.models.v1.TypedArray
6 changes: 4 additions & 2 deletions qcelemental/models/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import types
from . import types # ever used?
from .align import AlignmentMill
from .basemodels import AutodocBaseSettings # remove when QCFractal merges `next`
from .basemodels import ProtoModel
Expand All @@ -8,6 +8,7 @@
from .procedures import Optimization # scheduled for removal
from .procedures import (
OptimizationInput,
OptimizationProtocols,
OptimizationResult,
OptimizationSpecification,
QCInputSpecification,
Expand All @@ -18,7 +19,8 @@
from .results import Result # scheduled for removal
from .results import ResultInput # scheduled for removal
from .results import ResultProperties # scheduled for removal
from .results import AtomicInput, AtomicResult, AtomicResultProperties, AtomicResultProtocols
from .results import AtomicInput, AtomicResult, AtomicResultProperties, AtomicResultProtocols, WavefunctionProperties
from .types import Array


def qcschema_models():
Expand Down
12 changes: 11 additions & 1 deletion qcelemental/models/v1/basis.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from enum import Enum
from typing import Dict, List, Optional

try:
from typing import Literal
except ImportError:
# remove when minimum py38
from typing_extensions import Literal

from pydantic.v1 import ConstrainedInt, Field, constr, validator

from ...exceptions import ValidationError
Expand Down Expand Up @@ -155,7 +161,7 @@ class BasisSet(ProtoModel):
"qcschema_basis",
description=(f"The QCSchema specification to which this model conforms. Explicitly fixed as qcschema_basis."),
)
schema_version: int = Field( # type: ignore
schema_version: Literal[1] = Field( # type: ignore
1,
description="The version number of :attr:`~qcelemental.models.BasisSet.schema_name` to which this model conforms.",
)
Expand All @@ -175,6 +181,10 @@ class Config(ProtoModel.Config):
def schema_extra(schema, model):
schema["$schema"] = qcschema_draft

@validator("schema_version", pre=True)
def _version_stamp(cls, v):
return 1

@validator("atom_map")
def _check_atom_map(cls, v, values):
sv = set(v)
Expand Down
3 changes: 2 additions & 1 deletion qcelemental/models/v1/common_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class FailedOperation(ProtoModel):
":class:`ComputeError` for more details.",
)
extras: Optional[Dict[str, Any]] = Field( # type: ignore
None,
{},
description="Additional information to bundle with the failed operation. Details which pertain specifically "
"to a thrown error should be contained in the `error` field. See :class:`ComputeError` for details.",
)
Expand All @@ -139,6 +139,7 @@ def convert_v(

dself = self.dict()
if version == 2:
# TODO if FailedOp gets a schema_version, add a validator
self_vN = qcel.models.v2.FailedOperation(**dself)

return self_vN
Expand Down
14 changes: 13 additions & 1 deletion qcelemental/models/v1/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union, cast

try:
from typing import Literal
except ImportError:
# remove when minimum py38
from typing_extensions import Literal

import numpy as np
from pydantic.v1 import ConstrainedFloat, ConstrainedInt, Field, constr, validator

Expand Down Expand Up @@ -119,7 +125,7 @@ class Molecule(ProtoModel):
f"The QCSchema specification to which this model conforms. Explicitly fixed as {qcschema_molecule_default}."
),
)
schema_version: int = Field( # type: ignore
schema_version: Literal[2] = Field( # type: ignore
2,
description="The version number of :attr:`~qcelemental.models.Molecule.schema_name` to which this model conforms.",
)
Expand Down Expand Up @@ -370,6 +376,12 @@ def __init__(self, orient: bool = False, validate: Optional[bool] = None, **kwar
elif validate or geometry_prep:
values["geometry"] = float_prep(values["geometry"], geometry_noise)

@validator("schema_version", pre=True)
def _version_stamp(cls, v):
# seemingly unneeded, this lets conver_v re-label the model w/o discarding model and
# submodel version fields first.
return 2

@validator("geometry")
def _must_be_3n(cls, v, values, **kwargs):
n = len(values["symbols"])
Expand Down
34 changes: 32 additions & 2 deletions qcelemental/models/v1/procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class QCInputSpecification(ProtoModel):
"""

schema_name: constr(strip_whitespace=True, regex=qcschema_input_default) = qcschema_input_default # type: ignore
schema_version: int = 1 # TODO
schema_version: Literal[1] = 1

driver: DriverEnum = Field(DriverEnum.gradient, description=str(DriverEnum.__doc__))
model: Model = Field(..., description=str(Model.__doc__))
Expand All @@ -71,6 +71,10 @@ class QCInputSpecification(ProtoModel):
description="Additional information to bundle with the computation. Use for schema development and scratch space.",
)

@validator("schema_version", pre=True)
def _version_stamp(cls, v):
return 1


class OptimizationInput(ProtoModel):
id: Optional[str] = None
Expand Down Expand Up @@ -110,6 +114,7 @@ def convert_v(

dself = self.dict()
if version == 2:
dself["input_specification"].pop("schema_version", None)
self_vN = qcel.models.v2.OptimizationInput(**dself)

return self_vN
Expand Down Expand Up @@ -171,8 +176,16 @@ def convert_v(
if check_convertible_version(version, error="OptimizationResult") == "self":
return self

trajectory_class = self.trajectory[0].__class__
dself = self.dict()
if version == 2:
# remove harmless empty error field that v2 won't accept. if populated, pydantic will catch it.
if dself.pop("error", None):
pass

dself["trajectory"] = [trajectory_class(**atres).convert_v(version) for atres in dself["trajectory"]]
dself["input_specification"].pop("schema_version", None)

self_vN = qcel.models.v2.OptimizationResult(**dself)

return self_vN
Expand All @@ -189,12 +202,16 @@ class OptimizationSpecification(ProtoModel):
"""

schema_name: constr(strip_whitespace=True, regex="qcschema_optimization_specification") = "qcschema_optimization_specification" # type: ignore
schema_version: int = 1 # TODO
schema_version: Literal[1] = 1

procedure: str = Field(..., description="Optimization procedure to run the optimization with.")
keywords: Dict[str, Any] = Field({}, description="The optimization specific keywords to be used.")
protocols: OptimizationProtocols = Field(OptimizationProtocols(), description=str(OptimizationProtocols.__doc__))

@validator("schema_version", pre=True)
def _version_stamp(cls, v):
return 1

@validator("procedure")
def _check_procedure(cls, v):
return v.lower()
Expand Down Expand Up @@ -282,6 +299,9 @@ def convert_v(

dself = self.dict()
if version == 2:
dself["input_specification"].pop("schema_version", None)
dself["optimization_spec"].pop("schema_version", None)

self_vN = qcel.models.v2.TorsionDriveInput(**dself)

return self_vN
Expand Down Expand Up @@ -332,8 +352,18 @@ def convert_v(
if check_convertible_version(version, error="TorsionDriveResult") == "self":
return self

opthist_class = next(iter(self.optimization_history.values()))[0].__class__
dself = self.dict()
if version == 2:
# remove harmless empty error field that v2 won't accept. if populated, pydantic will catch it.
if dself.pop("error", None):
pass

dself["optimization_history"] = {
(k, [opthist_class(**res).convert_v(version) for res in lst])
for k, lst in dself["optimization_history"].items()
}

self_vN = qcel.models.v2.TorsionDriveResult(**dself)

return self_vN
Expand Down
4 changes: 4 additions & 0 deletions qcelemental/models/v1/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,10 @@ def convert_v(

dself = self.dict()
if version == 2:
# remove harmless empty error field that v2 won't accept. if populated, pydantic will catch it.
if dself.pop("error", None):
pass

self_vN = qcel.models.v2.AtomicResult(**dself)

return self_vN
Expand Down
13 changes: 11 additions & 2 deletions qcelemental/models/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
from .basis import BasisSet
from .common_models import ComputeError, DriverEnum, FailedOperation, Model, Provenance
from .molecule import Molecule
from .procedures import OptimizationInput, OptimizationResult, TorsionDriveInput, TorsionDriveResult
from .results import AtomicInput, AtomicResult, AtomicResultProperties, AtomicResultProtocols
from .procedures import (
OptimizationInput,
OptimizationProtocols,
OptimizationResult,
OptimizationSpecification,
QCInputSpecification,
TDKeywords,
TorsionDriveInput,
TorsionDriveResult,
)
from .results import AtomicInput, AtomicResult, AtomicResultProperties, AtomicResultProtocols, WavefunctionProperties


def qcschema_models():
Expand Down
12 changes: 11 additions & 1 deletion qcelemental/models/v2/basis.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from enum import Enum
from typing import Dict, List, Optional

try:
from typing import Literal
except ImportError:
# remove when minimum py38
from typing_extensions import Literal

from pydantic import Field, constr, field_validator
from typing_extensions import Annotated

Expand Down Expand Up @@ -171,7 +177,7 @@ class BasisSet(ProtoModel):
"qcschema_basis",
description=f"The QCSchema specification to which this model conforms. Explicitly fixed as qcschema_basis.",
)
schema_version: int = Field( # type: ignore
schema_version: Literal[2] = Field( # type: ignore
2,
description="The version number of :attr:`~qcelemental.models.BasisSet.schema_name` "
"to which this model conforms.",
Expand Down Expand Up @@ -245,3 +251,7 @@ def _calculate_nbf(cls, atom_map, center_data) -> int:
ret += center_count[center]

return ret

@field_validator("schema_version", mode="before")
def _version_stamp(cls, v):
return 2
12 changes: 9 additions & 3 deletions qcelemental/models/v2/common_models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from enum import Enum
from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Tuple, Union

try:
from typing import Literal
except ImportError:
# remove when minimum py38
from typing_extensions import Literal

import numpy as np
from pydantic import Field
from pydantic import Field, field_validator

from .basemodels import ProtoModel, qcschema_draft
from .basis import BasisSet
Expand Down Expand Up @@ -106,7 +112,7 @@ class FailedOperation(ProtoModel):
description="The input data which was passed in that generated this failure. This should be the complete "
"input which when attempted to be run, caused the operation to fail.",
)
success: bool = Field( # type: ignore
success: Literal[False] = Field( # type: ignore
False,
description="A boolean indicator that the operation failed consistent with the model of successful operations. "
"Should always be False. Allows programmatic assessment of all operations regardless of if they failed or "
Expand All @@ -118,7 +124,7 @@ class FailedOperation(ProtoModel):
":class:`ComputeError` for more details.",
)
extras: Optional[Dict[str, Any]] = Field( # type: ignore
None,
{},
description="Additional information to bundle with the failed operation. Details which pertain specifically "
"to a thrown error should be contained in the `error` field. See :class:`ComputeError` for details.",
)
Expand Down
8 changes: 7 additions & 1 deletion qcelemental/models/v2/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Molecule(ProtoModel):
),
)
schema_version: int = Field( # type: ignore
2,
2, # TODO Turn to Literal[3] = Field(3)
description="The version number of :attr:`~qcelemental.models.Molecule.schema_name` to which this model conforms.",
)
validated: bool = Field( # type: ignore
Expand Down Expand Up @@ -402,6 +402,12 @@ def __init__(self, orient: bool = False, validate: Optional[bool] = None, **kwar
elif validate or geometry_prep:
values["geometry"] = float_prep(values["geometry"], geometry_noise)

@field_validator("schema_version", mode="before")
def _version_stamp(cls, v):
# seemingly unneeded, this lets conver_v re-label the model w/o discarding model and
# submodel version fields first.
return 2 # TODO 3

@field_validator("geometry")
@classmethod
def _must_be_3n(cls, v, info):
Expand Down
Loading

0 comments on commit 44556c0

Please sign in to comment.