Seamlessly handle type conversion during operations in Python
Project description
๐ TypeFlow
Because Life's Too Short for TypeError Exceptions!
from typeflow import flow, TypeFlowContext
with TypeFlowContext():
answer = flow(42) + " is the answer to everything" # Works like magic! ๐ช
print(answer) # "42 is the answer to everything"
Output
42 is the answer to everything
What is TypeFlow?
TypeFlow is a Python package that makes type conversion seamless and painless. Say goodbye to those annoying TypeError: can only concatenate str (not "int") to str exceptions that haunt your dreams!
Why Do I Need This in My Life?
Ever tried to:
- Add a number to a string?
- Concatenate a list with text?
- Do math with values from JSON or CSV files without checking types?
TypeFlow handles all these scenarios with grace, so you can focus on building cool stuff instead of writing repetitive type conversion code.
Why Use TypeFlow?
๐ Boost Development Speed
- Write Less Code: No more manual type checking and conversion
- Reduce Bugs: Eliminate an entire class of type-related errors
- Faster Prototyping: Focus on features, not type compatibility
๐ก๏ธ Improve Code Quality
- More Readable Code: Express your intent clearly without conversion noise
- Easier Maintenance: Less code means less to maintain
- Better Error Handling: Consistent approach to type conversion issues
๐ช Handle Real-World Challenges
- Messy Input Data: Process API responses with inconsistent types
- Form Data: Handle form submissions where all values are strings
- CSV/JSON Imports: Process tabular data without type headaches
- Database Results: Work with query results that might return mixed types
- Configuration Files: Parse config values without type validation
๐ Great for Learning
- Perfect for Beginners: Remove frustrating type errors that discourage new Python programmers
- Educational Tool: Learn about Python's type system in a forgiving environment
- Teaching Aid: Explain type conversion without getting bogged down in details
TypeFlow strikes the perfect balance between Python's dynamic nature and the safety of strong typing. It respects the "principle of least surprise" while adding powerful capabilities to your code.
Installation
pip install typeflow
current version:0.13.6
Quick Start Guide
TypeFlow offers multiple ways to handle type conversions based on your needs:
from typeflow import flow, TypeFlowContext, with_typeflow
# Method 1: Use flow() directly - the most explicit approach
result1 = flow(42) + " unicorns"
print(result1) # "42 unicorns"
# Method 2: Use TypeFlowContext for a block of code
with TypeFlowContext():
# Remember to wrap values with flow() inside the context
num = flow(123)
text = " in context"
result2 = num + text
print(result2) # "123 in context"
# Method 3: Use decorator for functions
@with_typeflow
def make_sandwich(bread, fillings):
# Arguments are auto-wrapped - no need for flow()
return bread + fillings
print(make_sandwich("Wheat bread with ", 3)) # "Wheat bread with 3"
Output
42 unicorns
123 in context
Wheat bread with 3
๐งฐ API Reference
Core Functions
flow(value)
Wraps any value in a TypeFlow type for seamless operations. This is the foundation of TypeFlow.
num = flow(42)
text = flow("answer")
print(num + text) # "42answer"
# Works with all major types
list_flow = flow([1, 2, 3])
print(list_flow + " items") # "1, 2, 3 items"
Output
42answer
1, 2, 3 items
enable() and disable()
Controls TypeFlow globally - use with caution.
from typeflow import enable, disable
# Enable TypeFlow globally (affects new objects created after enabling)
enable()
# Create new variables using built-in constructors
new_int = int(42)
text = " answers"
print(new_int + text) # "42 answers"
# Disable when done to restore normal Python behavior
disable()
Output
42 answers
Note: When using enable(), use the built-in constructors (int(), str(), etc.) to create values that can properly handle mixed operations.
Context Managers
TypeFlowContext(verbose=None, raise_errors=None)
Creates a safe playground where TypeFlow is active.
with TypeFlowContext(verbose=True): # See what's happening under the hood
# Use flow() to wrap existing values
result = flow([1, 2, 3]) + " items in cart"
print(result)
# Or create new values with type constructors inside the context
new_value = int(456)
print(new_value + " is a new value")
Output
typeflow - INFO - Converting list to string for concatenation with string: [1, 2, 3] -> '1, 2, 3'
1, 2, 3 items in cart
typeflow - INFO - Converting int to string for concatenation with string: 456 -> '456'
456 is a new value
Decorators
@with_typeflow(verbose=None, raise_errors=None, auto_flow=True)
Makes functions automatically handle mixed types.
# Arguments are automatically wrapped with flow()
@with_typeflow
def calculate_total(quantity, price, coupon=0):
# All arguments are pre-wrapped, so operations just work
return "Total: $" + (quantity * price) - coupon
print(calculate_total(3, 9.99, 5)) # "Total: $24.97"
# For manual control, disable auto_flow
@with_typeflow(auto_flow=False)
def manual_calculate(a, b):
# Here you need to use flow() manually
return flow(a) * flow(b)
print(manual_calculate(5, "6")) # Will convert "6" to a number and multiply
Output
Total: $24.97
30
Configuration
configure(verbose=None, raise_errors=None, log_level=None)
Customize TypeFlow's behavior to your liking.
from typeflow import configure, flow
import logging
# Set up verbose logging to see what TypeFlow is doing
configure(verbose=True, log_level=logging.INFO)
# Try a conversion that requires type handling
result = flow(42) + " magic beans"
print(result)
# Be strict and raise errors on conversion problems
configure(raise_errors=True)
Output
typeflow - INFO - Converting int to string for concatenation with string: 42 -> '42'
42 magic beans
Custom Converters
register_converter(target_type, source_type, converter_function)
Teach TypeFlow how to handle your custom classes.
from typeflow import register_converter, flow, TypeFlowContext
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Register how to convert Person to string
register_converter('str', Person, lambda p: f"{p.name} ({p.age})")
register_converter('int', Person, lambda p: p.age)
with TypeFlowContext():
person = Person("Alice", 30)
# Now you can do string concatenation with a Person
greeting = flow("Hello, ") + person # "Hello, Alice (30)"
print(greeting)
# And numeric operations using the age
age_in_months = flow(person) * 12 # 360
print(f"Age in months: {age_in_months}")
Output
Hello, Alice (30)
Age in months: 360
Real-World Examples
Data Processing
from typeflow import flow
# Mixed data from a CSV file or API
user_data = [
{"id": "1001", "visits": 5, "active": "true"},
{"id": 1002, "visits": "12", "active": 1},
{"id": 1003, "visits": None, "active": "false"}
]
# Process without worrying about types
def process_user(user):
activity_score = flow(user["visits"]) * (1 if flow(user["active"]) else 0.5)
return f"User {user['id']} has a score of {activity_score}"
for user in user_data:
print(process_user(user))
Output
User 1001 has a score of 5.0
User 1002 has a score of 12.0
User 1003 has a score of 0.0
Form Input Processing
from typeflow import with_typeflow
# Input values from a web form
form_data = {
"quantity": "3",
"price": 24.99,
"discount": "5",
"is_member": "true"
}
@with_typeflow
def calculate_order(quantity, price, discount=0, is_member=False):
subtotal = quantity * price
member_discount = subtotal * 0.1 if is_member else 0
return subtotal - discount - member_discount
total = calculate_order(
form_data["quantity"],
form_data["price"],
form_data["discount"],
form_data["is_member"]
)
print(f"Order total: ${total:.2f}")
Output
Order total: $62.47
Command-Line Interface
TypeFlow comes with a simple command-line interface:
# Show version information
typeflow --version
# Enable TypeFlow globally
typeflow --enable
# Enable with verbose mode
typeflow --enable --verbose
# Disable TypeFlow
typeflow --disable
Output
TypeFlow version 0.13.6
# When enabling:
TypeFlow has been enabled globally
# When disabling:
TypeFlow has been disabled globally
Limitations
- Currently, TypeFlow works best when explicitly wrapping values with
flow(). Globalenable()works but requires creating new values using type constructors. - Due to Python's immutable built-in types, patching existing values directly isn't possible in all cases.
- Performance impact is minimal for most operations, but may be noticeable in tight loops with many conversions.
Uploading to PyPI
If you've made improvements to TypeFlow and want to share them with the world, here's how to upload your package to PyPI:
1. Prepare your package
Make sure your package structure is correct:
TypeFlow/
โโโ typeflow/
โ โโโ __init__.py
โ โโโ core.py
โ โโโ ...
โโโ setup.py
โโโ README.md
โโโ LICENSE
2. Install build tools
pip install build twine
3. Build distribution packages
From the project root directory, run:
python -m build
This creates distribution packages in the dist/ directory.
4. Upload to PyPI
Test PyPI first (recommended)
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
Upload to production PyPI
python -m twine upload dist/*
You'll need to provide your PyPI username and password or API token.
5. Verify installation
# From test PyPI
pip install --index-url https://test.pypi.org/simple/ typeflow
# From production PyPI
pip install typeflow
Example Output
Uploading distributions to https://upload.pypi.org/legacy/
Uploading typeflow-0.13.6-py3-none-any.whl
100% โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 21.3/21.3 kB โข 00:00 โข ?
Uploading typeflow-0.13.6.tar.gz
100% โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 19.4/19.4 kB โข 00:00 โข ?
View at: https://pypi.org/project/typeflow/0.13.6/
Publishing with GitHub Actions
TypeFlow uses GitHub Actions for automated publishing to PyPI. To set up your own fork for publishing:
-
Create a PyPI API token:
- Go to https://pypi.org/manage/account/
- Create an API token with the scope limited to your project
-
Set up GitHub repository:
- In your repository, go to Settings > Environments
- Create a new environment named
pypi - Add a secret called
PYPI_API_TOKENwith your PyPI token value
-
Set up PyPI Trusted Publisher:
- In PyPI project settings, add a new "Trusted Publisher"
- Configure with these values:
- PyPI Project Name: typeflow
- Owner: your GitHub username or organization name
- Repository name: typeflow
- Workflow name: publish.yml
- Environment name: pypi
-
Publish a new version:
- Update version in
setup.py - Create a new GitHub Release
- The workflow will automatically publish to PyPI
- Update version in
This implements modern OIDC authentication between GitHub and PyPI, eliminating the need for long-lived API tokens.
Philosophy
TypeFlow follows the "batteries included" and "it should just work" philosophy of Python, tackling one of the few remaining pain points in Python's smooth developer experience.
"In Python, we trust; with TypeFlow, we flow."
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_typeflow-0.13.6.tar.gz.
File metadata
- Download URL: python_typeflow-0.13.6.tar.gz
- Upload date:
- Size: 19.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02c9fd65bb9dc927bb156585c7dd5a8860b7f94ad336fb25e38ea1a99145236a
|
|
| MD5 |
2408d2e1034069223a9d7d8b1e98ad8b
|
|
| BLAKE2b-256 |
eab93e172111665f4157cb57c41d1d249423fb7083a07525379e62a351d219ce
|
File details
Details for the file python_typeflow-0.13.6-py3-none-any.whl.
File metadata
- Download URL: python_typeflow-0.13.6-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf6827287900905bfa37c09513b9215eacb32fea6530601e5552452f1945b826
|
|
| MD5 |
80a5db759ca15e4ff829a9fa36a13263
|
|
| BLAKE2b-256 |
c9f940a9e8afd40d3e5b53b7618b624f5777e510c38bd159b2f4e23e7e3667c9
|