Skip to main content

Universal schema converter for Python data types with optional dependencies

Project description

Lugia

Language Universal Gateway for Interoperable Adaptations

Universal schema converter for Python data types with optional dependencies.

Lugia provides bidirectional conversions between popular data schema types including PySpark, Polars, Pandas, Pydantic, dataclass, TypedDict, SQLModel, and SQLAlchemy. All dependencies are optional for maximum flexibility.

Features

  • Universal Conversions: Convert between any supported schema type
  • Optional Dependencies: Install only what you need
  • Schema & Data Support: Convert both type definitions and data instances
  • Type Detection: Automatic detection of source schema types
  • Error Handling: Clear error messages for missing dependencies

Installation

Install the base package:

pip install lugia

Install with optional dependencies as needed:

# Install specific dependencies
pip install lugia[pydantic]
pip install lugia[pandas]
pip install lugia[polars]
pip install lugia[pyspark]
pip install lugia[sqlalchemy]
pip install lugia[sqlmodel]

# Install all dependencies
pip install lugia[all]

# Install with development dependencies
pip install lugia[dev]

Quick Start

Basic Usage

from lugia import convert, to_pydantic, to_pandas, to_polars
from pydantic import BaseModel

# Define a Pydantic model
class User(BaseModel):
    name: str
    age: int
    email: str

# Convert to dataclass
from lugia.dataclass import to_dataclass
UserDataclass = to_dataclass(User)

# Convert to Pandas DataFrame
import pandas as pd
user = User(name="John", age=30, email="john@example.com")
df = to_pandas(user)
print(df)

Output:

   name  age             email
0  John   30  john@example.com

Using the Unified Converter

from lugia import convert

# Convert Pydantic to dataclass
UserDataclass = convert(User, target="dataclass")

# Convert dataclass to Pydantic
UserPydantic = convert(UserDataclass, target="pydantic")

Supported Conversions

Pydantic

from lugia.pydantic import to_pydantic
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# Convert from dataclass
import dataclasses

@dataclasses.dataclass
class UserDC:
    name: str
    age: int

UserPydantic = to_pydantic(UserDC)

# Convert from Pandas DataFrame
import pandas as pd
df = pd.DataFrame({"name": ["John"], "age": [30]})
UserPydantic = to_pydantic(df)

Dataclass

from lugia.dataclass import to_dataclass
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# Convert to dataclass
UserDC = to_dataclass(User)

TypedDict

from lugia.typedict import to_typeddict
from typing import TypedDict
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# Convert to TypedDict
UserTD = to_typeddict(User)

Pandas

from lugia.pandas import to_pandas, from_pandas
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

user = User(name="John", age=30)

# Convert to Pandas DataFrame
df = to_pandas(user)
print(df)

# Convert from Pandas to Pydantic
UserModel = from_pandas(df, target_type="pydantic")

Output:

   name  age
0  John   30

Polars

from lugia.polars import to_polars, from_polars
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

user = User(name="John", age=30)

# Convert to Polars DataFrame
df = to_polars(user)
print(df)

# Convert from Polars to Pydantic
UserModel = from_polars(df, target_type="pydantic")

Output:

shape: (1, 2)
┌──────┬─────┐
│ name ┆ age │
│ ---  ┆ --- │
│ str  ┆ i64 │
╞══════╪═════╡
│ John ┆ 30  │
└──────┴─────┘

PySpark

from lugia.pyspark import to_pyspark, from_pyspark
from pyspark.sql import SparkSession
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

spark = SparkSession.builder \
    .appName("test") \
    .master("local[1]") \
    .config("spark.driver.host", "localhost") \
    .config("spark.driver.bindAddress", "127.0.0.1") \
    .getOrCreate()

# Convert to PySpark StructType (schema)
struct_type = to_pyspark(User)
print(f"To PySpark StructType: {struct_type}")

# Convert to PySpark DataFrame (data)
user = User(name="John", age=30)
df = to_pyspark(user, spark_session=spark)
print("To PySpark DataFrame:")
df.show()

# Convert from PySpark to Pydantic
UserModel = from_pyspark(struct_type, target_type="pydantic")

spark.stop()

Output:

To PySpark StructType: StructType([StructField('name', StringType(), True), StructField('age', LongType(), True)])

To PySpark DataFrame:
+----+----+
|name| age|
+----+----+
|John|  30|
+----+----+

SQLAlchemy

from lugia.sqlalchemy import to_sqlalchemy, from_sqlalchemy
from sqlalchemy import MetaData
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# Convert to SQLAlchemy Table
metadata = MetaData()
table = to_sqlalchemy(User, table_name="users", metadata=metadata)
print(f"To SQLAlchemy Table: {table}")
print(f"Columns: {[c.name for c in table.columns]}")

# Convert from SQLAlchemy to Pydantic
UserModel = from_sqlalchemy(table, target_type="pydantic")

Output:

To SQLAlchemy Table: users
Columns: ['name', 'age']

SQLModel

from lugia.sqlmodel import to_sqlmodel, from_sqlmodel
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# Convert to SQLModel
UserSQLModel = to_sqlmodel(User)
print(f"To SQLModel: {UserSQLModel}")

# Convert from SQLModel to Pydantic
UserPydantic = from_sqlmodel(UserSQLModel, target_type="pydantic")

Output:

To SQLModel: <class 'abc.UserSQLModel'>

Type Detection

Lugia can automatically detect the type of your schema or data:

from lugia import detect_type
from pydantic import BaseModel

class User(BaseModel):
    name: str

# Detect type
print(detect_type(User))  # "pydantic"
print(detect_type(User(name="John")))  # "pydantic"

Output:

Type of class: pydantic
Type of instance: pydantic

Error Handling

When a required optional dependency is missing, Lugia raises a clear error:

from lugia.exceptions import MissingDependencyError
from lugia.pandas import to_pandas

try:
    df = to_pandas(some_data)
except MissingDependencyError as e:
    print(e)  # "Missing optional dependency 'pandas' required for Pandas conversions. Install it with: pip install lugia[pandas]"

API Reference

Core Functions

  • convert(source, target, target_type): Unified conversion function
  • detect_type(obj): Detect the type of a schema or data object

Conversion Functions

Each module provides conversion functions:

  • lugia.pydantic.to_pydantic(source): Convert to Pydantic
  • lugia.dataclass.to_dataclass(source): Convert to dataclass
  • lugia.typedict.to_typeddict(source): Convert to TypedDict
  • lugia.pandas.to_pandas(source): Convert to Pandas DataFrame
  • lugia.pandas.from_pandas(df, target_type): Convert from Pandas
  • lugia.polars.to_polars(source): Convert to Polars DataFrame/Schema
  • lugia.polars.from_polars(polars_obj, target_type): Convert from Polars
  • lugia.pyspark.to_pyspark(source, spark_session): Convert to PySpark
  • lugia.pyspark.from_pyspark(pyspark_obj, target_type): Convert from PySpark
  • lugia.sqlalchemy.to_sqlalchemy(source, table_name, metadata): Convert to SQLAlchemy
  • lugia.sqlalchemy.from_sqlalchemy(sa_obj, target_type): Convert from SQLAlchemy
  • lugia.sqlmodel.to_sqlmodel(source): Convert to SQLModel
  • lugia.sqlmodel.from_sqlmodel(sqlmodel_class, target_type): Convert from SQLModel

Development

Setup

# Clone the repository
git clone https://github.com/eddiethedean/lugia.git
cd lugia

# Install with development dependencies
pip install -e ".[dev,all]"

Running Tests

pytest

Code Formatting

black lugia tests

License

MIT License - see LICENSE file for details.

Author

Odos Matthews

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

Inspired by articuno for the optional dependency pattern.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lugia-0.1.1.tar.gz (25.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lugia-0.1.1-py3-none-any.whl (27.8 kB view details)

Uploaded Python 3

File details

Details for the file lugia-0.1.1.tar.gz.

File metadata

  • Download URL: lugia-0.1.1.tar.gz
  • Upload date:
  • Size: 25.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for lugia-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2ea3b081b44e93c6ee41b2a144be7ed4d3d2267e2fe5b2f8c1bcc27eef4b8b32
MD5 f49482b6fb465159b0cda75418075c5e
BLAKE2b-256 4f70a91fcfda45ac708abca0348dbe0626ac80d825c8587dabb94a214929d599

See more details on using hashes here.

File details

Details for the file lugia-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: lugia-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 27.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for lugia-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 759e17b9b2315a664a0972fa6b999e9154e3d63989dc1ec7338edf40127e8b5e
MD5 b9535ad344de4c588f5ad5c7598c400b
BLAKE2b-256 a54fba6b1552884ca3755b290bccd5878eb871633c792599fb2ce79d3928864d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page