|
10 | 10 | import operator as op
|
11 | 11 | import random
|
12 | 12 | import sys
|
| 13 | +import types |
| 14 | +import warnings |
13 | 15 |
|
14 | 16 | from pathlib import Path
|
15 | 17 | from colour import Color
|
|
34 | 36 | class Mobject(Container):
|
35 | 37 | """Mathematical Object: base class for objects that can be displayed on screen.
|
36 | 38 |
|
| 39 | + There is a compatibility layer that allows for |
| 40 | + getting and setting generic attributes with ``get_*`` |
| 41 | + and ``set_*`` methods. See :meth:`set` for more details. |
| 42 | +
|
37 | 43 | Attributes
|
38 | 44 | ----------
|
39 | 45 | submobjects : :class:`list`
|
@@ -248,6 +254,106 @@ def __sub__(self, other):
|
248 | 254 | def __isub__(self, other):
|
249 | 255 | raise NotImplementedError
|
250 | 256 |
|
| 257 | + def set(self, **kwargs): |
| 258 | + """Sets attributes. |
| 259 | +
|
| 260 | + Mainly to be used along with :attr:`animate` to |
| 261 | + animate setting attributes. |
| 262 | +
|
| 263 | + In addition to this method, there is a compatibility |
| 264 | + layer that allows ``get_*`` and ``set_*`` methods to |
| 265 | + get and set generic attributes. For instance:: |
| 266 | +
|
| 267 | + >>> mob = Mobject() |
| 268 | + >>> mob.set_foo(0) |
| 269 | + Mobject |
| 270 | + >>> mob.get_foo() |
| 271 | + 0 |
| 272 | + >>> mob.foo |
| 273 | + 0 |
| 274 | +
|
| 275 | + This compatibility layer does not interfere with any |
| 276 | + ``get_*`` or ``set_*`` methods that are explicitly |
| 277 | + defined. |
| 278 | +
|
| 279 | + .. warning:: |
| 280 | +
|
| 281 | + This compatibility layer is for backwards compatibility |
| 282 | + and is not guaranteed to stay around. Where applicable, |
| 283 | + please prefer getting/setting attributes normally or with |
| 284 | + the :meth:`set` method. |
| 285 | +
|
| 286 | + Parameters |
| 287 | + ---------- |
| 288 | + **kwargs |
| 289 | + The attributes and corresponding values to set. |
| 290 | +
|
| 291 | + Returns |
| 292 | + ------- |
| 293 | + :class:`Mobject` |
| 294 | + ``self`` |
| 295 | +
|
| 296 | + Examples |
| 297 | + -------- |
| 298 | + :: |
| 299 | +
|
| 300 | + >>> mob = Mobject() |
| 301 | + >>> mob.set(foo=0) |
| 302 | + Mobject |
| 303 | + >>> mob.foo |
| 304 | + 0 |
| 305 | + """ |
| 306 | + |
| 307 | + for attr, value in kwargs.items(): |
| 308 | + setattr(self, attr, value) |
| 309 | + |
| 310 | + return self |
| 311 | + |
| 312 | + def __getattr__(self, attr): |
| 313 | + # Add automatic compatibility layer |
| 314 | + # between properties and get_* and set_* |
| 315 | + # methods. |
| 316 | + # |
| 317 | + # In python 3.9+ we could change this |
| 318 | + # logic to use str.remove_prefix instead. |
| 319 | + |
| 320 | + if attr.startswith("get_"): |
| 321 | + # Remove the "get_" prefix |
| 322 | + to_get = attr[4:] |
| 323 | + |
| 324 | + def getter(self): |
| 325 | + warnings.warn( |
| 326 | + "This method is not guaranteed to stay around. Please prefer getting the attribute normally.", |
| 327 | + DeprecationWarning, |
| 328 | + stacklevel=2, |
| 329 | + ) |
| 330 | + |
| 331 | + return getattr(self, to_get) |
| 332 | + |
| 333 | + # Return a bound method |
| 334 | + return types.MethodType(getter, self) |
| 335 | + |
| 336 | + if attr.startswith("set_"): |
| 337 | + # Remove the "set_" prefix |
| 338 | + to_set = attr[4:] |
| 339 | + |
| 340 | + def setter(self, value): |
| 341 | + warnings.warn( |
| 342 | + "This method is not guaranteed to stay around. Please prefer setting the attribute normally or with Mobject.set().", |
| 343 | + DeprecationWarning, |
| 344 | + stacklevel=2, |
| 345 | + ) |
| 346 | + |
| 347 | + setattr(self, to_set, value) |
| 348 | + |
| 349 | + return self |
| 350 | + |
| 351 | + # Return a bound method |
| 352 | + return types.MethodType(setter, self) |
| 353 | + |
| 354 | + # Unhandled attribute, therefore error |
| 355 | + raise AttributeError |
| 356 | + |
251 | 357 | def get_array_attrs(self):
|
252 | 358 | return ["points"]
|
253 | 359 |
|
|
0 commit comments