Skip to content

Commit 2af9879

Browse files
committed
Drop fancy metaclass, improve instance method compatibility
1 parent 5934f81 commit 2af9879

File tree

3 files changed

+19
-26
lines changed

3 files changed

+19
-26
lines changed

src/variants/_variants.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
# -*- coding: utf-8 -*-
22
"""Provides the variant form decorator."""
33

4-
import six
5-
64
import types
75

86
__all__ = ['variants']
97

108

11-
class _StaticCallableMetaclass(type):
12-
"""Metaclass for a static callable function."""
13-
14-
def __call__(cls, *args, **kwargs):
15-
"""Rather than calling the constructor, call a static function."""
16-
return cls.__main_form__(*args, **kwargs)
17-
18-
def __repr__(cls):
19-
return cls.__func_repr__()
20-
21-
229
def variants(f):
2310
"""
2411
Decorator to register a function that has variant forms.
@@ -40,26 +27,31 @@ def myfunc(url):
4027
do_something(r.text)
4128
"""
4229

43-
@six.add_metaclass(_StaticCallableMetaclass)
4430
class VariantFunction:
4531
__doc__ = f.__doc__
4632

47-
@staticmethod
48-
def __main_form__(*args, **kwargs):
33+
def __call__(self, *args, **kwargs):
4934
return f(*args, **kwargs)
5035

51-
@classmethod
52-
def variant(cls, func_name):
36+
def variant(self, func_name):
37+
"""Decorator to add a new variant form to the function."""
5338
def decorator(vfunc):
54-
setattr(cls, func_name, vfunc)
55-
return cls
39+
setattr(self.__class__, func_name, staticmethod(vfunc))
40+
return self
5641

5742
return decorator
5843

59-
@classmethod
60-
def __func_repr__(cls):
61-
return '<VariantFunction {}>'.format(cls.__name__)
44+
def __get__(self, instance, owner):
45+
# This is necessary to bind instance methods
46+
if instance is None:
47+
return self
48+
49+
return types.MethodType(self, instance)
50+
51+
def __repr__(self):
52+
return '<VariantFunction {}>'.format(self.__name__)
6253

63-
VariantFunction.__name__ = f.__name__
54+
f_out = VariantFunction()
55+
f_out.__name__ = f.__name__
6456

65-
return VariantFunction
57+
return f_out

tests/test_functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pytest
1010

11+
1112
###
1213
# Example implementation - division function
1314
@variants
@@ -18,6 +19,7 @@ def divide(x, y):
1819

1920
@divide.variant('round')
2021
def divide(x, y):
22+
"""A version of divide that also rounds."""
2123
return round(x / y)
2224

2325

tests/test_instance_methods.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ def divide(self, y, mode=None):
4242
return funcs[mode](y)
4343

4444

45-
@pytest.mark.xfail
4645
@pytest.mark.parametrize('x,y,expected', DivisionData.DIV_VALS)
4746
def test_divide(x, y, expected):
4847
dv = DivisionVariants(x)

0 commit comments

Comments
 (0)