Skip to content

Avoid code deduplication with attrs #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
guyzmo opened this issue May 4, 2017 · 2 comments
Closed

Avoid code deduplication with attrs #10

guyzmo opened this issue May 4, 2017 · 2 comments

Comments

@guyzmo
Copy link
Contributor

guyzmo commented May 4, 2017

The code relies a lot on a common super-verbose pattern:

class GogsFoobar:
    def __init__(self, param):
        self._param = param

    @staticmethod
    def from_json(self, parsed_json):
        param = parsed_json.get(param, 42)
        return GogsFoobar(param=param)

    @property
    def param(self):
        return self._param

you end up writing 9 times param, for each attribute you add. I love python, and things being explicit better than implicit, but we're light years away from DRY here. This is being…

I suggest instead to use some tricks like, the attrs module:

import attr

@attr.s(frozen=True)
class GogsFoobar:
    foobar = attr.ib(default=42)

    @staticmethod
    def from_json(self, parsed_json):
        param = parsed_json.get(param, 42)
        return GogsFoobar(param=param)

it's now down to 4.

But we can make it totally DRY, the following way:

import attr

@attr.s
class GogsEntity:
    json = attr.ib()
    @classmethod
    def from_json(cls, parsed_json):
        # with introspection, get arguments of the constructor
        params = attr.fields(cls)
        args = []
        kwargs = {}
        for param in params:
            # if not a keyword argument
            if param.name == attr._make._Nothing:
                args.append(json_get(parsed_json, param.name))
            # if it's a keyword argument
            else:
                kwargs[param.name] = parsed_json.get(param.name, None)
        del kwargs['json']
        instance = cls(*args, json=parsed_json, **kwargs)
        return instance

@attr.s(frozen=True)
class GogsFoobar(GogsEntity):
    foo = attr.ib()
    foobar = attr.ib(default=42)

x = GogsFoobar.from_json(dict(foo=1, foobar=2))

print(x.foo, x.foobar, x.json)

and now you only write the attribute once. But I agree, it's using some creepy dirty internal automagic from python. At the cost of making it uglier in one place, you make it DRY everywhere else, with the same strong type checkings you enforce currently.

@guyzmo
Copy link
Contributor Author

guyzmo commented May 4, 2017

(if you checked you email first, note that I updated the issue to make the code better and working ☺)

@ethantkoenig
Copy link
Contributor

Resolved by d3db08e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants