Skip to content

Instantly share code, notes, and snippets.

@Xion
Created June 30, 2013 12:18
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Xion/5894951 to your computer and use it in GitHub Desktop.
Save Xion/5894951 to your computer and use it in GitHub Desktop.
Fluent interface decorators
#!/usr/bin/env python
"""
Decorator for fluent interface classes.
"""
import functools
import inspect
def chained(method):
"""Method decorator to allow chaining."""
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
result = method(self, *args, **kwargs)
return self if result is None else result
return wrapper
def fluent(cls):
"""Class decorator to allow method chaining."""
for name, member in cls.__dict__.iteritems():
if inspect.isfunction(member):
setattr(cls, name, chained(member))
return cls
if __name__ == '__main__':
class Foo(object):
@chained
def set_value(self, value):
self.value = value
def get_value(self):
return self.value
@fluent
class Bar(object):
def set_value(self, value):
self.value = value
def get_value(self):
return self.value
print Foo().set_value("Foo").get_value()
print Bar().set_value("Bar").get_value()
@rg-532
Copy link

rg-532 commented Feb 8, 2024

Hello. Thank you for posting these decorator definitions, they are exactly what I was looking for!

Unfortunately, PyCharm raises a bunch of errors in many use cases of these decorators, such as "unfilled parameter" when I use @chained on a method with no arguments or "Cannot find reference 'get_value' in 'None'" for your example of using the @fluent interface (This is probably because the inspector checks for errors in the wrong place).

If you know how to fix this, or a workaround I could use, that would be perfect! Otherwise, I am wondering whether I should report these issues between decorators and methods of a class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment