PolyField¶
The PolyField took great inspiration from Pydantic in the way it is generated.
Although being inspired from great tools, it acts in a unique fashion and it is what is internally used for the validation of the static typing.
Why the PolyField then? Well, for structure of course. To make sure there is always a source of truth when the Polyforce is taking action.
The PolyField¶
To import the PolyField
you only need to:
from polyforce import PolyField
Or
from polyforce.fields import PolyField
The PolyField
should generally not be initialised directly, instead the Field should be
used instead.
Parameters¶
The PolyField has the following parameters:
- annotation - The annotation of the field being created/checked.
- default - The default value of the field.
- factory - The altenative to
default
, usually a callable. -
name - The name of the field.
Default: Name of the attribute
-
title - The title of the field.
- description - The description of the field.
Warning
title
and description
for now are used for documentation purposes only and
you can only pass or default
or factory
but not both.
Let us see how a declaration of class using the Polyforce would look like internally and how the polyfield plays the role here.
from polyforce import PolyModel
class User(PolyModel):
def __init__(self, name: str, email: str) -> None:
...
def set_name(self, name: str) -> None:
...
def set_email(self, email: str) -> None:
...
How does it work¶
As you can see, you simply declare the Python object subclassing the PolyModel and internally the Polyforce will generate the polyfields for you.
The way of accessing the generated polyfields is as the following:
user = User(name="Polyforce", email="polymodel@example.com")
user.poly_fields
{
'__init__': {
'name': PolyField(annotation=str, required=True, name='name'),
'email': PolyField(annotation=str, required=True, name='email')},
'set_name': {'name': PolyField(annotation=str, required=True, name='name')},
'set_email': {'email': PolyField(annotation=str, required=True, name='email')}
}
Now, this is a lot to unwrap!
In a nutshell, the PolyModel does a lot of the heavy lifting for you.
For each function of the object subclassing the PolyModel. it will generate unique polyfields for each declare function and then use them for the enforcing of the static typing.
As mentioned before, the PolyField should generally not be initialised directly and instead, you can simply use the Field.
Field¶
What is this Field
? In a nutshell, it is your way of explicitly saying exactly what you want the
field to be, giving you more direct control of what is happening.
To import the Field
you only need to:
from polyforce import Field
Or
from polyforce.fields import Field
How does it work¶
In pratical terms, how does this Field
actually work.
Let us see the same example as before and go from there.
from polyforce import PolyModel
class User(PolyModel):
def __init__(self, name: str, email: str) -> None:
...
def set_name(self, name: str) -> None:
...
def set_email(self, email: str) -> None:
...
Until here, everything is ok btu what is actually happening is that the PolyModel will generate the polyfields for you.
Now, what happens if we apply the Field
, basically something like this:
from polyforce import Field, PolyModel
class User(PolyModel):
def __init__(self, name: str = Field(), email: str = Field()) -> None:
...
def set_name(self, name: str = Field()) -> None:
...
def set_email(self, email: str = Field()) -> None:
...
In the end, you are the one explicitly saying exactly what type of PolyField you want to be generated and to access the results is exactly in the same way as before.
user = User(name="Polyforce", email="polymodel@example.com")
user.poly_fields
{
'__init__': {
'name': PolyField(annotation=str, required=True, name='name'),
'email': PolyField(annotation=str, required=True, name='email')},
'set_name': {'name': PolyField(annotation=str, required=True, name='name')},
'set_email': {'email': PolyField(annotation=str, required=True, name='email')}
}
Required¶
When the PolyModel generates the PolyField, it will evaluate if the field
is required or not and the best way of making sure is to use the Field and provide a default
value.
from polyforce import Field, PolyModel
class User(PolyModel):
def __init__(self, name: str = Field(), email: str = Field()) -> None:
...
def set_name(self, name: str = Field(default="model")) -> None:
...
Let us see what is happening. In the __init__
, the name
has no default
and therefore, it is required.
user = User(name="Polyforce", email="polymodel@example.com")
user.poly_fields["__init__"]["name"]
# PolyField(annotation=str, required=True, name='name')
On the other hand, for the set_name
, a default="model"
is provided, which means, the field is
no longer required as it will default to model
if nothing is provided.
user = User(name="Polyforce", email="polymodel@example.com")
user.poly_fields["set_name"]["name"]
# PolyField(annotation=str, required=False, default='test', name='name')
Available functions¶
Since the Field generates PolyField on the fly, that also means you also have access to some internal functions.
Let us continue with the following example.
from polyforce import Field, PolyModel
class User(PolyModel):
def __init__(self, name: str = Field(), email: str = Field()) -> None:
...
def set_name(self, name: str = Field(default="model")) -> None:
...
is_required()¶
In practice, every PolyField
has access to this.
user = User(name="Polyforce", email="polymodel@example.com")
field = user.poly_fields["set_name"]["name"]
field.is_required() # False
get_default()¶
The way of getting the default
value of the field.
user = User(name="Polyforce", email="polymodel@example.com")
field = user.poly_fields["set_name"]["name"]
field.get_default() # "model"