Artip – Scalar Temporal Period Identifiers for Power BI
Artip is a Python library that generates unique, scalar integer identifiers for temporal periods, optimized for storage and filtering in Power BI's Vertipaq engine.
Features
- Scalar Period IDs: Encode temporal periods as 64-bit integers for efficient Power BI representation
- Flexible Granularity: Support for year, month, day, hour, minute, and second-level periods
- Period Constraints: Optional maximum period size enforcement
- Calendar Generation: Automatic generation of periodic calendar tables for Power BI filtering
- Type-Safe: Full Python type hints for IDE integration and runtime checks
- No Global State: Thread-safe with all state encapsulated in Artip instances
Installation
pip install artip
Quick Start
from datetime import date
from artip import Artip
# Create an Artip instance
artip = Artip(
min_time=date(2024, 1, 1),
max_time=date(2024, 12, 31),
granularity='day'
)
# Generate a period identifier
period_id = artip.make_period_id(
start=date(2024, 1, 1),
end=date(2024, 1, 31)
)
print(f"Period ID: {period_id}") # Output: Period ID: 101
# Retrieve the time range for a period
start, end = artip.get_period_range(period_id)
print(f"Period range: {start} to {end}")
# Generate a calendar table for Power BI
calendar = artip.make_calendar_table()
print(calendar)
Use Cases
ETL Pipeline Integration
Use Artip in Python ETL pipelines to generate period identifiers for facts tables:
from datetime import date
import polars as pl
from artip import Artip
# Setup period encoding
artip = Artip(
min_time=date(2020, 1, 1),
max_time=date(2030, 12, 31),
granularity='month'
)
# Process fact records
facts = pl.DataFrame({
'transaction_date': [date(2024, 3, 15), date(2024, 5, 20)],
'amount': [100.0, 250.0]
})
def add_period_id(record):
return artip.make_period_id(record['transaction_date'], record['transaction_date'])
facts = facts.with_columns(
period_id=facts['transaction_date'].map_elements(
lambda d: artip.make_period_id(d, d).value
)
)
Calendar Table for Power BI
Generate a calendar table to enable period-based filtering:
calendar_table = artip.make_calendar_table()
# Save to CSV for Power BI import
calendar_table.write_csv('period_calendar.csv')
API Reference
Artip Class
Constructor
Artip(
min_time: Union[date, datetime],
max_time: Union[date, datetime],
granularity: str = 'day',
period_max_size: Optional[int] = None
)
Parameters:
min_time: Minimum time boundary (inclusive)max_time: Maximum time boundary (inclusive)granularity: Temporal granularity ('year', 'month', 'day', 'hour', 'minute', 'second')period_max_size: Maximum allowed period length in granularity units (None = unlimited)
Raises:
InvalidIntervalError: If min_time >= max_timeInvalidGranularityError: If granularity is not supported
make_period_id(start, end) -> PeriodId
Generate a unique identifier for a temporal period.
Parameters:
start: Period start time (inclusive)end: Period end time (inclusive)
Returns: PeriodId object
Raises:
InvalidIntervalError: If start > end or period outside boundsPeriodTooLargeError: If period exceeds period_max_size
get_period_range(period_id) -> Tuple[datetime, datetime]
Retrieve the time range for a period identifier.
Parameters:
period_id: A PeriodId generated by this instance
Returns: Tuple of (start_time, end_time)
Raises:
InvalidIntervalError: If period_id not generated by this instance
make_calendar_table() -> pl.DataFrame
Generate a periodic calendar table for Power BI filtering.
Returns: Polars DataFrame with columns:
date: The timepoint at the specified granularityperiod_id: The PeriodId value (Int64)label: Relationship to period ('starts', 'ends', 'in')
PeriodId Class
Lightweight dataclass representing a period identifier.
Attributes:
value: int– The encoded period identifier
Methods:
__str__()– Returns string representation__eq__(other)– Equality comparison__hash__()– Hashable for use in sets/dicts
Exceptions
ArtipError– Base exceptionInvalidIntervalError– Invalid time intervalPeriodTooLargeError– Period exceeds constraintsInvalidGranularityError– Unsupported granularity
Design Rationale
Artip encodes periods as composite integers:
PeriodId = (start_id) * 10^period_size + period_length
Where:
start_id= offset from min_time in granularity unitsperiod_length= end_id - start_idperiod_size= number of digits allocated for period_length
This design ensures:
- Efficient storage in 64-bit integers
- Fast period range queries
- Compatible filtering in Power BI
Requirements
- Python 3.10+
- Polars 0.20.0+
License
MIT
Contributing
Contributions are welcome! Please ensure:
- All tests pass:
pytest - Code is type-checked:
mypy - Code adheres to style:
ruff
Metadata
Release files for artip 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| artip-0.1.2.tar.gz | 50.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| artip-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.5 kB
Release files / artip-0.1.2.tar.gz
| Download URL | artip-0.1.2.tar.gz |
|---|---|
| Size | 50.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8deb14c324e731f157ff2636a664e9bc922c0061380326777822ea06496afa68
|
|
BLAKE2b-256 checksum How to use checksums |
13ab4b90baf4e24f68144a1413775b6afae19b31c799bd5177ab89c302522c74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / artip-0.1.2-py3-none-any.whl
| Download URL | artip-0.1.2-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6696f096a9a4784b0fc26db311a6287b7b01a00f22bbb7266d0a771e199f14d6
|
|
BLAKE2b-256 checksum How to use checksums |
5a3f5a17b4549126262b07e4d796461785b567b7b5535d07233e8871e64bee13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|