openforcefield / openff-models

Helper classes for Pydantic compatibility in the OpenFF stack
MIT License
3 stars 2 forks source link

compound FloatQuantity #20

Closed richardjgowers closed 1 year ago

richardjgowers commented 1 year ago

I'm trying to do:

class T(models.BaseModel):
    foo: types.FloatQuantity['unit.boltzmann_constant * unit.kelvin']

T(foo=2.5 * unit.boltzmann_constant * unit.kelvin)

and I get:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[37], line 1
----> 1 T2(foo=2.5 * unit.boltzmann_constant * unit.kelvin)

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/main.py:339, in pydantic.main.BaseModel.__init__()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/main.py:1076, in pydantic.main.validate_model()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/fields.py:884, in pydantic.fields.ModelField.validate()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/fields.py:1101, in pydantic.fields.ModelField._validate_singleton()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/fields.py:1151, in pydantic.fields.ModelField._apply_validators()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pydantic/class_validators.py:337, in pydantic.class_validators._generic_validator_basic.lambda13()

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/openff/models/types.py:54, in FloatQuantity.validate_type(cls, val)
     50         raise UnitValidationError(
     51             f"Could not validate data of type {type(val)}"
     52         )
     53 else:
---> 54     unit_ = unit(unit_)
     55     if isinstance(val, unit.Quantity):
     56         # some custom behavior could go here
     57         assert unit_.dimensionality == val.dimensionality

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pint/facets/plain/registry.py:1252, in PlainRegistry.parse_expression(self, input_string, case_sensitive, use_decimal, **values)
   1250 for p in self.preprocessors:
   1251     input_string = p(input_string)
-> 1252 input_string = string_preprocessor(input_string)
   1253 gen = tokenizer(input_string)
   1255 return build_eval_tree(gen).evaluate(
   1256     lambda x: self._eval_token(x, case_sensitive=case_sensitive, **values)
   1257 )

File ~/miniconda3/envs/openfe_7/lib/python3.10/site-packages/pint/util.py:780, in string_preprocessor(input_string)
    779 def string_preprocessor(input_string: str) -> str:
--> 780     input_string = input_string.replace(",", "")
    781     input_string = input_string.replace(" per ", "/")
    783     for a, b in _subs_re:

AttributeError: 'Unit' object has no attribute 'replace'

Is this something that should work (eventually if I fixed it) or am I using FloatQuantity wrong here?

mattwthompson commented 1 year ago

Try this

In [12]: class T(models.DefaultModel):
    ...:     foo: types.FloatQuantity["boltzmann_constant * kelvin"]
    ...:
    ...:
    ...: T(foo=2.5 * unit.boltzmann_constant * unit.kelvin)
Out[12]: T(foo=<Quantity(2.5, 'boltzmann_constant * kelvin')>)

I wonder if that line should be unit.Unit(unit_) instead ...


In [33]: unit.Unit(unit.boltzmann_constant * unit.kelvin)
Out[33]: <Unit('boltzmann_constant * kelvin')>

In [34]: unit(unit.boltzmann_constant * unit.kelvin)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[34], line 1
----> 1 unit(unit.boltzmann_constant * unit.kelvin)

File ~/mambaforge/envs/openff-interchange-env/lib/python3.9/site-packages/pint/facets/plain/registry.py:1252, in PlainRegistry.parse_expression(self, input_string, case_sensitive, use_decimal, **values)
   1250 for p in self.preprocessors:
   1251     input_string = p(input_string)
-> 1252 input_string = string_preprocessor(input_string)
   1253 gen = tokenizer(input_string)
   1255 return build_eval_tree(gen).evaluate(
   1256     lambda x: self._eval_token(x, case_sensitive=case_sensitive, **values)
   1257 )

File ~/mambaforge/envs/openff-interchange-env/lib/python3.9/site-packages/pint/util.py:780, in string_preprocessor(input_string)
    779 def string_preprocessor(input_string: str) -> str:
--> 780     input_string = input_string.replace(",", "")
    781     input_string = input_string.replace(" per ", "/")
    783     for a, b in _subs_re:

AttributeError: 'Unit' object has no attribute 'replace'
richardjgowers commented 1 year ago

derp yes this works, thanks @mattwthompson