There are quite a few places in Hdl21 where we recognize it will be a common error to confuse one type of thing for another, and provide some very targeted user feedback to help with the confusion. Module._attr_type_error serves as a prime example, which does stuff like so:
if isinstance(val, (Generator, Primitive, ExternalModule)):
msg = f"Cannot add `{type(val).__name__}` `{val.name}` to `Module` `{m.name}`. Did you mean to make an `Instance` by *calling* it - once for params and once for connections - first?"
elif isinstance(val, Module):
msg = f"Cannot add `{type(val).__name__}` `{val.name}` to `Module` `{m.name}`. Did you mean to make an `Instance` by *calling* to connect it first?"
elif isinstance(val, (GeneratorCall, PrimitiveCall, ExternalModuleCall)):
msg = f"Cannot add `{type(val).__name__}` `{val}` to `Module` `{m.name}`. Did you mean to make an `Instance` by *calling* to connect it first?"
else:
msg = f"Invalid Module attribute {val} of type {type(val)} for {m}. Valid `Module` attributes are of types: {list(ModuleAttr.__args__)}"
raise TypeError(msg)
One place these errors do not show up - and we have not been providing great feedback - is in the ValidationErrors commonly generated by our many Pydantic dataclasses. The feedback is particularly poor for union types, like from this snippet here:
import hdl21 as h
@h.paramclass
class MyParams:
m = h.Param(dtype=h.Instantiable, desc="Module to instantiate")
MyParams(h.Mos) # <= Look here
Produces:
pydantic.error_wrappers.ValidationError: 4 validation errors for MyParams
m
instance of Module expected (type=type_error.arbitrary_type; expected_arbitrary_type=Module)
m
instance of ExternalModuleCall, tuple or dict expected (type=type_error.dataclass; class_name=ExternalModuleCall)
m
instance of GeneratorCall expected (type=type_error.arbitrary_type; expected_arbitrary_type=GeneratorCall)
m
instance of PrimitiveCall, tuple or dict expected (type=type_error.dataclass; class_name=PrimitiveCall)
(a) That's a mouthful
(b) All of the Call types are not really front-page user-facing things; it's probably not obvious what any of them are
Since it's probably pretty unclear, the fix is:
MyParams(h.Mos()) # <= Note `Mos()` here
Good news is, we learned quite a bit about customizing these Pydantic validations while upgrading our Scalar numeric type. Scalar is now more or less this:
class Scalar(BaseModel):
"""
Generally this means
````python
Union[Prefixed, Literal]
with built-in automatic conversions from each of:
```python
[str, int, float, Decimal]
```
when used in `paramclass` definitions.
"""
__root__: Union[Prefixed, Literal]
Seems we could apply this to a few more. Or at least one - `Instantiable` - would help quite a lot.
There are quite a few places in Hdl21 where we recognize it will be a common error to confuse one type of thing for another, and provide some very targeted user feedback to help with the confusion.
Module._attr_type_error
serves as a prime example, which does stuff like so:https://github.com/dan-fritchman/Hdl21/blob/524373b7f4b8f14a47f2ee5287863fe0ff58d630/hdl21/module.py#L375
One place these errors do not show up - and we have not been providing great feedback - is in the
ValidationError
s commonly generated by our many Pydantic dataclasses. The feedback is particularly poor for union types, like from this snippet here:Produces:
Call
types are not really front-page user-facing things; it's probably not obvious what any of them areSince it's probably pretty unclear, the fix is:
Good news is, we learned quite a bit about customizing these Pydantic validations while upgrading our
Scalar
numeric type. Scalar is now more or less this: