Package: colt
🐎 ColtEffortlessly configure and construct Python objects withcolt, a lightweight library inspired byAllenNLPandTangoQuick LinksIntroductionInstallationUsageInfluenceskaggle Titanic ExampleIntroductioncoltis a lightweight configuration utility for Python objects, allowing you to manage complex configurations for your projects easily.
Written solely using the Python standard library,coltcan construct class objects from JSON-convertible dictionaries, making it simple to manage your settings using JSON or YAML files. The library is particularly suitable for thedependency injectiondesign pattern.Some key features of colt include:No external dependencies, as it is built using the Python standard library.Construct class objects from JSON-convertible dictionaries.Manage complex configurations using JSON or YAML files.Well-suited for dependency injection design patterns.Inspired byAllenNLPandTango,coltaims to offer similar functionality while focusing on a more lightweight and user-friendly design.Differences betweencoltand AllenNLP/TangoWhile both AllenNLP and Tango construct objects based on the class signature, colt focuses on building objects from the type specified in the configuration. Although colt is aware of the class signature, it primarily uses it for validation when passing objects created from the configuration.This means that with colt, you don't necessarily need to have the target class available for configuration. As a result, you can conveniently build objects using the colt.build method without requiring the specific class to be present. This distinction makes colt more flexible and easier to work with in various scenarios.InstallationTo install colt, simply run the following command:pipinstallcoltUsageBasic ExampleHere is a basic example of how to usecoltto create class objects from a configuration dictionary:importtypingastpimportcolt@colt.register("foo")classFoo:def__init__(self,message:str)->None:self.message=message@colt.register("bar")classBar:def__init__(self,foos:tp.List[Foo])->None:self.foos=foosif__name__=="__main__":config={"@type":"bar",# specify type name with `@type`"foos":[{"message":"hello"},# type of this is inferred from type-hint{"message":"world"},]}bar=colt.build(config)assertisinstance(bar,Bar)print(" ".join(foo.messageforfooinbar.foos))# => "hello world"FunctionalityGuiding Object Construction with a Target ClassYou can guide the object construction process incoltby passing the desired class as the second argument to thecolt.buildmethod.
Here's an example demonstrating this functionality:@colt.register("foo")classFoo:def__init__(self,x:str)->None:self.x=xconfig={"x":"abc"}# Pass the desired class as the second argumentobj=colt.build(config,Foo)assertisinstance(obj,Foo)assertobj.x=="abc"By providing the target class tocolt.build, you can ensure the constructed object is of the desired type while still using the configuration for parameter values.Registrableclasscoltprovides the Registrable class, which allows you to divide the namespace for each class.
This can be particularly useful when working with larger projects or when you need to manage multiple classes with the same name but different functionality.Here is an example of how to use theRegistrableclass to manage different namespaces forFooandBar:importcoltclassFoo(colt.Registrable):passclassBar(colt.Registrable):pass@Foo.register("baz")classFooBaz(Foo):pass@Bar.register("baz")classBarBaz(Bar):pass@colt.register("my_class")classMyClass:def__init__(self,foo:Foo,bar:Bar):self.foo=fooself.bar=barif__name__=="__main__":config={"@type":"my_class","foo":{"@type":"baz"},"bar":{"@type":"baz"}}obj=colt.build(config)assertisinstance(obj.foo,FooBaz)assertisinstance(obj.bar,BarBaz)Lazyclasscoltoffers aLazyclass for deferring object creation until needed, which can be useful in cases where constructing an object is computationally expensive or should be delayed until certain conditions are met.Here's a concise example demonstrating theLazyclass usage withcolt:importdataclassesimportcoltfromcoltimportLazy@dataclasses.dataclassclassFoo:x:stry:int@dataclasses.dataclassclassBar:foo:Lazy[Foo]bar=colt.build({"foo":{"x":"hello"}},Bar)# Additional parameters can be passed when calling the construct() methodfoo=bar.foo.construct(y=10)In this example,Barcontains aLazyinstance ofFoo, which will only be constructed whenconstruct()is called.
When callingconstruct(), you can pass additional parameters required for the object's construction.
This approach allows you to control when an object is created, optimizing resource usage and computations while providing flexibility in passing parameters.Advanced Examplesscikit-learn ConfigurationHere's an example of how to usecoltto configure ascikit-learnmodel:importcoltfromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitif__name__=="__main__":config={# these types are imported automatically if type name is not registerd"@type":"sklearn.ensemble.VotingClassifier","estimators":[("rfc",{"@type":"sklearn.ensemble.RandomForestClassifier","n_estimators":10}),("svc",{"@type":"sklearn.svm.SVC","gamma":"scale"}),]}X,y=load_iris(return_X_y=True)X_train,X_valid,y_train,y_valid=train_test_split(X,y)model=colt.build(config)model.fit(X_train,y_train)valid_accuracy=model.score(X_valid,y_valid)print(f"valid_accuracy:{valid_accuracy}")In this example,coltis used to configure aVotingClassifierfrom scikit-learn, combining aRandomForestClassifierand anSVC.
The colt configuration dictionary makes it easy to manage the settings of these classifiers and modify them as needed.Influencescoltis heavily influenced by the following projects:AllenNLP: A popular natural language processing library, which provides a powerful configuration system for managing complex experiments.Tango: A lightweight and flexible library for running machine learning experiments, designed to work well with AllenNLP and other libraries.These projects have demonstrated the value of a robust configuration system for managing machine learning experiments and inspired the design ofcolt.