Factory Module

Dynamic model generation for MLB StatsAPI endpoints.

This module provides a fully config-driven approach to generating endpoint classes and methods from JSON schemas, eliminating hardcoded model definitions.

Key features: - Dynamic class and method generation from JSON schemas - Response objects with URL metadata for caching - Configurable method exclusions - Automatic parameter validation from schemas

class pymlb_statsapi.model.factory.APIResponse(response: Response, endpoint_name: str, method_name: str, path_params: dict | None = None, query_params: dict | None = None)[source]

Bases: LogMixin

MLB Stats API Response wrapper that includes URL metadata for caching and debugging.

This approach that just wraps the requests.Response and provides convenient access to URL components for cache key generation.

__init__(response: Response, endpoint_name: str, method_name: str, path_params: dict | None = None, query_params: dict | None = None)[source]
property status_code: int

HTTP status code

property ok: bool

True if status code is 2xx

json() dict | list[source]

Parse response as JSON

property text: str

Response body as text

property content: bytes

Response body as bytes

property headers: dict

Response headers

get_metadata() dict[source]

Get all request and response metadata as a JSON-serializable dict.

This includes everything about the request and response except the actual data payload. Consumers can use this metadata to build cache keys, store provenance, track API usage, etc.

Returns:

Metadata with the following structure:
  • request: Request metadata (endpoint, method, params, url, timestamp)

  • response: Response metadata (status_code, headers, elapsed, content_length)

Return type:

dict

Example

>>> response = StatsAPI.Schedule.schedule(sportId=1, date="2025-06-01")
>>> metadata = response.get_metadata()
>>> print(json.dumps(metadata, indent=2))
{
  "request": {
    "endpoint_name": "schedule",
    "method_name": "schedule",
    "path_params": {},
    "query_params": {"sportId": "1", "date": "2025-06-01"},
    "url": "https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=2025-06-01",
    "scheme": "https",
    "domain": "statsapi.mlb.com",
    "path": "/api/v1/schedule",
    "http_method": "GET",
    "timestamp": "2025-01-15T10:30:00.123456+00:00"
  },
  "response": {
    "status_code": 200,
    "ok": true,
    "elapsed_ms": 245.3,
    "content_type": "application/json",
    "content_length": 15234,
    "headers": {...}
  }
}
to_dict(include_data: bool = True) dict[source]

Convert the entire APIResponse to a JSON-serializable dict.

This is the primary method consumers should use to serialize the complete response (metadata + data) for storage, caching, or transmission.

Parameters:

include_data – Whether to include the response data payload (default: True) Set to False to get only metadata (equivalent to get_metadata())

Returns:

Complete response with metadata and data:
  • metadata: All request/response metadata (from get_metadata())

  • data: The parsed JSON response data (if include_data=True)

Return type:

dict

Example

>>> response = StatsAPI.Schedule.schedule(sportId=1, date="2025-06-01")
>>> # Get everything
>>> full_dict = response.to_dict()
>>> # Save to your storage
>>> with open("my_cache.json", "w") as f:
>>>     json.dump(full_dict, f)
>>>
>>> # Or just metadata
>>> metadata_only = response.to_dict(include_data=False)
get_path(prefix: str = '') str[source]

Generate a resource path for this API response.

The path does NOT include file extensions - those are added by get_uri() for file/s3 protocols. This keeps the path protocol-agnostic and flexible.

Format: {prefix}/{endpoint}/{method}/{path_params}/{sorted_query_params}

Examples

  • schedule/schedule/sportId=1&date=2025-06-01

  • mlb-data/schedule/schedule/sportId=1&date=2025-06-01

  • game/liveGameV1/game_pk=12345/timecode=20250601_120000

Parameters:

prefix – Optional prefix to prepend (separated by /)

Returns:

Path string suitable for use across different storage protocols

get_uri(prefix: str = '', gzip: bool = False) ParseResult[source]

Generate full file URI as a ParseResult for this API response.

Returns a urllib.parse.ParseResult that provides structured access to all URI components: - scheme: β€˜file’ - netloc: β€˜β€™ (empty for file protocol) - path: the absolute file path

Parameters:
  • prefix – Optional directory prefix

  • gzip – Whether to add .gz extension (default: False)

Environment Variables:
PYMLB_STATSAPI__BASE_FILE_PATH: Base directory for storage

(default: ./.var/local/mlb_statsapi)

Returns:

ParseResult object with URI components. Call .geturl() to get string representation.

Examples

>>> result = response.get_uri(prefix="mlb-data")
>>> result.scheme
'file'
>>> result.path
'/path/to/.var/local/mlb_statsapi/mlb-data/schedule/schedule/date=2025-06-01.json'
>>> result.geturl()
'file:///path/to/.var/local/mlb_statsapi/mlb-data/schedule/schedule/date=2025-06-01.json'
>>> result = response.get_uri(gzip=True)
>>> result.path
'/path/to/.var/local/mlb_statsapi/schedule/schedule/date=2025-06-01.json.gz'
save_json(file_path: str | None = None, gzip: bool = False, prefix: str = '') dict[source]

Save response JSON to a file.

Parameters:
  • file_path – Path to save the JSON file. If None, auto-generates using get_uri().

  • gzip – Whether to gzip the output (default: False)

  • prefix – Optional directory prefix (only used if file_path is None)

Returns:

Dict with β€˜path’, β€˜bytes_written’, and β€˜uri’ (ParseResult) keys

Examples

>>> # Save to explicit path
>>> response.save_json("/path/to/file.json")
>>> # Auto-generate path
>>> response.save_json(prefix="mlb-data")
>>> # Save gzipped with custom prefix
>>> response.save_json(gzip=True, prefix="raw-data")
>>> # Get URI details when auto-generating
>>> result = response.save_json(prefix="mlb-data")
>>> result['path']  # String path
>>> result['uri'].scheme  # 'file'
>>> result['uri'].geturl()  # Full file:// URI
gzip(file_path: str | None = None, prefix: str = '') dict[source]

Save response as gzipped JSON (convenience method).

This is equivalent to calling save_json(gzip=True, …).

Parameters:
  • file_path – Path to save the gzipped JSON file. If None, auto-generates.

  • prefix – Optional directory prefix (only used if file_path is None)

Returns:

Dict with β€˜path’, β€˜bytes_written’, and β€˜uri’ keys

Examples

>>> response.gzip("/path/to/file.json.gz")
>>> response.gzip(prefix="mlb-data")  # Auto-generates path
class pymlb_statsapi.model.factory.EndpointMethod(endpoint_name: str, method_name: str, api_definition: dict, operation_definition: dict, config_path: str)[source]

Bases: object

Represents a single API method with its schema-defined parameters and validation.

__init__(endpoint_name: str, method_name: str, api_definition: dict, operation_definition: dict, config_path: str)[source]
get_schema() dict[source]

Get the original schema JSON that defines this method.

Returns a dict with: - api: The API definition (path, description) - operation: The operation definition (method, parameters, etc.) - endpoint: Endpoint name - method: Method name - config_path: Configured path (if different from schema)

Returns:

Complete schema definition

Return type:

dict

Example

>>> method = api.Schedule.get_method_info("schedule")
>>> schema = method.get_schema()
>>> print(schema["operation"]["summary"])
'View schedule info'
>>> for param in schema["operation"]["parameters"]:
...     print(f"{param['name']}: {param['description']}")
get_parameter_schema(param_name: str) dict | None[source]

Get the full schema definition for a specific parameter.

Parameters:

param_name – Name of the parameter (e.g., β€œsportId”, β€œdate”)

Returns:

dict with parameter details or None if not found

Example

>>> param = method.get_parameter_schema("sportId")
>>> print(param["description"])
'Top level organization of a sport'
>>> print(param["required"])
False
>>> print(param["type"])
'integer'
list_parameters() dict[source]

List all parameters with their types and whether they’re required.

Returns:

dict with β€˜path’ and β€˜query’ keys, each containing parameter info

Example

>>> params = method.list_parameters()
>>> for param in params["path"]:
...     print(f"{param['name']} ({param['type']}): {param['required']}")
>>> for param in params["query"]:
...     print(f"{param['name']} ({param['type']}): {param['required']}")
get_long_description() str[source]

Get a comprehensive description of this method including all schema details.

Returns a formatted string with: - Summary - Notes - HTTP method and path - All parameters with descriptions - Response information

Returns:

Formatted description

Return type:

str

Example

>>> print(method.get_long_description())
validate_and_resolve_params(path_params: dict | None = None, query_params: dict | None = None) tuple[dict, dict, str][source]

Validate parameters and resolve the full URL path.

Parameters:
  • path_params – Path parameter values

  • query_params – Query parameter values

Returns:

Tuple of (validated_path_params, validated_query_params, resolved_path)

Raises:

AssertionError – If required parameters are missing or invalid

class pymlb_statsapi.model.factory.Endpoint(endpoint_name: str, schema: dict, endpoint_config: dict, excluded_methods: set[str] | None = None)[source]

Bases: LogMixin

Dynamically generated endpoint class that creates methods from JSON schema.

BASE_URL = 'https://statsapi.mlb.com/api'
MAX_RETRIES = 3
TIMEOUT = 30
__init__(endpoint_name: str, schema: dict, endpoint_config: dict, excluded_methods: set[str] | None = None)[source]
get_method_names() list[str][source]

Get list of available method names.

get_method(method_name: str) EndpointMethod[source]

Get the EndpointMethod object for introspection.

This allows access to all schema methods like: - get_schema() - get_parameter_schema() - list_parameters() - get_long_description()

Parameters:

method_name – Name of the method

Returns:

EndpointMethod instance

Raises:

ValueError – If method not found

Example

>>> method = api.Schedule.get_method("schedule")
>>> print(method.get_long_description())
>>> schema = method.get_schema()
>>> param = method.get_parameter_schema("sportId")
get_method_info(method_name: str) dict[source]

Get detailed information about a method.

DEPRECATED: Use get_method() instead for full schema access.

Parameters:

method_name – Name of the method

Returns:

dict with method details

Example

>>> info = api.Schedule.get_method_info("schedule")
>>> print(info["path"])
>>> print(info["summary"])
describe_method(method_name: str) str[source]

Get a human-readable description of a method with all its parameters.

This is a convenience wrapper around get_method().get_long_description().

Parameters:

method_name – Name of the method

Returns:

Formatted description

Return type:

str

Example

>>> print(api.Schedule.describe_method("schedule"))
get_method_schema(method_name: str) dict[source]

Get the original schema JSON for a method.

Parameters:

method_name – Name of the method

Returns:

Original schema definition

Return type:

dict

Example

>>> schema = api.Schedule.get_method_schema("schedule")
>>> print(schema["operation"]["parameters"])