Skip to content

Commit e39fab7

Browse files
committed
-
1 parent 766d745 commit e39fab7

File tree

6 files changed

+1146
-9
lines changed

6 files changed

+1146
-9
lines changed

source_py2/python_toolbox/dict_tools.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from python_toolbox import comparison_tools
1010

1111

12-
def filter_items(d, condition, force_dict_type=None):
12+
def filter_items(d, condition, double=False, force_dict_type=None):
1313
'''
1414
Get new dict with items from `d` that satisfy the `condition` functions.
1515
@@ -18,16 +18,29 @@ def filter_items(d, condition, force_dict_type=None):
1818
The newly created dict will be of the same class as `d`, e.g. if you passed
1919
an ordered dict as `d`, the result will be an ordered dict, using the
2020
correct order.
21+
22+
Specify `double=True` to get a tuple of two dicts instead of one. The
23+
second dict will have all the rejected items.
2124
'''
2225
# todo future: possibly shallow-copy `d` to allow for dict classes that
2326
# have more state, (like default factory.)
2427
if force_dict_type is not None:
2528
dict_type = force_dict_type
2629
else:
2730
dict_type = type(d) if (type(d).__name__ != 'dictproxy') else dict
28-
return dict_type(
29-
(key, value) for (key, value) in d.iteritems() if condition(key, value)
30-
)
31+
32+
if double:
33+
return map(
34+
dict_type,
35+
cute_iter_tools.double_filter(
36+
lambda (key, value): condition(key, value),
37+
d.iteritems()
38+
)
39+
)
40+
else:
41+
return dict_type(
42+
(key, value) for (key, value) in d.iteritems() if condition(key, value)
43+
)
3144

3245

3346
def get_list(d, iterable):

source_py2/python_toolbox/monkeypatching_tools.py

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
'''Tools for monkeypatching.'''
55

66
import sys
7+
import collections
8+
import inspect
79
import types
810

11+
from python_toolbox.third_party import funcsigs
12+
913
from python_toolbox import misc_tools
14+
from python_toolbox import dict_tools
1015
from python_toolbox import decorator_tools
1116
from python_toolbox import caching
1217

1318

1419
@decorator_tools.helpful_decorator_builder
15-
def monkeypatch_method(monkeypatchee, name=None):
20+
def monkeypatch_method(monkeypatchee, name=None, override_if_exists=True):
1621
'''
1722
Monkeypatch a method into a class (or an object).
1823
@@ -49,8 +54,8 @@ def decorator(function):
4954
new_method = types.MethodType(function, None, monkeypatchee) if \
5055
monkeypatchee_is_a_class else types.MethodType(function,
5156
monkeypatchee, class_of_monkeypatchee)
52-
setattr(monkeypatchee, name_, new_method)
53-
return function
57+
setattr_value = new_method
58+
return_value = function
5459
else:
5560
# `function` is probably some kind of descriptor.
5661
if not monkeypatchee_is_a_class:
@@ -77,8 +82,57 @@ def decorator(function):
7782
)
7883
# #
7984
### Finished getting name of descriptor. ######################
80-
setattr(monkeypatchee, name_, function)
81-
return function
85+
setattr_value = return_value = function
86+
87+
if override_if_exists or not hasattr(monkeypatchee, name_):
88+
setattr(monkeypatchee, name_, setattr_value)
89+
return return_value
8290

8391
return decorator
8492

93+
94+
def change_defaults(function=None, new_defaults={}):
95+
'''
96+
Change default values of a function.
97+
98+
Include the new defaults in a dict `new_defaults`, with each key being a
99+
keyword name and each value being the new default value.
100+
101+
Note: This changes the actual function!
102+
103+
Can be used both as a straight function and as a decorater to a function to
104+
be changed.
105+
'''
106+
def change_defaults_(function_, new_defaults_):
107+
signature = funcsigs.Signature.from_function(function_)
108+
defaults = list(function_.__defaults__ or ())
109+
non_keyword_only_defaultful_parameters = defaultful_parameters = \
110+
dict_tools.filter_items(
111+
signature.parameters,
112+
lambda name, parameter: parameter.default != funcsigs._empty,
113+
force_dict_type=collections.OrderedDict
114+
)
115+
116+
for i, parameter_name in \
117+
enumerate(non_keyword_only_defaultful_parameters):
118+
if parameter_name in new_defaults_:
119+
defaults[i] = new_defaults_[parameter_name]
120+
121+
function_.__defaults__ = tuple(defaults)
122+
123+
return function_
124+
125+
if not callable(function):
126+
# Decorator mode:
127+
if function is None:
128+
actual_new_defaults = new_defaults
129+
else:
130+
actual_new_defaults = function
131+
return lambda function_: change_defaults_(function_,
132+
actual_new_defaults)
133+
else:
134+
# Normal usage mode:
135+
return change_defaults_(function, new_defaults)
136+
137+
138+

0 commit comments

Comments
 (0)