Skip to main content

Gives a reproducible manner to your objects and can serialize them in 100% pythonic format.

Project description

Semi-text-pickling in pure python.
If you meet just a few restrictions, you can store classes
state into a python file and import or evaluate it somewhere
else or later on. You can even use it as a database unless
the amount of data is huge.

repr(object)

Does repr stand for “representation” or “reproduction”?
According to python documentation __repr__ functionality has two
separate approaches. From https://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 string
that would yield an object with the same value when passed to eval(),
otherwise the representation is a string enclosed in angle brackets
that contains the name of the type of the object together with
additional information often including the name and address of
the object. A class can control what this function returns for
its instances by defining a __repr__() method.

1. reproducible repr:

For several native objects it returns a string that can be used
to reproduce given object, i.e. to create a copy of given object.
a = [1, 3.141559, None, "string"]
statement_str = repr(a)
assert statement_str == '[1, 3.141559, None, "string"]'

You may tell that repr of an object is reproducible if this is meet:

a = [1, 3.14159, None, "string"]
statement_str = repr(a)
assert repr(eval(statement_str)) == statement_str
# if the object implements __eq__ this should be also true:
assert eval(statement_str) == a

2. descriptive repr:

Unfortunately python does not serve the “reproducible repr” out of the box
for types defined by user:
class Car(object):
    def __init__(self, body_type, engine_power):
        self.body_type = body_type
        self.engine_power = engine_power

car = Car("coupe", 124.0)
# repr(car) == '<__main__.Car object at 0x7f0ff6313290>'
# but using renew:

import renew

@renew.make_renew_reprs(namespace="bar")
class ReproducibleCar(object):
    def __init__(self, body_type, engine_power):
        self.body_type = body_type
        self.engine_power = engine_power

car2 = ReproducibleCar("sedan", 110.0)
assert repr(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.

import renew

repr_from_cars = renew.make_reproducible(namespace="cars", dependency="that.things")
repr_from_persons = renew.make_reproducible(namespace="persons", dependency="living.things")

class Car(repr_from_cars):
    def __init__(self, body_type, engine_power, fuel, seats, color=None):
        self.body_type = body_type
        self.engine_power = engine_power
        self.fuel = fuel
        self.seats = seats
        self.color = color

class Driver(repr_from_persons):
    def __init__(self, first_name, last_name, *cars):
        self.first_name = first_name
        self.last_name = last_name
        self.cars = cars

car_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)

assert repr(driver_1) == "persons.Driver('Blenda', 'Klapa', cars.Car('Truck', 120.0, 'diesel', 2))"
assert repr(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/

from living.things import persons
from that.things import cars

blenda = 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 that ReproducibleCar does not explicitly implement the __repr__, but the renew.reproducible
decorator supplements it (overrides it if any has been defined before).
renew.reproduction inspects constructor’s argument specification
of decorated class and yields a string that tries to be a call statement composed of
  • namespace, e.g. your package name (according to desired importing convention)

  • given class name

  • given class’ attributes values, that have the same names and order as constructor arguments

That forms the only one usage restriction:

The class has to store all the constructor arguments in its attributes with the same name (as in ReproducibleCar definition above).

Limitations

Besides the statement above:

  • constructor arguments have to get exactly same name as instance attributes

  • plain keyword-arguments of constructors are not (yet) supported (default-arguments work well, however)

  • keys of plain dict being “complex” objects are getting a bit ugly layout if repr of given key spans multiple lines.

  • renew does not cross-reference objects while serializing.
    Although neither pickle nor marshal does cross-reference, renew most probably could do it but it’s
    hard to tell how to let renew know where and how a chain of objects have to be cross-referenced.
  • For ultra-capable meta programming MacroPy: https://pypi.org/project/MacroPy/ would be a better choice.

For full list of features and usage examples, please refer to unit tests, especially tests/test_renew.py.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

renew-0.3.1.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

renew-0.3.1-py2.py3-none-any.whl (18.8 kB view details)

Uploaded Python 2Python 3

File details

Details for the file renew-0.3.1.tar.gz.

File metadata

  • Download URL: renew-0.3.1.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.0 CPython/2.7.13

File hashes

Hashes for renew-0.3.1.tar.gz
Algorithm Hash digest
SHA256 290a5c2a2c0ece6e7a53cc2d4c1b7586d0714347652ce14a3ca0787f85086b46
MD5 29f79de9ab3b2426bc6a1d1c120e2952
BLAKE2b-256 0d1286fca19e706b0a1cb2677e3eb0f332cc7931fad1872ff828e81dbed9bb4b

See more details on using hashes here.

File details

Details for the file renew-0.3.1-py2.py3-none-any.whl.

File metadata

  • Download URL: renew-0.3.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 18.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.0 CPython/2.7.13

File hashes

Hashes for renew-0.3.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 e9d4b7b1ca47e266e7ae742b352c6eda4b70e8b89de3a89936634a2d3b656ddc
MD5 b526f66bf43362e962cf1f0315bb26ee
BLAKE2b-256 a1a577da6b080acfe1f6951506103080932119b336682abd51b3a7bbf5d89434

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page