Introduction to Scalar Types
In this tutorial, you will learn how to use the basic scalar types provided by pydantic-core to build a data validation layer. We will cover how to handle permissive data with AnySchema, null values with NoneSchema, and boolean logic with BoolSchema.
By the end of this guide, you will have a working script that demonstrates how to configure these schemas and use the SchemaValidator to enforce data integrity.
Prerequisites
To follow this tutorial, you need the pydantic-core package installed in your environment. You will be using the core_schema module to define your validation rules.
Step 1: Validating Permissive Data with Any
The most flexible schema in pydantic-core is the AnySchema. It is often used as a fallback or for fields where you want to allow any Python object without restriction.
Create a file named scalar_validation.py and add the following code:
from pydantic_core import SchemaValidator, core_schema
# Define a schema that accepts anything
schema = core_schema.any_schema()
v = SchemaValidator(schema)
# Test with different types
print(v.validate_python(123)) # Output: 123
print(v.validate_python("hello")) # Output: 'hello'
print(v.validate_python({"a": 1})) # Output: {'a': 1}
The any_schema() function returns an AnySchema dictionary. When passed to SchemaValidator, it creates a validator that simply returns whatever input it receives, making it the "catch-all" type.
Step 2: Handling Null Values
In many data structures, you need to explicitly allow or require a None value (equivalent to null in JSON). The NoneSchema is designed specifically for this purpose.
Add this to your script:
# Define a schema that only accepts None
none_schema = core_schema.none_schema()
v_none = SchemaValidator(none_schema)
# This succeeds
print(v_none.validate_python(None)) # Output: None
# This will raise a ValidationError
try:
v_none.validate_python(False)
except Exception as e:
print(f"Validation failed: {e}")
The none_schema() helper ensures that the input is exactly None. Unlike some other validation libraries, it does not treat empty strings or other "falsy" values as None.
Step 3: Boolean Logic and Strictness
The BoolSchema allows you to validate boolean values. One of the most powerful features of pydantic-core is the ability to toggle between Lax and Strict validation modes.
Update your script with the following:
# 1. Lax Mode (Default)
lax_bool = core_schema.bool_schema()
v_lax = SchemaValidator(lax_bool)
# Lax mode accepts strings like 'yes', 'true', '1'
print(v_lax.validate_python("yes")) # Output: True
print(v_lax.validate_python(0)) # Output: False
# 2. Strict Mode
strict_bool = core_schema.bool_schema(strict=True)
v_strict = SchemaValidator(strict_bool)
# Strict mode requires an actual boolean
print(v_strict.validate_python(True)) # Output: True
try:
v_strict.validate_python("true")
except Exception as e:
print(f"Strict validation failed: {e}")
In the default lax mode, bool_schema() is quite permissive, accepting common truthy/falsy strings and integers. By setting strict=True in the BoolSchema, you force the validator to only accept literal True or False values.
Complete Working Result
Here is the complete code combining all the scalar types we've explored:
from pydantic_core import SchemaValidator, core_schema
def run_tutorial():
# Any Schema
any_v = SchemaValidator(core_schema.any_schema())
assert any_v.validate_python("anything goes") == "anything goes"
# None Schema
none_v = SchemaValidator(core_schema.none_schema())
assert none_v.validate_python(None) is None
# Bool Schema (Lax)
bool_v = SchemaValidator(core_schema.bool_schema())
assert bool_v.validate_python("1") is True
assert bool_v.validate_python("no") is False
# Bool Schema (Strict)
strict_bool_v = SchemaValidator(core_schema.bool_schema(strict=True))
try:
strict_bool_v.validate_python("true")
except Exception:
print("Strict validation correctly blocked a string input.")
print("All scalar validations passed!")
if __name__ == "__main__":
run_tutorial()
Next Steps
Now that you understand basic scalars, you can explore combining them using union_schema to create nullable fields (e.g., a field that is either a bool or None) or move on to more complex types like IntSchema and StringSchema.