-
Notifications
You must be signed in to change notification settings - Fork 0
/
attributes_manager_ren.py
194 lines (161 loc) · 6.97 KB
/
attributes_manager_ren.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import renpy
from renpy import python_object, config
"""renpy
init python in attributes_manager:
"""
class attribute(str):
"""
Represents an attribute passed to the attributes_manager functions.
In a nutshell :
att=attribute("hello")
att.name=="hello", att.added==True
att=attribute("-hello")
att.name=="hello", att.added==False
If given, the `added` argument of the constructor overrides the added-ness.
Examples :
att=attribute("hello", added=False)
att.name=="hello", att.added==False, att==attribute("-hello"), str(att)=="-hello"
att=attribute("-hello", added=True)
att.name=="hello", att.added==True, att==attribute("hello"), str(att)=="hello"
attribute is a subclass of str and supports operations with strings, usually returning strings.
In particular, `"hello" in attribute("hello")`, `"hello" in attribute("-hello")`,
`"-hell" in attribute("-hello")` and `attribute("hello", added=False)[0] == "-"` all return True.
"""
__slots__ = ()
def __new__(clss, name, added=None):
if added is not None:
if (not added) and (name[0] != "-"):
name = "-"+name
elif added:
name = name.removeprefix("-")
return super(attribute, clss).__new__(clss, name)
@property
def name(self):
"""
Returns the attribute as a string, without the prepended minus sign.
"""
return self.removeprefix("-")
@property
def added(self):
"""
Returns a boolean representing the minus sign in front of attributes to remove them :
if added is True, the minus sign wasn't there.
"""
return self[0] != '-'
def __repr__(self):
return "attribute({})".format(super().__repr__())
class set(renpy.store.set):
__slots__ = ()
def __init__(self, iterable=()):
super().__init__(attribute(el) for el in iterable)
def add(self, value, **kwargs):
return super().add(attribute(value, **kwargs))
def find(self, name=None, added=None):
"""
Returns an element of the set satisfying the conditions given in arguments, or None.
attributes_manager.set({"-hello", "-goodbye"}).find(name="hello")
returns attribute("-hello")
attributes_manager.set({"hello", "-goodbye"}).find(added=False)
returns attribute("-goodbye")
attributes_manager.set({"-hello", "-goodbye"}).find(added=False)
returns either one as an attribute object
attributes_manager.set({"hello", "-goodbye"}).find(name="hello", added=False)
returns None
attributes_manager.set({"hello", "goodbye"}).find(name="hell")
returns None
"""
if name is None and added is None:
raise ValueError("One of name or added must be given.")
for att in self:
if ((name is None) or (att.name == name)) and ((added is None) or (att.added == added)):
return att
return None
def filter_or(self, *args):
"""
Returns a subset of each attribute containing ANY OF the substrings passed as arguments.
attributes_manager.set({"hell", "hello", "love", "bite"}).filter_or("hell", "lo")
returns attributes_manager.set({"hell", "hello", "love"})
"""
rv = type(self)()
for att in self:
for substring in args:
if substring in str(att):
rv.add(att)
return rv
def filter_and(self, *args):
"""
Returns a subset of each attribute containing EACH OF the substrings passed as arguments.
attributes_manager.set({"hell", "hello", "love", "bite"}).filter_and("hell", "lo")
returns attributes_manager.set({"hello"})
"""
rv = type(self)()
for att in self:
for substring in args:
if substring not in str(att):
break
else:
rv.add(att)
return rv
def __repr__(self):
return __name__ + "." + super().__repr__()
# Some little magic to make our set's inerited methods return objects of the proper type.
def _wrapper(func, typ):
def internal(self, *args):
args = (typ(arg) for arg in args)
return typ(func(self, *args))
return internal
for methname in ("__sub__", "__isub__", "__rsub__",
"__xor__", "__ixor__", "__rxor__",
"__and__", "__iand__", "__rand__",
"__or__", "__ior__", "__ror__",
"copy", "difference", "intersection", "symmetric_difference", "union"):
setattr(set, methname, _wrapper(getattr(renpy.store.set, methname), set))
del methname, _wrapper
class adjust_decorator(python_object):
"""
This is a decorator for the declaration of adjust_attributes functions.
The function being decorated will be passed a single argument :
an `attributes_manager.set` of `attributes_manager.attribute` objects.
The first attribute, which is the tag of the shown image, is not a part of the set.
The function being decorated must return an iterable (set, list, tuple... attributes_manager.set)
of string objects (or subclasses of string, such as attributes_manager.attribute).
If a `name` is provided to the decorator, the decorated version of the function
will be stored in `config.adjust_attributes[name]`.
If no `name` parameter is passed, if the name of the function is "(something)_adjust_attributes",
that `something` is taken as the name.
Otherwise, the decorator doesn't store the function anywhere.
"""
__slots__ = "name",
suffix = "_adjust_attributes"
store = renpy.store.config.adjust_attributes
def __init__(self, name=None, /):
if (name is None) or isinstance(name, str):
self.name = name
elif callable(name):
self.name = None
self(name)
else:
raise TypeError("This must be used as a decorator directly, or called with no parameter, or called with a string.")
def __call__(self, func):
funcname = self.name
def rf(name):
aaa_set = set(attribute(att) for att in name[1:])
rv = func(aaa_set)
rv = tuple(str(el) for el in rv) # very important, only return native types !
return name[0], *rv
if funcname is None:
sfx = self.suffix
if func.__name__.endswith(sfx):
funcname = func.__name__.removesuffix(sfx)
if funcname is not None:
self.store[funcname] = rf
return rf
class default_decorator(adjust_decorator):
"""
This is a decorator for the declaration of default_attribute_callbacks functions.
It works the same as adjust_decorator, except that the store is config.default_attribute_callbacks,
and the recognized template is "(something)_default_attributes"
"""
__slots__ = ()
suffix = "_default_attributes"
store = renpy.store.config.default_attribute_callbacks