Skip to main content

Type System

IterableData provides comprehensive type hints and typed helper functions for modern Python projects using static type checkers like mypy, pyright, or pyre.

Overview​

The type system includes:

  • Complete type annotations across the public API
  • Type aliases for common data structures (Row, IterableArgs, CodecArgs)
  • Typed helper functions for converting dict-based rows to dataclasses or Pydantic models
  • Type marker file (py.typed) to indicate package supports type checking

Type Aliases​

Import type aliases for use in your own type annotations:

from iterable import Row, IterableArgs, CodecArgs

# Row represents a data row as a dictionary
def process_row(row: Row) -> None:
name = row.get('name')
age = row.get('age')

# IterableArgs for configuration dictionaries
def configure_csv(config: IterableArgs) -> None:
delimiter = config.get('delimiter', ',')
encoding = config.get('encoding', 'utf-8')

# CodecArgs for compression codec configuration
def configure_compression(codec_config: CodecArgs) -> None:
level = codec_config.get('level', 6)

Available Type Aliases​

  • Row: dict[str, Any] - A data row represented as a dictionary
  • IterableArgs: dict[str, Any] - Iterable-specific configuration arguments
  • CodecArgs: dict[str, Any] - Codec-specific configuration arguments

Type Hints in API​

All public API functions and methods have complete type annotations:

from iterable import open_iterable
from iterable.base import BaseIterable

# open_iterable() has type hints
source: BaseIterable = open_iterable('data.csv')

# BaseIterable methods have type hints
row: Row = source.read()
rows: list[Row] = source.read_bulk(100)

# write() and write_bulk() accept Row types
source.write(row)
source.write_bulk(rows)

Typed Helper Functions​

as_dataclasses()​

Convert dict-based rows into dataclass instances for type-safe data processing.

from dataclasses import dataclass
from iterable import open_iterable, as_dataclasses

@dataclass
class Person:
name: str
age: int
email: str

with open_iterable('people.csv') as source:
for person in as_dataclasses(source, Person):
# person is typed as Person
print(f"{person.name} is {person.age} years old")
# IDE autocomplete works for person.name, person.age, etc.

Parameters:

  • iterable: The iterable to read rows from (BaseIterable)
  • dataclass_type: The dataclass type to convert rows to (type[T])
  • skip_empty: Whether to skip empty rows (default: True)

Returns:

  • Iterator of dataclass instances (Iterator[T])

Behavior:

  • Only includes fields that exist in the dataclass (extra fields are ignored)
  • Raises ValueError if required fields are missing
  • Works with any dataclass that can be instantiated from keyword arguments

Example with Extra Fields:

@dataclass
class Person:
name: str
age: int
# email field not included

# CSV has: name,age,email,city
# Only name and age are used, email and city are ignored
with open_iterable('people.csv') as source:
for person in as_dataclasses(source, Person):
print(person.name) # Works
# person.email # AttributeError - field not in dataclass

as_pydantic()​

Convert dict-based rows into Pydantic model instances with optional validation.

from pydantic import BaseModel
from iterable import open_iterable, as_pydantic

class PersonModel(BaseModel):
name: str
age: int
email: str

# With validation (default)
with open_iterable('people.csv') as source:
for person in as_pydantic(source, PersonModel, validate=True):
# Rows are validated against the model schema
# Invalid rows raise ValueError with ValidationError details
print(f"{person.name} ({person.email})")

Parameters:

  • iterable: The iterable to read rows from (BaseIterable)
  • model_type: The Pydantic model type to convert rows to (type[T])
  • skip_empty: Whether to skip empty rows (default: True)
  • validate: Whether to validate rows against the model schema (default: True)

Returns:

  • Iterator of Pydantic model instances (Iterator[T])

Raises:

  • ImportError: If pydantic is not installed (with helpful installation message)
  • TypeError: If model_type is not a Pydantic BaseModel subclass
  • ValueError: If validation fails and validate=True

Installation:

pip install iterabledata[pydantic]
# or
pip install pydantic>=2.0.0

Example with Validation Disabled:

# Skip validation for faster processing (use with caution)
with open_iterable('people.csv') as source:
for person in as_pydantic(source, PersonModel, validate=False):
# No validation, faster but less safe
print(person.name)

Example with Type Conversion:

Pydantic automatically converts types:

class PersonModel(BaseModel):
name: str
age: int # Automatically converts string "30" to int 30
email: str

# CSV: name,age,email
# Alice,30,alice@example.com
# Bob,25,bob@example.com

with open_iterable('people.csv') as source:
for person in as_pydantic(source, PersonModel):
print(type(person.age)) # <class 'int'> (converted from string)

Type Checking​

The package includes a py.typed marker file, indicating to type checkers that the package supports type checking.

Using mypy​

pip install mypy
mypy your_code.py

Using pyright​

pip install pyright
pyright your_code.py

Example Type-Checked Code​

from iterable import open_iterable, Row, as_dataclasses
from dataclasses import dataclass

@dataclass
class Person:
name: str
age: int

def process_people(filename: str) -> list[Person]:
people: list[Person] = []
with open_iterable(filename) as source:
for person in as_dataclasses(source, Person):
people.append(person)
return people

# Type checker validates:
# - filename is str ✓
# - return type is list[Person] ✓
# - person is Person type ✓

Benefits​

  • IDE Support: Better autocomplete, type checking, and documentation in modern IDEs
  • Error Prevention: Catch type-related mistakes before runtime
  • Code Clarity: Type hints serve as inline documentation
  • Refactoring Safety: Type checkers help ensure refactoring doesn't break code
  • Team Collaboration: Type hints make code easier to understand and maintain

Backward Compatibility​

All type hints are additive and don't affect runtime behavior:

  • Existing code continues to work without modifications
  • Type hints are optional and don't change function behavior
  • No performance impact (type hints are ignored at runtime)

See Also​