Skip to content

Your First Type System

Now that you've seen the basics, let's dive deeper into understanding how pyvider.cty's type system works.

๐Ÿค– AI-Generated Content

This documentation was generated with AI assistance and is still being audited. Some, or potentially a lot, of this information may be inaccurate. Learn more.

Core Concepts

Before building more complex types, let's understand the main components:

Types

A Type defines the shape and constraints of your data. Types in pyvider.cty include:

  • Primitives: CtyString, CtyNumber, CtyBool
  • Collections: CtyList, CtyMap, CtySet
  • Structural: CtyObject, CtyTuple
  • Special: CtyDynamic (runtime type determination)

Values

A Value is an instance of a type. Values are:

  • Immutable - Once created, they cannot be changed
  • Type-safe - They always conform to their type schema
  • Rich - They carry metadata like marks and null status

Validation

Validation is the process of checking if raw Python data conforms to a type. If valid, you get a CtyValue. If not, you get a clear error.

Conversion

Conversion transforms between cty values and raw Python values, or between different cty types.

Building a More Complex Type

Let's build a type for a blog post system:

from pyvider.cty import (
    CtyObject, CtyString, CtyNumber, CtyList, CtyBool
)

# Define a comment type
comment_type = CtyObject(
    attribute_types={
        "author": CtyString(),
        "text": CtyString(),
        "likes": CtyNumber()
    }
)

# Define a blog post type
post_type = CtyObject(
    attribute_types={
        "title": CtyString(),
        "content": CtyString(),
        "author": CtyString(),
        "published": CtyBool(),
        "comments": CtyList(element_type=comment_type),
        "tags": CtyList(element_type=CtyString())
    }
)

Notice how we can nest types - the comments field is a list of comment_type objects.

Validating Complex Data

Now let's validate some data:

post_data = {
    "title": "Getting Started with Pyvider CTY",
    "content": "This is a great library for type-safe data...",
    "author": "Alice",
    "published": True,
    "comments": [
        {
            "author": "Bob",
            "text": "Great post!",
            "likes": 5
        },
        {
            "author": "Charlie",
            "text": "Very helpful, thanks!",
            "likes": 3
        }
    ],
    "tags": ["python", "types", "tutorial"]
}

try:
    post_value = post_type.validate(post_data)
    print("โœ… Post validated successfully!")
except Exception as e:
    print(f"โŒ Validation failed: {e}")

Optional Attributes

Sometimes you want fields to be optional:

user_type = CtyObject(
    attribute_types={
        "name": CtyString(),
        "email": CtyString(),
        "age": CtyNumber(),
        "bio": CtyString()
    },
    optional_attributes={"age", "bio"}
)

# This is valid - age and bio are optional
user_data = {
    "name": "Alice",
    "email": "[email protected]"
}

user_value = user_type.validate(user_data)

# Optional attributes that weren't provided are null
print(f"Age is null: {user_value['age'].is_null}")  # True
print(f"Bio is null: {user_value['bio'].is_null}")  # True

Accessing Nested Data

With nested structures, you can chain access:

post_value = post_type.validate(post_data)

# Access nested data
first_comment = post_value['comments'][0]
print(f"First comment by: {first_comment['author'].raw_value}")
print(f"Comment text: {first_comment['text'].raw_value}")

# Iterate over comments
for i, comment in enumerate(post_value['comments']):
    author = comment['author'].raw_value
    text = comment['text'].raw_value
    likes = comment['likes'].raw_value
    print(f"Comment {i+1} by {author}: {text} ({likes} likes)")

What About Invalid Data?

pyvider.cty provides clear error messages when validation fails:

invalid_data = {
    "title": "My Post",
    "content": "Content here",
    "author": "Alice",
    "published": "yes",  # Should be boolean!
    "comments": [],
    "tags": []
}

try:
    post_value = post_type.validate(invalid_data)
except Exception as e:
    print(f"Error: {e}")
    # Output: Error: Attribute 'published': expected CtyBool, got str

Next Steps

Now you understand the fundamentals! Continue learning:


Key Concepts:

  • Types define data structure, values hold the actual data
  • Values are immutable and type-safe
  • Validation converts raw Python data to cty values
  • Optional attributes can be marked when defining objects
  • Nested structures are fully supported
  • Error messages are clear and actionable