Skip to content

Access Layer

The access layer is the primary user-facing interface of pyBDL. It provides a clean, pandas DataFrame-based API that automatically handles data conversion and normalization.

Overview

The access layer sits on top of the raw API clients and provides:

  • Automatic DataFrame conversion: All responses are converted to pandas DataFrames
  • Column name normalization: camelCase API fields are converted to snake_case
  • Data type inference: Proper types (integers, floats, booleans) are automatically detected
  • Nested data normalization: Complex nested structures are flattened into tabular format

The main client provides two interfaces:

  • Access layer (default): Returns pandas DataFrames - use bdl.levels, bdl.data, etc.
  • API layer: Returns raw dictionaries - use bdl.api.levels, bdl.api.data, etc.

For most users, the access layer is recommended as it provides a more Pythonic and data-analysis-friendly interface.

Quick Start

from pybdl import BDL, BDLConfig

# Initialize client
bdl = BDL(BDLConfig(api_key="your-api-key"))

# Access layer returns DataFrames
levels_df = bdl.levels.list_levels()
print(levels_df.head())

# Data is ready for analysis
print(levels_df.dtypes)
print(levels_df.columns)

Key Features

DataFrame Conversion

All access layer methods return pandas DataFrames, making data immediately ready for analysis:

# Get variables as DataFrame
variables_df = bdl.variables.list_variables()

# Use pandas operations directly
filtered = variables_df[variables_df['name'].str.contains('population', case=False)]
sorted_vars = variables_df.sort_values('name')

Column Name Normalization

API responses use camelCase (e.g., variableId, unitName), but the access layer converts these to snake_case (e.g., variable_id, unit_name) for Pythonic access:

df = bdl.variables.get_variable("3643")
# Columns are: variable_id, name, description (not variableId, Name, Description)
print(df.columns)

Data Type Inference

The access layer automatically infers and converts data types:

df = bdl.data.get_data_by_variable("3643", years=[2021])
# year column is Int64, val column is float
print(df.dtypes)

Nested Data Normalization

The data endpoints return nested structures. The access layer automatically flattens them:

# API returns: [{"id": "1", "name": "Warsaw",
#   "values": [{"year": 2021, "val": 1000}, ...]}]
# Access layer returns flat DataFrame:
df = bdl.data.get_data_by_variable("3643", years=[2021])
# Columns: unit_id, unit_name, year, val, attr_id
print(df.head())

Available Endpoints

The access layer provides endpoints for all BDL API resources:

Endpoint Access Method Description
Aggregates bdl.aggregates Aggregation level metadata
Attributes bdl.attributes Attribute metadata
Data bdl.data Statistical data access
Levels bdl.levels Administrative unit levels
Measures bdl.measures Measure unit metadata
Subjects bdl.subjects Subject hierarchy
Units bdl.units Administrative units
Variables bdl.variables Variable metadata
Years bdl.years Available years

Available Access Endpoints

Endpoint Details

Levels

Administrative unit aggregation levels (country, voivodeship, county, municipality):

# List all levels
levels_df = bdl.levels.list_levels()

# Get specific level
level_df = bdl.levels.get_level(1)  # Level 1 = country

# Get metadata
metadata_df = bdl.levels.get_levels_metadata()

Subjects

Subject categories and hierarchy:

# List all top-level subjects
subjects_df = bdl.subjects.list_subjects()

# Get subjects under a parent
child_subjects = bdl.subjects.list_subjects(parent_id="P0001")

# Search subjects
results = bdl.subjects.search_subjects(name="population")

# Get specific subject
subject_df = bdl.subjects.get_subject("P0001")

Variables

Statistical variables (indicators):

# List all variables
variables_df = bdl.variables.list_variables()

# Filter variables
filtered = bdl.variables.list_variables(
    category_id="P0001",
    name="population"
)

# Search variables
results = bdl.variables.search_variables(name="unemployment")

# Get specific variable
variable_df = bdl.variables.get_variable("3643")

Data

Statistical data retrieval:

# Get data by variable (most common)
df = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2021],
    unit_level=2  # Voivodeship level
)

# Get data for multiple years
df = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2020, 2021, 2022],
    unit_level=2
)

# Get data with aggregate filter
df = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2021],
    aggregate_id=1
)

# Get data by administrative unit
df = bdl.data.get_data_by_unit(
    unit_id="020000000000",
    variable_ids=["3643"],
    years=[2021]
)

# Get data for a locality
df = bdl.data.get_data_by_variable_locality(
    variable_id="3643",
    unit_parent_id="1465011",
    years=[2021]
)

# Get data by unit locality
df = bdl.data.get_data_by_unit_locality(
    unit_id="1465011",
    variable_id="3643",
    years=[2021]
)

The data endpoints automatically normalize nested values arrays into flat rows.

Accessing Pagination Metadata

Use return_metadata=True to receive a (DataFrame, metadata) tuple alongside the data. The metadata dictionary contains information from the first response page, including pagination details such as totalPages and totalRecords.

# Returns (DataFrame, metadata_dict)
df, meta = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2021],
    return_metadata=True,
)
print(meta.get("totalPages"))
print(meta.get("totalRecords"))

Convenience *_with_metadata wrappers always return a tuple:

df, meta = bdl.data.get_data_by_variable_with_metadata(variable_id="3643", years=[2021])
df, meta = bdl.data.get_data_by_unit_with_metadata(unit_id="020000000000", variable_ids=["3643"])
df, meta = bdl.data.get_data_by_variable_locality_with_metadata(
    variable_id="3643", unit_parent_id="1465011", years=[2021]
)
df, meta = bdl.data.get_data_by_unit_locality_with_metadata(
    unit_id="1465011", variable_ids=["3643"]
)

Units

Administrative units (regions, cities, etc.):

# List units by level
voivodeships = bdl.units.list_units(level=2)  # Level 2 = voivodeship

# Search units
warsaw = bdl.units.search_units(name="Warsaw")

# Get specific unit
unit_df = bdl.units.get_unit("020000000000")

# List localities (statistical localities)
localities = bdl.units.list_localities(level=6)  # Level 6 = municipality

# Search localities
warsaw_localities = bdl.units.search_localities(name="Warsaw", level=6)

# Get specific locality
locality_df = bdl.units.get_locality("1465011")

Attributes

Data attributes (dimensions):

# List all attributes
attributes_df = bdl.attributes.list_attributes()

# Get specific attribute
attr_df = bdl.attributes.get_attribute("1")

Measures

Measure units:

# List all measures
measures_df = bdl.measures.list_measures()

# Get specific measure
measure_df = bdl.measures.get_measure(1)

Aggregates

Aggregation types:

# List all aggregates
aggregates_df = bdl.aggregates.list_aggregates()

# Get specific aggregate
aggregate_df = bdl.aggregates.get_aggregate("1")

Years

Available years for data:

# List all available years
years_df = bdl.years.list_years()

# Get specific year metadata
year_df = bdl.years.get_year(2021)

Enrichment

Many access layer methods accept an enrich parameter (or individual enrich_* flags) to automatically join human-readable reference data into the returned DataFrame. Enrichment fetches the required lookup table once per client session, caches it in memory, and left-joins the resolved columns onto each result row.

Usage

Pass a list of dimension names to enrich:

# Enrich variables with level names, measure descriptions, and subject names
variables = bdl.variables.list_variables(enrich=["levels", "measures", "subjects"])

# Enrich data with unit details, attribute labels, and aggregate descriptions
data = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2021],
    enrich=["units", "attributes", "aggregates"],
)

Individual enrich_* boolean flags are also accepted (legacy style):

data = bdl.data.get_data_by_variable("3643", years=[2021], enrich_attributes=True)

Supported Enrichment Dimensions

The available enrichment dimensions depend on the endpoint:

Endpoint enrich values Added columns
Variables (bdl.variables.*) "levels", "measures", "subjects" level_name; measure_unit_description; subject_name
Data (bdl.data.*) "units", "attributes", "aggregates" unit_name_enriched, unit_level, unit_parent_id, unit_kind; attr_name, attr_symbol, attr_description; aggregate_name, aggregate_description, aggregate_level
Units (bdl.units.*) "levels" level_name
Aggregates (bdl.aggregates.*) "levels" level_name

Caching

Lookup tables are fetched once per access-layer instance and cached for the lifetime of the client session. Subsequent calls using the same enrichment dimension reuse the cached data without additional API requests.

bdl = BDL()
# First call: fetches the levels lookup table from the API
v1 = bdl.variables.list_variables(enrich=["levels"])
# Second call: reuses the cached levels table — no extra request
v2 = bdl.variables.get_variable("3643", enrich=["levels"])

Pagination

Most list methods support pagination:

# Fetch all pages (default, max_pages=None)
all_data = bdl.variables.list_variables()

# Fetch only first page
first_page = bdl.variables.list_variables(max_pages=1, page_size=50)

# Limit number of pages
limited = bdl.variables.list_variables(max_pages=5, page_size=100)

Parameters:

  • max_pages: Maximum number of pages to fetch. None (default) fetches all pages, 1 fetches only the first page, N fetches up to N pages.
  • page_size: Number of results per page (default: 100 from config or 100).
  • show_progress: Display a tqdm progress bar while fetching pages (default: True). Set to False to suppress output in scripts or automated pipelines.
# Suppress progress bar
data = bdl.data.get_data_by_variable("3643", years=[2021], show_progress=False)

Async Usage

All access layer methods have async versions (prefixed with a):

import asyncio
from pybdl import BDL

async def main():
    bdl = BDL()

    # Async methods return DataFrames
    levels_df = await bdl.levels.alist_levels()
    variables_df = await bdl.variables.alist_variables()

    # Can run multiple requests concurrently
    levels_task = bdl.levels.alist_levels()
    variables_task = bdl.variables.alist_variables()

    levels_df, variables_df = await asyncio.gather(levels_task, variables_task)

    return levels_df, variables_df

asyncio.run(main())

Available async methods:

  • alist_levels(), alist_variables(), alist_subjects(), etc.
  • aget_level(), aget_variable(), aget_subject(), etc.
  • aget_data_by_variable(), aget_data_by_unit(), etc.

Examples

Basic Usage

from pybdl import BDL, BDLConfig

bdl = BDL(BDLConfig(api_key="your-api-key"))

# Get administrative levels
levels = bdl.levels.list_levels()
print(f"Found {len(levels)} administrative levels")

# Get variables related to population
population_vars = bdl.variables.search_variables(name="population")
print(f"Found {len(population_vars)} population-related variables")

# Get data for a specific variable
data = bdl.data.get_data_by_variable(
    variable_id="3643",
    years=[2021],
    unit_level=2  # Voivodeship level
)
print(data.head())

Filtering and Analysis

# Get all variables
variables = bdl.variables.list_variables()

# Filter using pandas
economic_vars = variables[variables['name'].str.contains('economic', case=False)]

# Get data for multiple variables
for var_id in economic_vars['id'].head(5):
    data = bdl.data.get_data_by_variable(var_id, years=[2021])
    print(f"Variable {var_id}: {len(data)} records")

Getting Data

# Get data
df = bdl.data.get_data_by_variable("3643", years=[2021])

# DataFrame includes IDs and values
print(df[['unit_name', 'attr_name', 'val']].head())

# Group by attribute name
by_attr = df.groupby('attr_name')['val'].mean()
print(by_attr)

Working with Nested Data

The data endpoints automatically normalize nested structures:

# API returns nested structure, but access layer flattens it
df = bdl.data.get_data_by_variable("3643", years=[2021])

# Each row represents one data point
# Columns: unit_id, unit_name, year, val, attr_id, attr_name
print(df.head())

# Easy to analyze
avg_by_unit = df.groupby('unit_name')['val'].mean()
print(avg_by_unit)

# Get data for multiple years
multi_year_df = bdl.data.get_data_by_variable("3643", years=[2020, 2021, 2022])
# Analyze trends over time
yearly_avg = multi_year_df.groupby('year')['val'].mean()
print(yearly_avg)

See examples for more comprehensive real-world examples.

API Reference

Module pybdl.access.base

base

Base access class for converting API responses to DataFrames.

BaseAccess

BaseAccess(api_client)

Base class for access layer implementations.

Supports per-function column renaming through the _column_renames class attribute. Child classes can define column rename mappings that apply to both sync and async methods.

Example::

class MyAccess(BaseAccess):
    _column_renames = {
        "list_items": {
            "id": "item_id",
            "name": "item_name",
        },
        "get_item": {
            "id": "item_id",
        },
    }

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

Module pybdl.access.enrichment

enrichment

Reusable enrichment decorator for access layer DataFrames.

EnrichmentLoader module-attribute

EnrichmentLoader = Callable[[BaseAccess], Any]

AsyncEnrichmentLoader module-attribute

AsyncEnrichmentLoader = Callable[
    [BaseAccess], Awaitable[Any]
]

LEVELS_SPEC module-attribute

LEVELS_SPEC = EnrichmentSpec(
    flag="enrich_levels",
    id_column="level",
    cache_key="levels",
    sync_loader=_fetch_levels_sync,
    async_loader=_fetch_levels_async,
    rename_map={"name": "level_name"},
)

MEASURES_SPEC module-attribute

MEASURES_SPEC = EnrichmentSpec(
    flag="enrich_measures",
    id_column="measure_unit_id",
    cache_key="measures",
    sync_loader=_fetch_measures_sync,
    async_loader=_fetch_measures_async,
    rename_map={"description": "measure_unit_description"},
)

ATTRIBUTES_SPEC module-attribute

ATTRIBUTES_SPEC = EnrichmentSpec(
    flag="enrich_attributes",
    id_column="attr_id",
    cache_key="attributes",
    sync_loader=_fetch_attributes_sync,
    async_loader=_fetch_attributes_async,
    rename_map={
        "name": "attr_name",
        "symbol": "attr_symbol",
        "description": "attr_description",
    },
)

UNITS_SPEC module-attribute

UNITS_SPEC = EnrichmentSpec(
    flag="enrich_units",
    id_column="unit_id",
    cache_key="units",
    sync_loader=_fetch_units_sync,
    async_loader=_fetch_units_async,
    rename_map={
        "name": "unit_name_enriched",
        "level": "unit_level",
        "parent_id": "unit_parent_id",
        "kind": "unit_kind",
        "has_description": "unit_has_description",
    },
    lookup_id_column="id",
)

AGGREGATES_SPEC module-attribute

AGGREGATES_SPEC = EnrichmentSpec(
    flag="enrich_aggregates",
    id_column="aggregate_id",
    cache_key="aggregates",
    sync_loader=_fetch_aggregates_sync,
    async_loader=_fetch_aggregates_async,
    rename_map={
        "name": "aggregate_name",
        "description": "aggregate_description",
        "level": "aggregate_level",
    },
)

SUBJECTS_SPEC module-attribute

SUBJECTS_SPEC = EnrichmentSpec(
    flag="enrich_subjects",
    id_column="subject_id",
    cache_key="subjects",
    sync_loader=_fetch_subjects_sync,
    async_loader=_fetch_subjects_async,
    rename_map={"name": "subject_name"},
    lookup_id_column="id",
)

EnrichmentSpec dataclass

EnrichmentSpec(
    flag,
    id_column,
    cache_key,
    sync_loader,
    async_loader,
    rename_map=dict(),
    lookup_id_column="id",
)

Configuration for a single enrichment dimension.

flag instance-attribute

flag

id_column instance-attribute

id_column

cache_key instance-attribute

cache_key

sync_loader instance-attribute

sync_loader

async_loader instance-attribute

async_loader

rename_map class-attribute instance-attribute

rename_map = field(default_factory=dict)

lookup_id_column class-attribute instance-attribute

lookup_id_column = 'id'

with_enrichment

with_enrichment(*specs)

Decorator to enrich DataFrame results with reference metadata.

Adds boolean flags (e.g., enrich_levels) to the wrapped function's kwargs, fetches lookup tables once per access instance, and left-joins enriched columns.

Source code in pybdl/access/enrichment.py
def with_enrichment(*specs: EnrichmentSpec) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """
    Decorator to enrich DataFrame results with reference metadata.

    Adds boolean flags (e.g., enrich_levels) to the wrapped function's kwargs,
    fetches lookup tables once per access instance, and left-joins enriched columns.
    """

    def _updated_signature(func: Callable[..., Any]) -> inspect.Signature:
        sig = inspect.signature(func)
        params = list(sig.parameters.values())
        existing = set(sig.parameters.keys())
        insert_at = next(
            (index for index, param in enumerate(params) if param.kind is inspect.Parameter.VAR_KEYWORD),
            len(params),
        )
        if "enrich" not in existing:
            params.insert(
                insert_at,
                inspect.Parameter(
                    "enrich",
                    kind=inspect.Parameter.KEYWORD_ONLY,
                    default=None,
                    annotation=list[str] | str | None,
                ),
            )
            insert_at += 1
        for spec in specs:
            if spec.flag in existing:
                continue
            params.insert(
                insert_at,
                inspect.Parameter(
                    spec.flag,
                    kind=inspect.Parameter.KEYWORD_ONLY,
                    default=False,
                    annotation=bool,
                ),
            )
            insert_at += 1
        return inspect.Signature(parameters=params, return_annotation=sig.return_annotation)

    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        if inspect.iscoroutinefunction(func):

            @wraps(func)
            async def async_wrapper(self: BaseAccess, *args: Any, **kwargs: Any) -> Any:
                flags = _resolve_enrichment_flags(specs, kwargs)
                result = await func(self, *args, **kwargs)
                df, metadata = _split_result(result)
                for spec in specs:
                    if flags.get(spec.flag):
                        lookup_df = await _get_lookup_async(self, spec)
                        df = _merge_enrichment(df, lookup_df, spec)
                return _recombine_result(df, metadata)

            async_wrapper.__signature__ = _updated_signature(func)  # type: ignore[attr-defined]
            return async_wrapper

        @wraps(func)
        def wrapper(self: BaseAccess, *args: Any, **kwargs: Any) -> Any:
            flags = _resolve_enrichment_flags(specs, kwargs)
            result = func(self, *args, **kwargs)
            df, metadata = _split_result(result)
            for spec in specs:
                if flags.get(spec.flag):
                    lookup_df = _get_lookup(self, spec)
                    df = _merge_enrichment(df, lookup_df, spec)
            return _recombine_result(df, metadata)

        wrapper.__signature__ = _updated_signature(func)  # type: ignore[attr-defined]
        return wrapper

    return decorator

Module pybdl.access.data

data

Access layer for data API endpoints with nested data normalization.

DataAccess

DataAccess(api_client)

Bases: BaseAccess

Access layer for data API, converting responses to DataFrames with nested data normalization.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

get_data_by_variable

get_data_by_variable(
    variable_id,
    years=None,
    unit_parent_id=None,
    unit_level=None,
    aggregate_id=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Retrieve statistical data for a specific variable as a DataFrame.

The nested 'values' array is normalized into separate rows, with each row containing: unit_id, unit_name, year, val, attr_id.

Parameters:

Name Type Description Default
variable_id str

Identifier of the variable.

required
years list[int] | None

Optional list of years to filter by.

None
unit_parent_id str | None

Optional parent administrative unit ID.

None
unit_level int | None

Optional administrative unit aggregation level.

None
aggregate_id int | None

Optional aggregate ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with normalized data, or tuple (DataFrame, metadata) if return_metadata is True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
def get_data_by_variable(
    self,
    variable_id: str,
    years: list[int] | None = None,
    unit_parent_id: str | None = None,
    unit_level: int | None = None,
    aggregate_id: int | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Retrieve statistical data for a specific variable as a DataFrame.

    The nested 'values' array is normalized into separate rows, with each row containing:
    unit_id, unit_name, year, val, attr_id.

    Args:
        variable_id: Identifier of the variable.
        years: Optional list of years to filter by.
        unit_parent_id: Optional parent administrative unit ID.
        unit_level: Optional administrative unit aggregation level.
        aggregate_id: Optional aggregate ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with normalized data, or tuple (DataFrame, metadata) if return_metadata is True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "variable_id": variable_id,
        "years": years,
        "unit_parent_id": unit_parent_id,
        "unit_level": unit_level,
        "aggregate_id": aggregate_id,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = self.api_client.get_data_by_variable(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata, normalize_variable_values=True)

get_data_by_variable_with_metadata

get_data_by_variable_with_metadata(*args, **kwargs)

Retrieve data by variable and always return (dataframe, metadata).

Source code in pybdl/access/data.py
def get_data_by_variable_with_metadata(self, *args: Any, **kwargs: Any) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Retrieve data by variable and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return self.get_data_by_variable(*args, **kwargs)

get_data_by_unit

get_data_by_unit(
    unit_id,
    variable_ids=None,
    years=None,
    aggregate_id=None,
    return_metadata=False,
    **kwargs,
)

Retrieve statistical data for a specific administrative unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Identifier of the administrative unit.

required
variable_ids Sequence[str | int] | str | int | None

Variable ID or sequence of variable IDs.

None
years list[int] | None

Optional list of years to filter by.

None
aggregate_id int | None

Optional aggregate ID.

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
def get_data_by_unit(
    self,
    unit_id: str,
    variable_ids: Sequence[str | int] | str | int | None = None,
    years: list[int] | None = None,
    aggregate_id: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Retrieve statistical data for a specific administrative unit as a DataFrame.

    Args:
        unit_id: Identifier of the administrative unit.
        variable_ids: Variable ID or sequence of variable IDs.
        years: Optional list of years to filter by.
        aggregate_id: Optional aggregate ID.
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    variable_id_list = self._normalize_variable_ids(variable_ids, kwargs)
    explicit_params = {
        "unit_id": unit_id,
        "variable_ids": variable_id_list,
        "years": years,
        "aggregate_id": aggregate_id,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = self.api_client.get_data_by_unit(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

get_data_by_unit_with_metadata

get_data_by_unit_with_metadata(*args, **kwargs)

Retrieve data by unit and always return (dataframe, metadata).

Source code in pybdl/access/data.py
def get_data_by_unit_with_metadata(self, *args: Any, **kwargs: Any) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Retrieve data by unit and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return self.get_data_by_unit(*args, **kwargs)

get_data_by_variable_locality

get_data_by_variable_locality(
    variable_id,
    unit_parent_id,
    years=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Retrieve data for a variable within a specific locality as a DataFrame.

Parameters:

Name Type Description Default
variable_id str

Identifier of the variable.

required
unit_parent_id str

Parent unit ID (required).

required
years list[int] | None

Optional list of years to filter by.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
def get_data_by_variable_locality(
    self,
    variable_id: str,
    unit_parent_id: str,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Retrieve data for a variable within a specific locality as a DataFrame.

    Args:
        variable_id: Identifier of the variable.
        unit_parent_id: Parent unit ID (required).
        years: Optional list of years to filter by.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "variable_id": variable_id,
        "unit_parent_id": unit_parent_id,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = self.api_client.get_data_by_variable_locality(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

get_data_by_variable_locality_with_metadata

get_data_by_variable_locality_with_metadata(
    *args, **kwargs
)

Retrieve locality data by variable and always return (dataframe, metadata).

Source code in pybdl/access/data.py
def get_data_by_variable_locality_with_metadata(
    self, *args: Any, **kwargs: Any
) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Retrieve locality data by variable and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return self.get_data_by_variable_locality(*args, **kwargs)

get_data_by_unit_locality

get_data_by_unit_locality(
    unit_id,
    variable_ids=None,
    years=None,
    aggregate_id=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Retrieve data for a single statistical locality by unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Identifier of the statistical locality.

required
variable_ids Sequence[str | int] | str | int | None

Variable ID or sequence of variable IDs.

None
years list[int] | None

Optional list of years to filter by.

None
aggregate_id int | None

Optional aggregate ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
def get_data_by_unit_locality(
    self,
    unit_id: str,
    variable_ids: Sequence[str | int] | str | int | None = None,
    years: list[int] | None = None,
    aggregate_id: int | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Retrieve data for a single statistical locality by unit as a DataFrame.

    Args:
        unit_id: Identifier of the statistical locality.
        variable_ids: Variable ID or sequence of variable IDs.
        years: Optional list of years to filter by.
        aggregate_id: Optional aggregate ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    variable_id_list = self._normalize_variable_ids(variable_ids, kwargs)
    explicit_params = {
        "unit_id": unit_id,
        "variable_ids": variable_id_list,
        "years": years,
        "aggregate_id": aggregate_id,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = self.api_client.get_data_by_unit_locality(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

get_data_by_unit_locality_with_metadata

get_data_by_unit_locality_with_metadata(*args, **kwargs)

Retrieve locality data by unit and always return (dataframe, metadata).

Source code in pybdl/access/data.py
def get_data_by_unit_locality_with_metadata(self, *args: Any, **kwargs: Any) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Retrieve locality data by unit and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return self.get_data_by_unit_locality(*args, **kwargs)

aget_data_by_variable async

aget_data_by_variable(
    variable_id,
    years=None,
    unit_parent_id=None,
    unit_level=None,
    aggregate_id=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Asynchronously retrieve statistical data for a specific variable as a DataFrame.

Parameters:

Name Type Description Default
variable_id str

Identifier of the variable.

required
years list[int] | None

Optional list of years to filter by.

None
unit_parent_id str | None

Optional parent administrative unit ID.

None
unit_level int | None

Optional administrative unit aggregation level.

None
aggregate_id int | None

Optional aggregate ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with normalized data, or tuple (DataFrame, metadata) if return_metadata is True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
async def aget_data_by_variable(
    self,
    variable_id: str,
    years: list[int] | None = None,
    unit_parent_id: str | None = None,
    unit_level: int | None = None,
    aggregate_id: int | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Asynchronously retrieve statistical data for a specific variable as a DataFrame.

    Args:
        variable_id: Identifier of the variable.
        years: Optional list of years to filter by.
        unit_parent_id: Optional parent administrative unit ID.
        unit_level: Optional administrative unit aggregation level.
        aggregate_id: Optional aggregate ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with normalized data, or tuple (DataFrame, metadata) if return_metadata is True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "variable_id": variable_id,
        "years": years,
        "unit_parent_id": unit_parent_id,
        "unit_level": unit_level,
        "aggregate_id": aggregate_id,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = await self.api_client.aget_data_by_variable(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata, normalize_variable_values=True)

aget_data_by_variable_with_metadata async

aget_data_by_variable_with_metadata(*args, **kwargs)

Asynchronously retrieve data by variable and always return (dataframe, metadata).

Source code in pybdl/access/data.py
async def aget_data_by_variable_with_metadata(
    self, *args: Any, **kwargs: Any
) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Asynchronously retrieve data by variable and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return await self.aget_data_by_variable(*args, **kwargs)

aget_data_by_unit async

aget_data_by_unit(
    unit_id,
    variable_ids=None,
    years=None,
    aggregate_id=None,
    return_metadata=False,
    **kwargs,
)

Asynchronously retrieve statistical data for a specific administrative unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Identifier of the administrative unit.

required
variable_ids Sequence[str | int] | str | int | None

Variable ID or sequence of variable IDs.

None
years list[int] | None

Optional list of years to filter by.

None
aggregate_id int | None

Optional aggregate ID.

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
async def aget_data_by_unit(
    self,
    unit_id: str,
    variable_ids: Sequence[str | int] | str | int | None = None,
    years: list[int] | None = None,
    aggregate_id: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Asynchronously retrieve statistical data for a specific administrative unit as a DataFrame.

    Args:
        unit_id: Identifier of the administrative unit.
        variable_ids: Variable ID or sequence of variable IDs.
        years: Optional list of years to filter by.
        aggregate_id: Optional aggregate ID.
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    variable_id_list = self._normalize_variable_ids(variable_ids, kwargs)
    explicit_params = {
        "unit_id": unit_id,
        "variable_ids": variable_id_list,
        "years": years,
        "aggregate_id": aggregate_id,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = await self.api_client.aget_data_by_unit(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

aget_data_by_unit_with_metadata async

aget_data_by_unit_with_metadata(*args, **kwargs)

Asynchronously retrieve data by unit and always return (dataframe, metadata).

Source code in pybdl/access/data.py
async def aget_data_by_unit_with_metadata(self, *args: Any, **kwargs: Any) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Asynchronously retrieve data by unit and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return await self.aget_data_by_unit(*args, **kwargs)

aget_data_by_variable_locality async

aget_data_by_variable_locality(
    variable_id,
    unit_parent_id,
    years=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Asynchronously retrieve data for a variable within a specific locality as a DataFrame.

Parameters:

Name Type Description Default
variable_id str

Identifier of the variable.

required
unit_parent_id str

Parent unit ID (required).

required
years list[int] | None

Optional list of years to filter by.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
async def aget_data_by_variable_locality(
    self,
    variable_id: str,
    unit_parent_id: str,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Asynchronously retrieve data for a variable within a specific locality as a DataFrame.

    Args:
        variable_id: Identifier of the variable.
        unit_parent_id: Parent unit ID (required).
        years: Optional list of years to filter by.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "variable_id": variable_id,
        "unit_parent_id": unit_parent_id,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = await self.api_client.aget_data_by_variable_locality(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

aget_data_by_variable_locality_with_metadata async

aget_data_by_variable_locality_with_metadata(
    *args, **kwargs
)

Asynchronously retrieve locality data by variable and always return (dataframe, metadata).

Source code in pybdl/access/data.py
async def aget_data_by_variable_locality_with_metadata(
    self, *args: Any, **kwargs: Any
) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Asynchronously retrieve locality data by variable and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return await self.aget_data_by_variable_locality(*args, **kwargs)

aget_data_by_unit_locality async

aget_data_by_unit_locality(
    unit_id,
    variable_ids=None,
    years=None,
    aggregate_id=None,
    page_size=None,
    max_pages=None,
    return_metadata=False,
    **kwargs,
)

Asynchronously retrieve data for a single statistical locality by unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Identifier of the statistical locality.

required
variable_ids Sequence[str | int] | str | int | None

Variable ID or sequence of variable IDs.

None
years list[int] | None

Optional list of years to filter by.

None
aggregate_id int | None

Optional aggregate ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
return_metadata bool

If True, return tuple (DataFrame, metadata).

False
**kwargs Any

Additional parameters passed to API layer, including enrich=["units", ...] or legacy enrich_units=True-style flags.

{}

Returns:

Type Description
DataFrame | tuple[DataFrame, dict[str, Any]]

DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.

Source code in pybdl/access/data.py
@with_enrichment(UNITS_SPEC, ATTRIBUTES_SPEC, AGGREGATES_SPEC)
async def aget_data_by_unit_locality(
    self,
    unit_id: str,
    variable_ids: Sequence[str | int] | str | int | None = None,
    years: list[int] | None = None,
    aggregate_id: int | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    return_metadata: bool = False,
    **kwargs: Any,
) -> pd.DataFrame | tuple[pd.DataFrame, dict[str, Any]]:
    """
    Asynchronously retrieve data for a single statistical locality by unit as a DataFrame.

    Args:
        unit_id: Identifier of the statistical locality.
        variable_ids: Variable ID or sequence of variable IDs.
        years: Optional list of years to filter by.
        aggregate_id: Optional aggregate ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        return_metadata: If True, return tuple (DataFrame, metadata).
        **kwargs: Additional parameters passed to API layer, including `enrich=["units", ...]`
            or legacy `enrich_units=True`-style flags.

    Returns:
        DataFrame with data, or tuple (DataFrame, metadata) if return_metadata=True.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    variable_id_list = self._normalize_variable_ids(variable_ids, kwargs)
    explicit_params = {
        "unit_id": unit_id,
        "variable_ids": variable_id_list,
        "years": years,
        "aggregate_id": aggregate_id,
        "page_size": page_size,
        "max_pages": max_pages,
        "return_metadata": return_metadata,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    result = await self.api_client.aget_data_by_unit_locality(**resolved_params, **kwargs)
    return self._to_dataframe_result(result, return_metadata=return_metadata)

aget_data_by_unit_locality_with_metadata async

aget_data_by_unit_locality_with_metadata(*args, **kwargs)

Asynchronously retrieve locality data by unit and always return (dataframe, metadata).

Source code in pybdl/access/data.py
async def aget_data_by_unit_locality_with_metadata(
    self, *args: Any, **kwargs: Any
) -> tuple[pd.DataFrame, dict[str, Any]]:
    """Asynchronously retrieve locality data by unit and always return `(dataframe, metadata)`."""
    kwargs["return_metadata"] = True
    return await self.aget_data_by_unit_locality(*args, **kwargs)

Module pybdl.access.variables

variables

Access layer for variables API endpoints.

VariablesAccess

VariablesAccess(api_client)

Bases: BaseAccess

Access layer for variables API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_variables

list_variables(
    subject_id=None,
    level=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

List all variables as a DataFrame.

Parameters:

Name Type Description Default
subject_id str | None

Optional subject ID to filter variables.

None
level int | None

Optional level to filter variables.

None
years list[int] | None

Optional list of years to filter variables.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with variables data.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
def list_variables(
    self,
    subject_id: str | None = None,
    level: int | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all variables as a DataFrame.

    Args:
        subject_id: Optional subject ID to filter variables.
        level: Optional level to filter variables.
        years: Optional list of years to filter variables.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with variables data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "subject_id": subject_id,
        "level": level,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.list_variables(**resolved_params, **kwargs)
    return self._to_dataframe(data)

get_variable

get_variable(variable_id, **kwargs)

Retrieve metadata details for a specific variable as a DataFrame.

Parameters:

Name Type Description Default
variable_id str

Variable identifier.

required
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with variable metadata.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
def get_variable(
    self,
    variable_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata details for a specific variable as a DataFrame.

    Args:
        variable_id: Variable identifier.
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with variable metadata.
    """
    data = self.api_client.get_variable(variable_id, **kwargs)
    return self._to_dataframe(data)

search_variables

search_variables(
    name=None,
    subject_id=None,
    level=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Search for variables by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in variable name.

None
subject_id str | None

Optional subject ID to filter variables.

None
level int | None

Optional level to filter variables.

None
years list[int] | None

Optional list of years to filter variables.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with matching variables.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
def search_variables(
    self,
    name: str | None = None,
    subject_id: str | None = None,
    level: int | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Search for variables by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in variable name.
        subject_id: Optional subject ID to filter variables.
        level: Optional level to filter variables.
        years: Optional list of years to filter variables.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with matching variables.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "name": name,
        "subject_id": subject_id,
        "level": level,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.search_variables(**resolved_params, **kwargs)
    return self._to_dataframe(data)

alist_variables async

alist_variables(
    subject_id=None,
    level=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Asynchronously list all variables as a DataFrame.

Parameters:

Name Type Description Default
subject_id str | None

Optional subject ID to filter variables.

None
level int | None

Optional level to filter variables.

None
years list[int] | None

Optional list of years to filter variables.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with variables data.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
async def alist_variables(
    self,
    subject_id: str | None = None,
    level: int | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all variables as a DataFrame.

    Args:
        subject_id: Optional subject ID to filter variables.
        level: Optional level to filter variables.
        years: Optional list of years to filter variables.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with variables data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "subject_id": subject_id,
        "level": level,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.alist_variables(**resolved_params, **kwargs)
    return self._to_dataframe(data)

aget_variable async

aget_variable(variable_id, **kwargs)

Asynchronously retrieve metadata details for a specific variable as a DataFrame.

Parameters:

Name Type Description Default
variable_id str

Variable identifier.

required
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with variable metadata.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
async def aget_variable(
    self,
    variable_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata details for a specific variable as a DataFrame.

    Args:
        variable_id: Variable identifier.
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with variable metadata.
    """
    data = await self.api_client.aget_variable(variable_id, **kwargs)
    return self._to_dataframe(data)

asearch_variables async

asearch_variables(
    name=None,
    subject_id=None,
    level=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Asynchronously search for variables by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in variable name.

None
subject_id str | None

Optional subject ID to filter variables.

None
level int | None

Optional level to filter variables.

None
years list[int] | None

Optional list of years to filter variables.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer, including enrich=["levels", ...] or legacy enrich_levels=True-style flags.

{}

Returns:

Type Description
DataFrame

DataFrame with matching variables.

Source code in pybdl/access/variables.py
@with_enrichment(LEVELS_SPEC, MEASURES_SPEC, SUBJECTS_SPEC)
async def asearch_variables(
    self,
    name: str | None = None,
    subject_id: str | None = None,
    level: int | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously search for variables by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in variable name.
        subject_id: Optional subject ID to filter variables.
        level: Optional level to filter variables.
        years: Optional list of years to filter variables.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer, including `enrich=["levels", ...]`
            or legacy `enrich_levels=True`-style flags.

    Returns:
        DataFrame with matching variables.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "name": name,
        "subject_id": subject_id,
        "level": level,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.asearch_variables(**resolved_params, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.subjects

subjects

Access layer for subjects API endpoints.

SubjectsAccess

SubjectsAccess(api_client)

Bases: BaseAccess

Access layer for subjects API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_subjects

list_subjects(
    parent_id=None, page_size=None, max_pages=None, **kwargs
)

List all subjects as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent subject ID. If not specified, returns all top-level subjects.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with subjects data.

Source code in pybdl/access/subjects.py
def list_subjects(
    self,
    parent_id: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all subjects as a DataFrame.

    Args:
        parent_id: Optional parent subject ID. If not specified, returns all top-level subjects.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with subjects data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "parent_id": parent_id,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.list_subjects(**resolved_params, **kwargs)
    return self._to_dataframe(data)

get_subject

get_subject(subject_id, **kwargs)

Retrieve metadata for a specific subject as a DataFrame.

Parameters:

Name Type Description Default
subject_id str

Subject identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with subject metadata.

Source code in pybdl/access/subjects.py
def get_subject(
    self,
    subject_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata for a specific subject as a DataFrame.

    Args:
        subject_id: Subject identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with subject metadata.
    """
    data = self.api_client.get_subject(subject_id, **kwargs)
    return self._to_dataframe(data)

search_subjects

search_subjects(
    name, page_size=None, max_pages=None, **kwargs
)

Search for subjects by name as a DataFrame.

Parameters:

Name Type Description Default
name str

Subject name to search for.

required
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching subjects.

Source code in pybdl/access/subjects.py
def search_subjects(
    self,
    name: str,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Search for subjects by name as a DataFrame.

    Args:
        name: Subject name to search for.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with matching subjects.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.search_subjects(
        name=name,
        page_size=page_size,
        max_pages=max_pages,
        **kwargs,
    )
    return self._to_dataframe(data)

alist_subjects async

alist_subjects(
    parent_id=None, page_size=None, max_pages=None, **kwargs
)

Asynchronously list all subjects as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent subject ID. If not specified, returns all top-level subjects.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with subjects data.

Source code in pybdl/access/subjects.py
async def alist_subjects(
    self,
    parent_id: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all subjects as a DataFrame.

    Args:
        parent_id: Optional parent subject ID. If not specified, returns all top-level subjects.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with subjects data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "parent_id": parent_id,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.alist_subjects(**resolved_params, **kwargs)
    return self._to_dataframe(data)

aget_subject async

aget_subject(subject_id, **kwargs)

Asynchronously retrieve metadata for a specific subject as a DataFrame.

Parameters:

Name Type Description Default
subject_id str

Subject identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with subject metadata.

Source code in pybdl/access/subjects.py
async def aget_subject(
    self,
    subject_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata for a specific subject as a DataFrame.

    Args:
        subject_id: Subject identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with subject metadata.
    """
    data = await self.api_client.aget_subject(subject_id, **kwargs)
    return self._to_dataframe(data)

asearch_subjects async

asearch_subjects(
    name, page_size=None, max_pages=None, **kwargs
)

Asynchronously search for subjects by name as a DataFrame.

Parameters:

Name Type Description Default
name str

Subject name to search for.

required
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching subjects.

Source code in pybdl/access/subjects.py
async def asearch_subjects(
    self,
    name: str,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously search for subjects by name as a DataFrame.

    Args:
        name: Subject name to search for.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with matching subjects.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.asearch_subjects(
        name=name,
        page_size=page_size,
        max_pages=max_pages,
        **kwargs,
    )
    return self._to_dataframe(data)

Module pybdl.access.units

units

Access layer for units API endpoints.

UnitsAccess

UnitsAccess(api_client)

Bases: BaseAccess

Access layer for units API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_units

list_units(
    parent_id=None,
    level=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

List all administrative units as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent unit ID.

None
level int | list[int] | None

Optional administrative level (integer or list of integers).

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., name, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with units data.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def list_units(
    self,
    parent_id: str | None = None,
    level: int | list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all administrative units as a DataFrame.

    Args:
        parent_id: Optional parent unit ID.
        level: Optional administrative level (integer or list of integers).
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., name, sort, lang, format, extra_query).

    Returns:
        DataFrame with units data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    # Convert single level to list for API compatibility
    level_list = [level] if isinstance(level, int) else level
    explicit_params = {
        "parent_id": parent_id,
        "level": level_list,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.list_units(**resolved_params, **kwargs)
    return self._to_dataframe(data)

get_unit

get_unit(unit_id, **kwargs)

Retrieve metadata details for a specific administrative unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Administrative unit identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with unit metadata.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def get_unit(
    self,
    unit_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata details for a specific administrative unit as a DataFrame.

    Args:
        unit_id: Administrative unit identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with unit metadata.
    """
    data = self.api_client.get_unit(unit_id, **kwargs)
    return self._to_dataframe(data)

search_units

search_units(
    name=None,
    level=None,
    years=None,
    kind=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Search for administrative units by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in unit name.

None
level int | list[int] | None

Optional administrative level (integer or list of integers).

None
years list[int] | None

Optional list of years to filter by.

None
kind str | None

Optional unit kind filter.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching units.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def search_units(
    self,
    name: str | None = None,
    level: int | list[int] | None = None,
    years: list[int] | None = None,
    kind: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Search for administrative units by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in unit name.
        level: Optional administrative level (integer or list of integers).
        years: Optional list of years to filter by.
        kind: Optional unit kind filter.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with matching units.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    # Convert single level to list for API compatibility
    level_list = [level] if isinstance(level, int) else level
    explicit_params = {
        "name": name,
        "level": level_list,
        "years": years,
        "kind": kind,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.search_units(**resolved_params, **kwargs)
    return self._to_dataframe(data)

list_localities

list_localities(
    parent_id=None, page_size=None, max_pages=None, **kwargs
)

List all statistical localities as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent unit ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., name, level, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with localities data.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def list_localities(
    self,
    parent_id: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all statistical localities as a DataFrame.

    Args:
        parent_id: Optional parent unit ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., name, level, sort, lang, format, extra_query).

    Returns:
        DataFrame with localities data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "parent_id": parent_id,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.list_localities(**resolved_params, **kwargs)
    return self._to_dataframe(data)

get_locality

get_locality(locality_id, **kwargs)

Retrieve metadata details for a specific statistical locality as a DataFrame.

Parameters:

Name Type Description Default
locality_id str

Locality identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with locality metadata.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def get_locality(
    self,
    locality_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata details for a specific statistical locality as a DataFrame.

    Args:
        locality_id: Locality identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with locality metadata.
    """
    data = self.api_client.get_locality(locality_id, **kwargs)
    return self._to_dataframe(data)

search_localities

search_localities(
    name=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Search for statistical localities by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in locality name.

None
years list[int] | None

Optional list of years to filter by.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., level, parent_id, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching localities.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
def search_localities(
    self,
    name: str | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Search for statistical localities by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in locality name.
        years: Optional list of years to filter by.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., level, parent_id, sort, lang, format, extra_query).

    Returns:
        DataFrame with matching localities.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "name": name,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = self.api_client.search_localities(**resolved_params, **kwargs)
    return self._to_dataframe(data)

alist_units async

alist_units(
    parent_id=None,
    level=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Asynchronously list all administrative units as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent unit ID.

None
level int | list[int] | None

Optional administrative level (integer or list of integers).

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., name, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with units data.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def alist_units(
    self,
    parent_id: str | None = None,
    level: int | list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all administrative units as a DataFrame.

    Args:
        parent_id: Optional parent unit ID.
        level: Optional administrative level (integer or list of integers).
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., name, sort, lang, format, extra_query).

    Returns:
        DataFrame with units data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    # Convert single level to list for API compatibility
    level_list = [level] if isinstance(level, int) else level
    explicit_params = {
        "parent_id": parent_id,
        "level": level_list,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.alist_units(**resolved_params, **kwargs)
    return self._to_dataframe(data)

aget_unit async

aget_unit(unit_id, **kwargs)

Asynchronously retrieve metadata details for a specific administrative unit as a DataFrame.

Parameters:

Name Type Description Default
unit_id str

Administrative unit identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with unit metadata.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def aget_unit(
    self,
    unit_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata details for a specific administrative unit as a DataFrame.

    Args:
        unit_id: Administrative unit identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with unit metadata.
    """
    data = await self.api_client.aget_unit(unit_id, **kwargs)
    return self._to_dataframe(data)

asearch_units async

asearch_units(
    name=None,
    level=None,
    years=None,
    kind=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Asynchronously search for administrative units by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in unit name.

None
level int | list[int] | None

Optional administrative level (integer or list of integers).

None
years list[int] | None

Optional list of years to filter by.

None
kind str | None

Optional unit kind filter.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching units.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def asearch_units(
    self,
    name: str | None = None,
    level: int | list[int] | None = None,
    years: list[int] | None = None,
    kind: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously search for administrative units by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in unit name.
        level: Optional administrative level (integer or list of integers).
        years: Optional list of years to filter by.
        kind: Optional unit kind filter.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with matching units.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    # Convert single level to list for API compatibility
    level_list = [level] if isinstance(level, int) else level
    explicit_params = {
        "name": name,
        "level": level_list,
        "years": years,
        "kind": kind,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.asearch_units(**resolved_params, **kwargs)
    return self._to_dataframe(data)

alist_localities async

alist_localities(
    parent_id=None, page_size=None, max_pages=None, **kwargs
)

Asynchronously list all statistical localities as a DataFrame.

Parameters:

Name Type Description Default
parent_id str | None

Optional parent unit ID.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., name, level, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with localities data.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def alist_localities(
    self,
    parent_id: str | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all statistical localities as a DataFrame.

    Args:
        parent_id: Optional parent unit ID.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., name, level, sort, lang, format, extra_query).

    Returns:
        DataFrame with localities data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "parent_id": parent_id,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.alist_localities(**resolved_params, **kwargs)
    return self._to_dataframe(data)

aget_locality async

aget_locality(locality_id, **kwargs)

Asynchronously retrieve metadata details for a specific statistical locality as a DataFrame.

Parameters:

Name Type Description Default
locality_id str

Locality identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with locality metadata.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def aget_locality(
    self,
    locality_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata details for a specific statistical locality as a DataFrame.

    Args:
        locality_id: Locality identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with locality metadata.
    """
    data = await self.api_client.aget_locality(locality_id, **kwargs)
    return self._to_dataframe(data)

asearch_localities async

asearch_localities(
    name=None,
    years=None,
    page_size=None,
    max_pages=None,
    **kwargs,
)

Asynchronously search for statistical localities by name and optional filters as a DataFrame.

Parameters:

Name Type Description Default
name str | None

Optional substring to search in locality name.

None
years list[int] | None

Optional list of years to filter by.

None
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., level, parent_id, sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with matching localities.

Source code in pybdl/access/units.py
@with_enrichment(LEVELS_SPEC)
async def asearch_localities(
    self,
    name: str | None = None,
    years: list[int] | None = None,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously search for statistical localities by name and optional filters as a DataFrame.

    Args:
        name: Optional substring to search in locality name.
        years: Optional list of years to filter by.
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., level, parent_id, sort, lang, format, extra_query).

    Returns:
        DataFrame with matching localities.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    explicit_params = {
        "name": name,
        "years": years,
        "page_size": page_size,
        "max_pages": max_pages,
    }
    resolved_params = self._resolve_api_params(explicit_params, kwargs)
    data = await self.api_client.asearch_localities(**resolved_params, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.levels

levels

Access layer for levels API endpoints.

LevelsAccess

LevelsAccess(api_client)

Bases: BaseAccess

Access layer for levels API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_levels

list_levels(page_size=None, max_pages=None, **kwargs)

List all administrative unit aggregation levels as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with levels data.

Source code in pybdl/access/levels.py
def list_levels(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all administrative unit aggregation levels as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with levels data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.list_levels(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

get_level

get_level(level_id, **kwargs)

Retrieve metadata for a specific aggregation level as a DataFrame.

Parameters:

Name Type Description Default
level_id int

Aggregation level identifier (integer).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with level metadata.

Source code in pybdl/access/levels.py
def get_level(
    self,
    level_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata for a specific aggregation level as a DataFrame.

    Args:
        level_id: Aggregation level identifier (integer).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with level metadata.
    """
    data = self.api_client.get_level(level_id, **kwargs)
    return self._to_dataframe(data)

alist_levels async

alist_levels(page_size=None, max_pages=None, **kwargs)

Asynchronously list all administrative unit aggregation levels as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with levels data.

Source code in pybdl/access/levels.py
async def alist_levels(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all administrative unit aggregation levels as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with levels data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.alist_levels(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

aget_level async

aget_level(level_id, **kwargs)

Asynchronously retrieve metadata for a specific aggregation level as a DataFrame.

Parameters:

Name Type Description Default
level_id int

Aggregation level identifier (integer).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with level metadata.

Source code in pybdl/access/levels.py
async def aget_level(
    self,
    level_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata for a specific aggregation level as a DataFrame.

    Args:
        level_id: Aggregation level identifier (integer).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with level metadata.
    """
    data = await self.api_client.aget_level(level_id, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.measures

measures

Access layer for measures API endpoints.

MeasuresAccess

MeasuresAccess(api_client)

Bases: BaseAccess

Access layer for measures API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_measures

list_measures(page_size=None, max_pages=None, **kwargs)

List all measure units as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with measures data.

Source code in pybdl/access/measures.py
def list_measures(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all measure units as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with measures data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.list_measures(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

get_measure

get_measure(measure_id, **kwargs)

Retrieve metadata for a specific measure unit as a DataFrame.

Parameters:

Name Type Description Default
measure_id int

Measure unit identifier (integer).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with measure unit metadata.

Source code in pybdl/access/measures.py
def get_measure(
    self,
    measure_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata for a specific measure unit as a DataFrame.

    Args:
        measure_id: Measure unit identifier (integer).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with measure unit metadata.
    """
    data = self.api_client.get_measure(measure_id, **kwargs)
    return self._to_dataframe(data)

alist_measures async

alist_measures(page_size=None, max_pages=None, **kwargs)

Asynchronously list all measure units as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with measures data.

Source code in pybdl/access/measures.py
async def alist_measures(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all measure units as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with measures data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.alist_measures(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

aget_measure async

aget_measure(measure_id, **kwargs)

Asynchronously retrieve metadata for a specific measure unit as a DataFrame.

Parameters:

Name Type Description Default
measure_id int

Measure unit identifier (integer).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with measure unit metadata.

Source code in pybdl/access/measures.py
async def aget_measure(
    self,
    measure_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata for a specific measure unit as a DataFrame.

    Args:
        measure_id: Measure unit identifier (integer).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with measure unit metadata.
    """
    data = await self.api_client.aget_measure(measure_id, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.attributes

attributes

Access layer for attributes API endpoints.

AttributesAccess

AttributesAccess(api_client)

Bases: BaseAccess

Access layer for attributes API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_attributes

list_attributes(page_size=None, max_pages=None, **kwargs)

List all attributes as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with attributes data.

Source code in pybdl/access/attributes.py
def list_attributes(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all attributes as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with attributes data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.list_attributes(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

get_attribute

get_attribute(attribute_id, **kwargs)

Retrieve metadata details for a specific attribute as a DataFrame.

Parameters:

Name Type Description Default
attribute_id str

Attribute identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with attribute metadata.

Source code in pybdl/access/attributes.py
def get_attribute(
    self,
    attribute_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata details for a specific attribute as a DataFrame.

    Args:
        attribute_id: Attribute identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with attribute metadata.
    """
    data = self.api_client.get_attribute(attribute_id, **kwargs)
    return self._to_dataframe(data)

alist_attributes async

alist_attributes(page_size=None, max_pages=None, **kwargs)

Asynchronously list all attributes as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with attributes data.

Source code in pybdl/access/attributes.py
async def alist_attributes(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all attributes as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with attributes data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.alist_attributes(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

aget_attribute async

aget_attribute(attribute_id, **kwargs)

Asynchronously retrieve metadata details for a specific attribute as a DataFrame.

Parameters:

Name Type Description Default
attribute_id str

Attribute identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with attribute metadata.

Source code in pybdl/access/attributes.py
async def aget_attribute(
    self,
    attribute_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata details for a specific attribute as a DataFrame.

    Args:
        attribute_id: Attribute identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with attribute metadata.
    """
    data = await self.api_client.aget_attribute(attribute_id, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.aggregates

aggregates

Access layer for aggregates API endpoints.

AggregatesAccess

AggregatesAccess(api_client)

Bases: BaseAccess

Access layer for aggregates API, converting responses to DataFrames.

Example column renaming::

_column_renames = {
    "list_aggregates": {
        "id": "aggregate_id",
        "name": "aggregate_name",
    },
    "get_aggregate": {
        "id": "aggregate_id",
    },
}

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_aggregates

list_aggregates(page_size=None, max_pages=None, **kwargs)

List all aggregates as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with aggregates data.

Source code in pybdl/access/aggregates.py
@with_enrichment(LEVELS_SPEC)
def list_aggregates(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all aggregates as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with aggregates data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.list_aggregates(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

get_aggregate

get_aggregate(aggregate_id, **kwargs)

Retrieve metadata details for a specific aggregate as a DataFrame.

Parameters:

Name Type Description Default
aggregate_id str

Aggregate identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with aggregate metadata.

Source code in pybdl/access/aggregates.py
@with_enrichment(LEVELS_SPEC)
def get_aggregate(
    self,
    aggregate_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata details for a specific aggregate as a DataFrame.

    Args:
        aggregate_id: Aggregate identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with aggregate metadata.
    """
    data = self.api_client.get_aggregate(aggregate_id, **kwargs)
    return self._to_dataframe(data)

alist_aggregates async

alist_aggregates(page_size=None, max_pages=None, **kwargs)

Asynchronously list all aggregates as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with aggregates data.

Source code in pybdl/access/aggregates.py
@with_enrichment(LEVELS_SPEC)
async def alist_aggregates(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all aggregates as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with aggregates data.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.alist_aggregates(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

aget_aggregate async

aget_aggregate(aggregate_id, **kwargs)

Asynchronously retrieve metadata details for a specific aggregate as a DataFrame.

Parameters:

Name Type Description Default
aggregate_id str

Aggregate identifier.

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with aggregate metadata.

Source code in pybdl/access/aggregates.py
@with_enrichment(LEVELS_SPEC)
async def aget_aggregate(
    self,
    aggregate_id: str,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata details for a specific aggregate as a DataFrame.

    Args:
        aggregate_id: Aggregate identifier.
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with aggregate metadata.
    """
    data = await self.api_client.aget_aggregate(aggregate_id, **kwargs)
    return self._to_dataframe(data)

Module pybdl.access.years

years

Access layer for years API endpoints.

YearsAccess

YearsAccess(api_client)

Bases: BaseAccess

Access layer for years API, converting responses to DataFrames.

Initialize base access class.

Parameters:

Name Type Description Default
api_client Any

API client instance (e.g., LevelsAPI, AttributesAPI).

required
Source code in pybdl/access/base.py
def __init__(self, api_client: Any):
    """
    Initialize base access class.

    Args:
        api_client: API client instance (e.g., LevelsAPI, AttributesAPI).
    """
    self.api_client = api_client
    # Cache for enrichment lookups (e.g., levels, measures) to avoid refetching
    self._enrichment_cache: dict[str, Any] = {}

api_client instance-attribute

api_client = api_client

list_years

list_years(page_size=None, max_pages=None, **kwargs)

List all available years as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with available years.

Source code in pybdl/access/years.py
def list_years(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    List all available years as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with available years.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = self.api_client.list_years(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

get_year

get_year(year_id, **kwargs)

Retrieve metadata for a specific year as a DataFrame.

Parameters:

Name Type Description Default
year_id int

Year identifier (integer, e.g. 2020).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with year metadata.

Source code in pybdl/access/years.py
def get_year(
    self,
    year_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Retrieve metadata for a specific year as a DataFrame.

    Args:
        year_id: Year identifier (integer, e.g. 2020).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with year metadata.
    """
    data = self.api_client.get_year(year_id, **kwargs)
    return self._to_dataframe(data)

alist_years async

alist_years(page_size=None, max_pages=None, **kwargs)

Asynchronously list all available years as a DataFrame.

Parameters:

Name Type Description Default
page_size int | None

Number of results per page (defaults to config.page_size or 100).

None
max_pages int | None

Maximum number of pages to fetch (None for all pages).

None
**kwargs Any

Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with available years.

Source code in pybdl/access/years.py
async def alist_years(
    self,
    page_size: int | None = None,
    max_pages: int | None = None,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously list all available years as a DataFrame.

    Args:
        page_size: Number of results per page (defaults to config.page_size or 100).
        max_pages: Maximum number of pages to fetch (None for all pages).
        **kwargs: Additional parameters passed to API layer (e.g., sort, lang, format, extra_query).

    Returns:
        DataFrame with available years.
    """
    if page_size is None:
        page_size = self._get_default_page_size()
    data = await self.api_client.alist_years(page_size=page_size, max_pages=max_pages, **kwargs)
    return self._to_dataframe(data)

aget_year async

aget_year(year_id, **kwargs)

Asynchronously retrieve metadata for a specific year as a DataFrame.

Parameters:

Name Type Description Default
year_id int

Year identifier (integer, e.g. 2020).

required
**kwargs Any

Additional parameters passed to API layer (e.g., lang, format, extra_query).

{}

Returns:

Type Description
DataFrame

DataFrame with year metadata.

Source code in pybdl/access/years.py
async def aget_year(
    self,
    year_id: int,
    **kwargs: Any,
) -> pd.DataFrame:
    """
    Asynchronously retrieve metadata for a specific year as a DataFrame.

    Args:
        year_id: Year identifier (integer, e.g. 2020).
        **kwargs: Additional parameters passed to API layer (e.g., lang, format, extra_query).

    Returns:
        DataFrame with year metadata.
    """
    data = await self.api_client.aget_year(year_id, **kwargs)
    return self._to_dataframe(data)

Seealso

- [Main client](main_client.md) — main client usage
- [API clients](api_clients.md) — low-level API access
- [Examples](examples.ipynb) — real-world examples
- [Configuration](config.md) — configuration options