Package: simple_model
As the name suggests, this is a very simple model framework. It can be used for data
validation and (de-)serialization.NewHead over tov2now!InstallationInstall with pip:$ pip install --user simple_modelUsageThis allows me to test the examples by taking care of sorting the dictionaries, it is not required for simple_model
to work:>>>frompprintimportpprintExamples:>>>fromsimple_modelimportModel,Attribute>>>classData(Model):...name=Attribute(str)...some_value=Attribute(str,optional=True)...another_value=Attribute(int,fallback=0)>>>pprint(dict(Data(name='test',some_value=None,another_value=12))){'another_value':12,'name':'test','some_value':None}>>>pprint(dict(Data(name='test'))){'another_value':0,'name':'test','some_value':None}>>>init_dict={'name':'test','some_value':'val','another_value':3}>>>pprint(dict(Data(**init_dict))){'another_value':3,'name':'test','some_value':'val'}Initializing with missing attributes while not specifying them as optional or providing a fallback value
will result in aValueErrorcontaining all failed attributes.
Note thatfallbacktakes precedence overoptional, specifying both is unnecessary.Unknown values will be ignored>>>pprint(dict(Data(name='test',unknown_value=True))){'another_value':0,'name':'test','some_value':None}Serialization can be achieved easily, for example>>>importjson>>>defserialize(model):...returnjson.dumps(dict(model))>>>defdeserialize(string):...returnData(**json.loads(string))Since the Model class simply calls the Attribute class for each parameter and the Attribute class in turn calls the
given ‘type’, one could easily use functions instead of types to achieve more complex results and value parsing>>>fromdatetimeimportdatetime>>>defparse_date(string):...returndatetime.strptime(string,'%Y-%m-%d')>>>classData(Model):...date=Attribute(parse_date)>>>dict(Data(date='2015-11-20')){'date':datetime.datetime(2015,11,20,0,0)}Fallback values can also be given as functions>>>deffun():...return"foo">>>classData(Model):...point=Attribute(str,fallback=fun)>>>dict(Data()){'point':'foo'}If you need to verify Lists of objects, use functions>>>classData(Model):...points=Attribute(lambdal:list(map(str,l)))>>>dict(Data(points=['abc','def','ghi'])){'points':['abc','def','ghi']}Or the includedlist_typehelper class>>>fromsimple_model.helpersimportlist_type>>>classData(Model):...points=Attribute(list_type(str))>>>dict(Data(points=['abc','def','ghi'])){'points':['abc','def','ghi']}For more complex data, use Models to verify>>>classSubData(Model):...some_value=Attribute(str)...some_other_value=Attribute(int)>>>classData(Model):...point=Attribute(SubData)>>>pprint(dict(Data(point={'some_value':'abc','some_other_value':12}))){'point':{'some_other_value':12,'some_value':'abc'}}To allow uncommon names, use the Attribute name keyword>>>classData(Model):...point=Attribute(str,name='@point')>>>dict(Data(point='something')){'@point':'something'}>>>dict(Data(**{'@point':'something'})){'@point':'something'}To easily check against expected values you can use the helper functionone_of>>>fromsimple_model.helpersimportone_of>>>classData(Model):...foo=Attribute(one_of('bar','foobar'))>>>dict(Data(foo='bar')){'foo':'bar'}>>>dict(Data(foo='foo'))# doctest: +ELLIPSISTraceback(mostrecentcalllast):...ValueError:{...'exception':"ValueError: must be one of ('bar', 'foobar') but was 'foo'"...}If you want to disallow unknown values, set the __ignore_unknown__ attribute to False>>>classData(Model):...__ignore_unknown__=False......point=Attribute(str)>>>Data(point='abc',other='def')Traceback(mostrecentcalllast):...ValueError:Unknownkey"other"withvalue"def"You can now set Models to be mutable and change Attribute values after creation>>>classData(Model):...point=Attribute(int)>>>d=Data(point=1)>>>d.point1>>>d.point=2>>>d.point2>>>d.__mutable__=False>>>d.point=3Traceback(mostrecentcalllast):...AttributeError:ModelisimmutableTestsTo run the tests use tox:$ toxIssuesPlease submit any issues onGitHub.ChangelogseeCHANGELOGLicenseseeLICENSE