This is a pre-production deployment of Warehouse, however changes made here WILL affect the production instance of PyPI.
Latest Version Dependencies status unknown Test status unknown Test coverage unknown
Project Description

A Python dictionary implementation that supports properties, class variables and inheritance for your sophisticated templating needs.

tested for Python 2.6, 2.7 and 3.3

Motivation

Overriding a specific behavior of a class is easy: create a subclass (or even just an instance) and just implement the aspect you are interested with and be done. Not so with templates, though. If you want to change one part of it, you need to override the entire template, essentially forking the work of the template author.

propdict counters this by allowing the template author to put logic and behavior into the data that goes into the template rather than the template itself.

A consumer of the template can then simply subclass the propdict based data, override the specific aspects and leave the template as-is.

Basic Features

propdict instances behave almost exactly as a regular dictionary, except that you can access values using the dict notation or attribute notation:

>>> server_foo.ip_addr
'10.0.0.1'
>>> server_foo['ip_addr']
'10.0.0.1'
>>> print server_foo['ifconfig']
ifconfig_em0="inet 10.0.0.1 netmask 255.255.255.0"
>>> print server_foo.ifconfig
ifconfig_em0="inet 10.0.0.1 netmask 255.255.255.0"

The same works also for assignment:

>>> server_foo.ip_addr = '192.168.1.1'
>>> print server_foo.ip_addr
192.168.1.1
>>> server_foo['ip_addr'] = '127.0.0.1'
>>> print server_foo.ip_addr
127.0.0.1

Assignment also works for changing properties, of course, as you saw in the example:

>>> server_foo.ifconfig = u'foo mask'
>>> print server_foo.ifconfig
foo mask

It is noteworthy, though, that you cannot delete properties. However, you can delete custom values of properties, but that just re-exposes their original value:

>>> del server_foo['ifconfig']
>>> print server_foo.ifconfig
ifconfig_em0="inet 127.0.0.1 netmask 255.255.255.0"
>>> del server_foo['ifconfig']
Traceback (most recent call last):
...
KeyError: 'ifconfig'

Example

Say you’re the author of a set of templates for configuring *NIX style systems. Naturally, a lot of these templates will be using the same values, for example the IP address of the machine being configured. Now, some other values in turn depend on the value of the IP address, too. Let’s say one such file has a line configuring the network interface using a netmask, so you end up with a template containing the following snippet:

>>> template = '''ifconfig_%(iface)s="inet %(ip_addr)s netmask %(netmask)s"'''

Given a dictionary with the necessary data, this would then evaluate to the following:

>>> print template % dict(ip_addr='192.168.1.1', iface='em0', netmask='255.255.255.0')
ifconfig_em0="inet 192.168.1.1 netmask 255.255.255.0"

This works fine for most cases, but what if a particular host you deploy is behind a NAT and needs an entirely different configuration that doesn’t follow the above format? You now either need to create a custom version of the template (which, unlike the basic example above, could well be of non-trivial length and complexity) that differs in just that one line or the author of the template needs to work in (yet another) special edgecase that won’t affect 99% of the users.

The third solution is to keep (that line of) the templates as simple as possible:

>>> template = "%(ifconfig)s"

and put the logic into the dictionary. Like so:

>>> from propdict import propdict
>>> class Host(propdict):
...     ip_addr = None
...     iface = 'em0'
...     netmask = '255.255.255.0'
...     @property
...     def ifconfig(self):
...         return '''ifconfig_%(iface)s="inet %(ip_addr)s netmask %(netmask)s"''' % self
>>> server_foo = Host(ip_addr='10.0.0.1')
>>> print template % server_foo
ifconfig_em0="inet 10.0.0.1 netmask 255.255.255.0"

So far so good, we got the same result as above. But let’s consider another server:

>>> server_bar = Host(ip_addr='10.0.0.2', ifconfig='ifconfig_em1="inet 10.0.0.2 netmask 255.255.0.0"')
>>> print template % server_bar
ifconfig_em1="inet 10.0.0.2 netmask 255.255.0.0"

Notice, how the new definition of ifconfig contains a new value for the interface (perhaps this host has two built-in) but still references ip_addr. In this case it might be better to not simply provide a new, static value but to come up with a better implementation of the property:

>>> class HostBar(Host):
...     iface_2 = 'em1'
...     @property
...     def ifconfig(self):
...         return '''ifconfig_%(iface_2)s="inet %(ip_addr)s netmask %(netmask)s"''' % self
>>> server_bar = HostBar(ip_addr='10.0.0.2', netmask='255.255.0.0')
>>> print template % server_bar
ifconfig_em1="inet 10.0.0.2 netmask 255.255.0.0"

So, we were able to provide an arbitrary new value for the ifconfig key by changing just that and without touching the template, while still keeping the default behavior (it’s automatically computed for you from the interface and IP address).

Installation

propdict has no dependencies and can simply be installed as an egg using your preferred tool, such as pip, easy_install, buildout, setuptools. You know the drill.

Run Tests

To make sure that propdict works for your setup, run its tests. You need a checkout from github and py.test, perhaps like so:

git clone git@github.com:tomster/propdict
cd propdict
virtualenv .
source bin/activate
pip install pytest-cov

Then, to run all tests (including this README):

bin/py.test

If you made some changes and want to know whether you broke coverage:

bin/py.test --cov propdict --cov-report html --cov-report term test_propdict.py

Changelog

1.1 - 201310-18

  • Packaging fix [fschulze]
  • Support dict in constructor [fschulze]

1.0 - 2013-10-17

After several months in production, released the identical code as stable.

0.1a1 - 2013-03-17

Initial public release

Release History

Release History

1.1

This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.0

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.1a1

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Download Files

Download Files

TODO: Brief introduction on what you do with files - including link to relevant help section.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
propdict-1.1.zip (12.9 kB) Copy SHA256 Checksum SHA256 Source Oct 18, 2013

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS HPE HPE Development Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting