internetimagery / to

Generic framework for "automatic" conversions between types.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TO(...) Build Status

Generic all purpose semi-static type converter for python! For automatic, but meaningful conversions.

    from to import shield, add_conversion, to

    @shield(str, str)
    def concat(prefix, suffix):
    	return prefix + suffix

    assert concat("one ", 23) == "one 23"

    concat([1,2,3], 456)
    # TypeError: Could not convert [] to <class 'str'>. Perhaps some conversion steps are missing.

    add_conversion(1, list, (), str, (), lambda x: "".join(map(lambda y: to(y, str), x)))

    assert concat([1,2,3], 456) == "123456"

The tool takes functions registered with their input and output types, and cost of computation (plus optionally some extra context). Then builds a graph for converting optimally and meaninfully through those types.

This provides an alternate way to create basic constructors for classes, as well as a means to easily work in a more type-centric way without the hassle of leaping through nested hoops.

NOTE: Extreme experimental warning. Do not use timidly in production. However DO feel free to mess around with the tool, the concept, and even reach out with any ideas or thoughts.

How To...

    from to import *
    assert to(123, str) == "123" # Drumroll!

Not impressed? Ok, how about you add your own classes!

    @dataclass
    class Age:
        value: int

    # Cost, In_Type, In_Context, Out_Type, Out_Context, Callable
    add_conversion(1, int, (), Age, (), Age)

    assert to(18) == Age(18)

Or maybe you've wrapped a class with a dependency?

    @dataclass
    class Person:
        age: Age

    add_conversion(1, Age, (), Person, (), Person)

    assert to(18, Person) == Person(Age(18))

And back again!

    from operator import attrgetter

    add_conversion(1, Age, (), int, (), attrgetter("value"))
    add_conversion(1, Person, (), Age, (), attrgetter("age"))

    assert to(Person(Age(18)), str) == "18"

Units anyone?

    @dataclass
    class Centemeter:
        value: float
    
    @dataclass
    class Meter:
        value: float

    add_conversion(2, Meter, (), Centemeter, (), lambda x: Centemeter(x.value * 100))

    assert to(Meter(2), Centemeter) == Centemeter(200)

Oh damn, Age takes a number as an int, but I have a str...

    assert to("123", Person) == Person(Age(123))

Also... I have a bool... not sure this is what I want... but it works!

    assert to(True, Person) = Person(Age(1))

Now we're getting into the weeds... can't convert the string directly to a number, but can if we make it a bool first!

Life finds a way!

    val = to("not a number", Person)
    # Warning: ValueError: invalid literal for int() with base 10: 'not a number'
    assert val = Person(Age(1))

Hmm... I want to be able to convert my units to and from unitless floats...

    add_conversion(1, Meter, (), float, (), attrgetter("value"))
    add_conversion(1, float, (), Centemeter, (), Centemeter)

    assert to(Meter(2), Centemeter) == Centemeter(2) # Oh wait, noo!

Yeah... be careful with that!

About

Generic framework for "automatic" conversions between types.

License:MIT License


Languages

Language:Rust 78.4%Language:Python 20.9%Language:Shell 0.5%Language:Batchfile 0.2%