Package: renew
Semi-text-pickling in pure python.If you meet just a few restrictions, you can store classesstate into a python file and import or evaluate it somewhereelse or later on. You can even use it as a database unlessthe amount of data is huge.1 minute - example:importrenewclassThatNiceClass(renew.Mold):# manual implementation of __init__ is needed. Constructor_arguments# have to be actual names of this class attributesdef__init__(self,f_a,f_b,*f_c,**f_d):self.f_a,self.f_b,self.f_c,self.f_d=f_a,f_b,f_c,f_dc=ThatNiceClass(1,2,3,4,five=5,six=6)assertrepr(c)=="ThatNiceClass(1, 2, 3, 4, five=5, six=6)"assertc==eval(repr(c))# __eq__ implementedassertrepr(c)==repr(eval(repr(c)))# pure reproduction, instance "survives" evalclassSecondClass(renew.Mold):_cls_namespace="foo_pkg"def__init__(self,one,two="number two",three=None):self.one,self.two,self.three=one,two,threes1=SecondClass(1)s2=SecondClass(3.14159,"non default")s3=SecondClass("Lorem ipsum dolor sit amet, consectetur adipiscing elit")s4=SecondClass(4,three=ThatNiceClass(1,2,3,4,five=5,six=6))d=ThatNiceClass(s1,s2,lorem=s3,im_nesting=s4)assertrepr(d)=="""\ThatNiceClass(
    foo_pkg.SecondClass(1),
    foo_pkg.SecondClass(3.14159, 'non default'),
    im_nesting=foo_pkg.SecondClass(4, three=ThatNiceClass(1, 2, 3, 4, five=5, six=6)),
    lorem=foo_pkg.SecondClass('Lorem ipsum dolor sit amet, consectetur adipiscing elit'),
)"""The__repr__story - repr(object)Doesreprstand for “representation” or “reproduction”?According to python documentation__repr__functionality has twoseparate approaches. Fromhttps://docs.python.org/3/library/functions.html#repr(v 3.7.2)repr(object)Return a string containing a printable
representation of an object.For many types, this function makes an attempt to return a stringthat would yield an object with the same value when passed to
eval(),otherwise the representation is a string enclosed in angle
bracketsthat contains the name of the type of the object together withadditional information often including the name and address ofthe object. A class can control what this function returns forits instances by defining a__repr__()method.1. reproducible repr:For several native objects it returns a string that can be usedto reproduce given object, i.e. to create a copy of given object.a=[1,3.141559,None,"string"]statement_str=repr(a)assertstatement_str=='[1, 3.141559, None, "string"]'You may tell that repr of an object isreproducibleif this is meet:a=[1,3.14159,None,"string"]statement_str=repr(a)assertrepr(eval(statement_str))==statement_str# if the object implements __eq__ this should be also true:asserteval(statement_str)==a2. descriptive repr:Unfortunately python does not serve the “reproducible repr” out of the
boxfor types defined by user:classCar(object):def__init__(self,body_type,engine_power):self.body_type=body_typeself.engine_power=engine_powercar=Car("coupe",124.0)# repr(car) == '<__main__.Car object at 0x7f0ff6313290>'# but using renew:importrenewclassReproducibleCar(renew.Mold):_cls_namespace="bar"def__init__(self,body_type,engine_power):self.body_type=body_typeself.engine_power=engine_powercar2=ReproducibleCar("sedan",110.0)assertrepr(car2)=='bar.ReproducibleCar("sedan", 110.0)'The method above is implemented as a decorator, but you can also use a
inheritance to get the same result.importrenewclassCar(renew.Mold):_cls_namespace="cars"_cls_dependency="that.things"def__init__(self,body_type,engine_power,fuel,seats,color=None):self.body_type=body_typeself.engine_power=engine_powerself.fuel=fuelself.seats=seatsself.color=colorclassDriver(renew.Mold):_cls_namespace="persons"def__init__(self,first_name,last_name,*cars):self.first_name=first_nameself.last_name=last_nameself.cars=carscar_1=Car("Truck",120.0,"diesel",2)car_2=Car("Van",145.0,"diesel",seats=7,color="silver")car_3=Car("Roadster",210.0,"gasoline",seats=2)driver_1=Driver("Blenda","Klapa",car_1)driver_2=Driver("Trytka","Blotnick",car_2,car_3)assertrepr(driver_1)==".Driver('Blenda', 'Klapa', cars.Car('Truck', 120.0, 'diesel', 2))"assertrepr(driver_2)=="""\persons.Driver(
    'Trytka',
    'Blotnick',
    cars.Car('Van', 145.0, 'diesel', 7, 'silver'),
    cars.Car('Roadster', 210.0, 'gasoline', 2),
)"""renew.serialize("/tmp/target.py",blenda=driver_1,trytka=driver_2)The created file looks like this:#!/usr/bin/env python# -*- coding: utf-8 -*-# This file has been created with renew.# A py-pickling tool: https://pypi.org/project/renew/fromliving.thingsimportpersonsfromthat.thingsimportcarsblenda=persons.Driver('Blenda','Klapa',cars.Car('Truck',120.0,'diesel',2))trytka=persons.Driver('Trytka','Blotnick',cars.Car('Van',145.0,'diesel',7,'silver'),cars.Car('Roadster',210.0,'gasoline',2),)How it works?Note thatReproducibleCardoes not explicitly implement the__repr__, but therenew.reproducibledecorator supplements it (overrides it if any has been defined
before).renew.reproductioninspects constructor’s argument specificationof decorated class and yields a string that tries to be a call
statement composed ofnamespace, e.g. your package name (according to desired importing
convention)given class namegiven class’ attributes values, that have the same names and order as
constructor argumentsThat forms the only one usage restriction:The class has to store all the constructor arguments in its attributes
with the same
name(as inReproducibleCardefinition above).Variadic args have to be stored in the instance either aslist,tuple(no cast needed),setorOrderedDict(set is rendered with sorting). Keyword args have to be stored in the
instance as adictorOrderedDict.fromcollectionsimportOrderedDictimportrenewclassThatClass(renew.Mold):def__init__(self,x=1,*others,**kw_args):self.x=xself.others=OrderedDict(others)self.kw_args=kw_argsthat=ThatClass(3.14159,("a","A"),("b","B"),one=1,two=2,many=666)assertrepr(that)=="ThatClass(3.14159, many=666, one=1, two=2)"assertthat.x==3.14159assertthat.others==OrderedDict([("a","A"),("b","B")])assertthat.kw_args==dict(one=1,two=2,many=666)Limitationskeys of plaindictbeing “complex” objects get a bit ugly layout
if repr of given key spans multiple lines.renewdoes not cross-reference objects while serializing.Although neitherpicklenormarshaldoes cross-reference,renewmost probably could do it but it’shard to tell how to let renew know where and how a chain of objects
have to be cross-referenced.For ultra-capable meta programmingMacroPy:https://pypi.org/project/MacroPy/would be a better choice.For full list of features and usage examples, please refer to unit
tests, especiallytests/test_renew.py.