1# -*- coding: utf-8 -*-
2"""
3    jinja2.runtime
4    ~~~~~~~~~~~~~~
5
6    Runtime helpers.
7
8    :copyright: (c) 2017 by the Jinja Team.
9    :license: BSD.
10"""
11import sys
12
13from itertools import chain
14from types import MethodType
15
16from jinja2.nodes import EvalContext, _context_function_types
17from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
18     internalcode, object_type_repr, evalcontextfunction, Namespace
19from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
20     TemplateNotFound
21from jinja2._compat import imap, text_type, iteritems, \
22     implements_iterator, implements_to_string, string_types, PY2, \
23     with_metaclass, abc
24
25
26# these variables are exported to the template runtime
27__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
28           'TemplateRuntimeError', 'missing', 'concat', 'escape',
29           'markup_join', 'unicode_join', 'to_string', 'identity',
30           'TemplateNotFound', 'Namespace']
31
32#: the name of the function that is used to convert something into
33#: a string.  We can just use the text type here.
34to_string = text_type
35
36#: the identity function.  Useful for certain things in the environment
37identity = lambda x: x
38
39_first_iteration = object()
40_last_iteration = object()
41
42
43def markup_join(seq):
44    """Concatenation that escapes if necessary and converts to unicode."""
45    buf = []
46    iterator = imap(soft_unicode, seq)
47    for arg in iterator:
48        buf.append(arg)
49        if hasattr(arg, '__html__'):
50            return Markup(u'').join(chain(buf, iterator))
51    return concat(buf)
52
53
54def unicode_join(seq):
55    """Simple args to unicode conversion and concatenation."""
56    return concat(imap(text_type, seq))
57
58
59def new_context(environment, template_name, blocks, vars=None,
60                shared=None, globals=None, locals=None):
61    """Internal helper to for context creation."""
62    if vars is None:
63        vars = {}
64    if shared:
65        parent = vars
66    else:
67        parent = dict(globals or (), **vars)
68    if locals:
69        # if the parent is shared a copy should be created because
70        # we don't want to modify the dict passed
71        if shared:
72            parent = dict(parent)
73        for key, value in iteritems(locals):
74            if value is not missing:
75                parent[key] = value
76    return environment.context_class(environment, parent, template_name,
77                                     blocks)
78
79
80class TemplateReference(object):
81    """The `self` in templates."""
82
83    def __init__(self, context):
84        self.__context = context
85
86    def __getitem__(self, name):
87        blocks = self.__context.blocks[name]
88        return BlockReference(name, self.__context, blocks, 0)
89
90    def __repr__(self):
91        return '<%s %r>' % (
92            self.__class__.__name__,
93            self.__context.name
94        )
95
96
97def _get_func(x):
98    return getattr(x, '__func__', x)
99
100
101class ContextMeta(type):
102
103    def __new__(cls, name, bases, d):
104        rv = type.__new__(cls, name, bases, d)
105        if bases == ():
106            return rv
107
108        resolve = _get_func(rv.resolve)
109        default_resolve = _get_func(Context.resolve)
110        resolve_or_missing = _get_func(rv.resolve_or_missing)
111        default_resolve_or_missing = _get_func(Context.resolve_or_missing)
112
113        # If we have a changed resolve but no changed default or missing
114        # resolve we invert the call logic.
115        if resolve is not default_resolve and \
116           resolve_or_missing is default_resolve_or_missing:
117            rv._legacy_resolve_mode = True
118        elif resolve is default_resolve and \
119             resolve_or_missing is default_resolve_or_missing:
120            rv._fast_resolve_mode = True
121
122        return rv
123
124
125def resolve_or_missing(context, key, missing=missing):
126    if key in context.vars:
127        return context.vars[key]
128    if key in context.parent:
129        return context.parent[key]
130    return missing
131
132
133class Context(with_metaclass(ContextMeta)):
134    """The template context holds the variables of a template.  It stores the
135    values passed to the template and also the names the template exports.
136    Creating instances is neither supported nor useful as it's created
137    automatically at various stages of the template evaluation and should not
138    be created by hand.
139
140    The context is immutable.  Modifications on :attr:`parent` **must not**
141    happen and modifications on :attr:`vars` are allowed from generated
142    template code only.  Template filters and global functions marked as
143    :func:`contextfunction`\\s get the active context passed as first argument
144    and are allowed to access the context read-only.
145
146    The template context supports read only dict operations (`get`,
147    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
148    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
149    method that doesn't fail with a `KeyError` but returns an
150    :class:`Undefined` object for missing variables.
151    """
152    # XXX: we want to eventually make this be a deprecation warning and
153    # remove it.
154    _legacy_resolve_mode = False
155    _fast_resolve_mode = False
156
157    def __init__(self, environment, parent, name, blocks):
158        self.parent = parent
159        self.vars = {}
160        self.environment = environment
161        self.eval_ctx = EvalContext(self.environment, name)
162        self.exported_vars = set()
163        self.name = name
164
165        # create the initial mapping of blocks.  Whenever template inheritance
166        # takes place the runtime will update this mapping with the new blocks
167        # from the template.
168        self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
169
170        # In case we detect the fast resolve mode we can set up an alias
171        # here that bypasses the legacy code logic.
172        if self._fast_resolve_mode:
173            self.resolve_or_missing = MethodType(resolve_or_missing, self)
174
175    def super(self, name, current):
176        """Render a parent block."""
177        try:
178            blocks = self.blocks[name]
179            index = blocks.index(current) + 1
180            blocks[index]
181        except LookupError:
182            return self.environment.undefined('there is no parent block '
183                                              'called %r.' % name,
184                                              name='super')
185        return BlockReference(name, self, blocks, index)
186
187    def get(self, key, default=None):
188        """Returns an item from the template context, if it doesn't exist
189        `default` is returned.
190        """
191        try:
192            return self[key]
193        except KeyError:
194            return default
195
196    def resolve(self, key):
197        """Looks up a variable like `__getitem__` or `get` but returns an
198        :class:`Undefined` object with the name of the name looked up.
199        """
200        if self._legacy_resolve_mode:
201            rv = resolve_or_missing(self, key)
202        else:
203            rv = self.resolve_or_missing(key)
204        if rv is missing:
205            return self.environment.undefined(name=key)
206        return rv
207
208    def resolve_or_missing(self, key):
209        """Resolves a variable like :meth:`resolve` but returns the
210        special `missing` value if it cannot be found.
211        """
212        if self._legacy_resolve_mode:
213            rv = self.resolve(key)
214            if isinstance(rv, Undefined):
215                rv = missing
216            return rv
217        return resolve_or_missing(self, key)
218
219    def get_exported(self):
220        """Get a new dict with the exported variables."""
221        return dict((k, self.vars[k]) for k in self.exported_vars)
222
223    def get_all(self):
224        """Return the complete context as dict including the exported
225        variables.  For optimizations reasons this might not return an
226        actual copy so be careful with using it.
227        """
228        if not self.vars:
229            return self.parent
230        if not self.parent:
231            return self.vars
232        return dict(self.parent, **self.vars)
233
234    @internalcode
235    def call(__self, __obj, *args, **kwargs):
236        """Call the callable with the arguments and keyword arguments
237        provided but inject the active context or environment as first
238        argument if the callable is a :func:`contextfunction` or
239        :func:`environmentfunction`.
240        """
241        if __debug__:
242            __traceback_hide__ = True  # noqa
243
244        # Allow callable classes to take a context
245        if hasattr(__obj, '__call__'):
246            fn = __obj.__call__
247            for fn_type in ('contextfunction',
248                            'evalcontextfunction',
249                            'environmentfunction'):
250                if hasattr(fn, fn_type):
251                    __obj = fn
252                    break
253
254        if isinstance(__obj, _context_function_types):
255            if getattr(__obj, 'contextfunction', 0):
256                args = (__self,) + args
257            elif getattr(__obj, 'evalcontextfunction', 0):
258                args = (__self.eval_ctx,) + args
259            elif getattr(__obj, 'environmentfunction', 0):
260                args = (__self.environment,) + args
261        try:
262            return __obj(*args, **kwargs)
263        except StopIteration:
264            return __self.environment.undefined('value was undefined because '
265                                                'a callable raised a '
266                                                'StopIteration exception')
267
268    def derived(self, locals=None):
269        """Internal helper function to create a derived context.  This is
270        used in situations where the system needs a new context in the same
271        template that is independent.
272        """
273        context = new_context(self.environment, self.name, {},
274                              self.get_all(), True, None, locals)
275        context.eval_ctx = self.eval_ctx
276        context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
277        return context
278
279    def _all(meth):
280        proxy = lambda self: getattr(self.get_all(), meth)()
281        proxy.__doc__ = getattr(dict, meth).__doc__
282        proxy.__name__ = meth
283        return proxy
284
285    keys = _all('keys')
286    values = _all('values')
287    items = _all('items')
288
289    # not available on python 3
290    if PY2:
291        iterkeys = _all('iterkeys')
292        itervalues = _all('itervalues')
293        iteritems = _all('iteritems')
294    del _all
295
296    def __contains__(self, name):
297        return name in self.vars or name in self.parent
298
299    def __getitem__(self, key):
300        """Lookup a variable or raise `KeyError` if the variable is
301        undefined.
302        """
303        item = self.resolve_or_missing(key)
304        if item is missing:
305            raise KeyError(key)
306        return item
307
308    def __repr__(self):
309        return '<%s %s of %r>' % (
310            self.__class__.__name__,
311            repr(self.get_all()),
312            self.name
313        )
314
315
316abc.Mapping.register(Context)
317
318
319class BlockReference(object):
320    """One block on a template reference."""
321
322    def __init__(self, name, context, stack, depth):
323        self.name = name
324        self._context = context
325        self._stack = stack
326        self._depth = depth
327
328    @property
329    def super(self):
330        """Super the block."""
331        if self._depth + 1 >= len(self._stack):
332            return self._context.environment. \
333                undefined('there is no parent block called %r.' %
334                          self.name, name='super')
335        return BlockReference(self.name, self._context, self._stack,
336                              self._depth + 1)
337
338    @internalcode
339    def __call__(self):
340        rv = concat(self._stack[self._depth](self._context))
341        if self._context.eval_ctx.autoescape:
342            rv = Markup(rv)
343        return rv
344
345
346class LoopContextBase(object):
347    """A loop context for dynamic iteration."""
348
349    _before = _first_iteration
350    _current = _first_iteration
351    _after = _last_iteration
352    _length = None
353
354    def __init__(self, undefined, recurse=None, depth0=0):
355        self._undefined = undefined
356        self._recurse = recurse
357        self.index0 = -1
358        self.depth0 = depth0
359        self._last_checked_value = missing
360
361    def cycle(self, *args):
362        """Cycles among the arguments with the current loop index."""
363        if not args:
364            raise TypeError('no items for cycling given')
365        return args[self.index0 % len(args)]
366
367    def changed(self, *value):
368        """Checks whether the value has changed since the last call."""
369        if self._last_checked_value != value:
370            self._last_checked_value = value
371            return True
372        return False
373
374    first = property(lambda x: x.index0 == 0)
375    last = property(lambda x: x._after is _last_iteration)
376    index = property(lambda x: x.index0 + 1)
377    revindex = property(lambda x: x.length - x.index0)
378    revindex0 = property(lambda x: x.length - x.index)
379    depth = property(lambda x: x.depth0 + 1)
380
381    @property
382    def previtem(self):
383        if self._before is _first_iteration:
384            return self._undefined('there is no previous item')
385        return self._before
386
387    @property
388    def nextitem(self):
389        if self._after is _last_iteration:
390            return self._undefined('there is no next item')
391        return self._after
392
393    def __len__(self):
394        return self.length
395
396    @internalcode
397    def loop(self, iterable):
398        if self._recurse is None:
399            raise TypeError('Tried to call non recursive loop.  Maybe you '
400                            "forgot the 'recursive' modifier.")
401        return self._recurse(iterable, self._recurse, self.depth0 + 1)
402
403    # a nifty trick to enhance the error message if someone tried to call
404    # the the loop without or with too many arguments.
405    __call__ = loop
406    del loop
407
408    def __repr__(self):
409        return '<%s %r/%r>' % (
410            self.__class__.__name__,
411            self.index,
412            self.length
413        )
414
415
416class LoopContext(LoopContextBase):
417
418    def __init__(self, iterable, undefined, recurse=None, depth0=0):
419        LoopContextBase.__init__(self, undefined, recurse, depth0)
420        self._iterator = iter(iterable)
421
422        # try to get the length of the iterable early.  This must be done
423        # here because there are some broken iterators around where there
424        # __len__ is the number of iterations left (i'm looking at your
425        # listreverseiterator!).
426        try:
427            self._length = len(iterable)
428        except (TypeError, AttributeError):
429            self._length = None
430        self._after = self._safe_next()
431
432    @property
433    def length(self):
434        if self._length is None:
435            # if was not possible to get the length of the iterator when
436            # the loop context was created (ie: iterating over a generator)
437            # we have to convert the iterable into a sequence and use the
438            # length of that + the number of iterations so far.
439            iterable = tuple(self._iterator)
440            self._iterator = iter(iterable)
441            iterations_done = self.index0 + 2
442            self._length = len(iterable) + iterations_done
443        return self._length
444
445    def __iter__(self):
446        return LoopContextIterator(self)
447
448    def _safe_next(self):
449        try:
450            return next(self._iterator)
451        except StopIteration:
452            return _last_iteration
453
454
455@implements_iterator
456class LoopContextIterator(object):
457    """The iterator for a loop context."""
458    __slots__ = ('context',)
459
460    def __init__(self, context):
461        self.context = context
462
463    def __iter__(self):
464        return self
465
466    def __next__(self):
467        ctx = self.context
468        ctx.index0 += 1
469        if ctx._after is _last_iteration:
470            raise StopIteration()
471        ctx._before = ctx._current
472        ctx._current = ctx._after
473        ctx._after = ctx._safe_next()
474        return ctx._current, ctx
475
476
477class Macro(object):
478    """Wraps a macro function."""
479
480    def __init__(self, environment, func, name, arguments,
481                 catch_kwargs, catch_varargs, caller,
482                 default_autoescape=None):
483        self._environment = environment
484        self._func = func
485        self._argument_count = len(arguments)
486        self.name = name
487        self.arguments = arguments
488        self.catch_kwargs = catch_kwargs
489        self.catch_varargs = catch_varargs
490        self.caller = caller
491        self.explicit_caller = 'caller' in arguments
492        if default_autoescape is None:
493            default_autoescape = environment.autoescape
494        self._default_autoescape = default_autoescape
495
496    @internalcode
497    @evalcontextfunction
498    def __call__(self, *args, **kwargs):
499        # This requires a bit of explanation,  In the past we used to
500        # decide largely based on compile-time information if a macro is
501        # safe or unsafe.  While there was a volatile mode it was largely
502        # unused for deciding on escaping.  This turns out to be
503        # problemtic for macros because if a macro is safe or not not so
504        # much depends on the escape mode when it was defined but when it
505        # was used.
506        #
507        # Because however we export macros from the module system and
508        # there are historic callers that do not pass an eval context (and
509        # will continue to not pass one), we need to perform an instance
510        # check here.
511        #
512        # This is considered safe because an eval context is not a valid
513        # argument to callables otherwise anwyays.  Worst case here is
514        # that if no eval context is passed we fall back to the compile
515        # time autoescape flag.
516        if args and isinstance(args[0], EvalContext):
517            autoescape = args[0].autoescape
518            args = args[1:]
519        else:
520            autoescape = self._default_autoescape
521
522        # try to consume the positional arguments
523        arguments = list(args[:self._argument_count])
524        off = len(arguments)
525
526        # For information why this is necessary refer to the handling
527        # of caller in the `macro_body` handler in the compiler.
528        found_caller = False
529
530        # if the number of arguments consumed is not the number of
531        # arguments expected we start filling in keyword arguments
532        # and defaults.
533        if off != self._argument_count:
534            for idx, name in enumerate(self.arguments[len(arguments):]):
535                try:
536                    value = kwargs.pop(name)
537                except KeyError:
538                    value = missing
539                if name == 'caller':
540                    found_caller = True
541                arguments.append(value)
542        else:
543            found_caller = self.explicit_caller
544
545        # it's important that the order of these arguments does not change
546        # if not also changed in the compiler's `function_scoping` method.
547        # the order is caller, keyword arguments, positional arguments!
548        if self.caller and not found_caller:
549            caller = kwargs.pop('caller', None)
550            if caller is None:
551                caller = self._environment.undefined('No caller defined',
552                                                     name='caller')
553            arguments.append(caller)
554
555        if self.catch_kwargs:
556            arguments.append(kwargs)
557        elif kwargs:
558            if 'caller' in kwargs:
559                raise TypeError('macro %r was invoked with two values for '
560                                'the special caller argument.  This is '
561                                'most likely a bug.' % self.name)
562            raise TypeError('macro %r takes no keyword argument %r' %
563                            (self.name, next(iter(kwargs))))
564        if self.catch_varargs:
565            arguments.append(args[self._argument_count:])
566        elif len(args) > self._argument_count:
567            raise TypeError('macro %r takes not more than %d argument(s)' %
568                            (self.name, len(self.arguments)))
569
570        return self._invoke(arguments, autoescape)
571
572    def _invoke(self, arguments, autoescape):
573        """This method is being swapped out by the async implementation."""
574        rv = self._func(*arguments)
575        if autoescape:
576            rv = Markup(rv)
577        return rv
578
579    def __repr__(self):
580        return '<%s %s>' % (
581            self.__class__.__name__,
582            self.name is None and 'anonymous' or repr(self.name)
583        )
584
585
586@implements_to_string
587class Undefined(object):
588    """The default undefined type.  This undefined type can be printed and
589    iterated over, but every other access will raise an :exc:`jinja2.exceptions.UndefinedError`:
590
591    >>> foo = Undefined(name='foo')
592    >>> str(foo)
593    ''
594    >>> not foo
595    True
596    >>> foo + 42
597    Traceback (most recent call last):
598      ...
599    jinja2.exceptions.UndefinedError: 'foo' is undefined
600    """
601    __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
602                 '_undefined_exception')
603
604    def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
605        self._undefined_hint = hint
606        self._undefined_obj = obj
607        self._undefined_name = name
608        self._undefined_exception = exc
609
610    @internalcode
611    def _fail_with_undefined_error(self, *args, **kwargs):
612        """Regular callback function for undefined objects that raises an
613        `jinja2.exceptions.UndefinedError` on call.
614        """
615        if self._undefined_hint is None:
616            if self._undefined_obj is missing:
617                hint = '%r is undefined' % self._undefined_name
618            elif not isinstance(self._undefined_name, string_types):
619                hint = '%s has no element %r' % (
620                    object_type_repr(self._undefined_obj),
621                    self._undefined_name
622                )
623            else:
624                hint = '%r has no attribute %r' % (
625                    object_type_repr(self._undefined_obj),
626                    self._undefined_name
627                )
628        else:
629            hint = self._undefined_hint
630        raise self._undefined_exception(hint)
631
632    @internalcode
633    def __getattr__(self, name):
634        if name[:2] == '__':
635            raise AttributeError(name)
636        return self._fail_with_undefined_error()
637
638    __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
639        __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
640        __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
641        __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
642        __float__ = __complex__ = __pow__ = __rpow__ = __sub__ = \
643        __rsub__ = _fail_with_undefined_error
644
645    def __eq__(self, other):
646        return type(self) is type(other)
647
648    def __ne__(self, other):
649        return not self.__eq__(other)
650
651    def __hash__(self):
652        return id(type(self))
653
654    def __str__(self):
655        return u''
656
657    def __len__(self):
658        return 0
659
660    def __iter__(self):
661        if 0:
662            yield None
663
664    def __nonzero__(self):
665        return False
666    __bool__ = __nonzero__
667
668    def __repr__(self):
669        return 'Undefined'
670
671
672def make_logging_undefined(logger=None, base=None):
673    """Given a logger object this returns a new undefined class that will
674    log certain failures.  It will log iterations and printing.  If no
675    logger is given a default logger is created.
676
677    Example::
678
679        logger = logging.getLogger(__name__)
680        LoggingUndefined = make_logging_undefined(
681            logger=logger,
682            base=Undefined
683        )
684
685    .. versionadded:: 2.8
686
687    :param logger: the logger to use.  If not provided, a default logger
688                   is created.
689    :param base: the base class to add logging functionality to.  This
690                 defaults to :class:`Undefined`.
691    """
692    if logger is None:
693        import logging
694        logger = logging.getLogger(__name__)
695        logger.addHandler(logging.StreamHandler(sys.stderr))
696    if base is None:
697        base = Undefined
698
699    def _log_message(undef):
700        if undef._undefined_hint is None:
701            if undef._undefined_obj is missing:
702                hint = '%s is undefined' % undef._undefined_name
703            elif not isinstance(undef._undefined_name, string_types):
704                hint = '%s has no element %s' % (
705                    object_type_repr(undef._undefined_obj),
706                    undef._undefined_name)
707            else:
708                hint = '%s has no attribute %s' % (
709                    object_type_repr(undef._undefined_obj),
710                    undef._undefined_name)
711        else:
712            hint = undef._undefined_hint
713        logger.warning('Template variable warning: %s', hint)
714
715    class LoggingUndefined(base):
716
717        def _fail_with_undefined_error(self, *args, **kwargs):
718            try:
719                return base._fail_with_undefined_error(self, *args, **kwargs)
720            except self._undefined_exception as e:
721                logger.error('Template variable error: %s', str(e))
722                raise e
723
724        def __str__(self):
725            rv = base.__str__(self)
726            _log_message(self)
727            return rv
728
729        def __iter__(self):
730            rv = base.__iter__(self)
731            _log_message(self)
732            return rv
733
734        if PY2:
735            def __nonzero__(self):
736                rv = base.__nonzero__(self)
737                _log_message(self)
738                return rv
739
740            def __unicode__(self):
741                rv = base.__unicode__(self)
742                _log_message(self)
743                return rv
744        else:
745            def __bool__(self):
746                rv = base.__bool__(self)
747                _log_message(self)
748                return rv
749
750    return LoggingUndefined
751
752
753@implements_to_string
754class DebugUndefined(Undefined):
755    """An undefined that returns the debug info when printed.
756
757    >>> foo = DebugUndefined(name='foo')
758    >>> str(foo)
759    '{{ foo }}'
760    >>> not foo
761    True
762    >>> foo + 42
763    Traceback (most recent call last):
764      ...
765    jinja2.exceptions.UndefinedError: 'foo' is undefined
766    """
767    __slots__ = ()
768
769    def __str__(self):
770        if self._undefined_hint is None:
771            if self._undefined_obj is missing:
772                return u'{{ %s }}' % self._undefined_name
773            return '{{ no such element: %s[%r] }}' % (
774                object_type_repr(self._undefined_obj),
775                self._undefined_name
776            )
777        return u'{{ undefined value printed: %s }}' % self._undefined_hint
778
779
780@implements_to_string
781class StrictUndefined(Undefined):
782    """An undefined that barks on print and iteration as well as boolean
783    tests and all kinds of comparisons.  In other words: you can do nothing
784    with it except checking if it's defined using the `defined` test.
785
786    >>> foo = StrictUndefined(name='foo')
787    >>> str(foo)
788    Traceback (most recent call last):
789      ...
790    jinja2.exceptions.UndefinedError: 'foo' is undefined
791    >>> not foo
792    Traceback (most recent call last):
793      ...
794    jinja2.exceptions.UndefinedError: 'foo' is undefined
795    >>> foo + 42
796    Traceback (most recent call last):
797      ...
798    jinja2.exceptions.UndefinedError: 'foo' is undefined
799    """
800    __slots__ = ()
801    __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
802        __ne__ = __bool__ = __hash__ = \
803        Undefined._fail_with_undefined_error
804
805
806# remove remaining slots attributes, after the metaclass did the magic they
807# are unneeded and irritating as they contain wrong data for the subclasses.
808del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__
809