warownia1
warownia1

Reputation: 2945

Convert python attr.ib using other values

I'm using the attrs library to create data structure for paths. I want the first attribute to be the root directory which other are automatically joined with. I'd like to have something like that:

def my_converter(obj, value):
  return os.path.join(obj.root, value)

class Paths:
  root = attr.ib()
  relative = attr.ib(converter=my_converter)

This would do the trick, but converter function is given one argument only. Is there a clean way to convert the value using other attributes before validation? The validator takes three arguments (one of which is the object) but it is not the right place to convert values. Also putting everything into __attrs_post_init__ defeats the purpose of using attrs.

Upvotes: 2

Views: 1312

Answers (1)

hynek
hynek

Reputation: 4146

You could use a third attribute and a default:

import os
import attr

@attr.s
class Paths:
  root = attr.ib()
  _relative = attr.ib(repr=False)
  full = attr.ib()

  @full.default
  def _full_factory(self):
     return os.path.join(self.root, self._relative)

Which gives you:

>>> Paths("/home", "foo")
Paths(root='/home', full='/home/foo')

I personally prefer straight-forward and well-named @classmethod factory methods in cases like this. They tend to be more readable and you can easily dodge them when writing tests.

Upvotes: 1

Related Questions