From: David Lord Date: Tue, 28 Jan 2020 06:05:00 +0000 (-0800) Subject: remove _compat module X-Git-Tag: 3.0.0a1~2^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=148a19138c197233cbd3a2cb1f543d468479f1bc;p=thirdparty%2Fjinja.git remove _compat module --- diff --git a/src/jinja2/_compat.py b/src/jinja2/_compat.py deleted file mode 100644 index 1f044954..00000000 --- a/src/jinja2/_compat.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8: noqa -import marshal -import sys - -PY2 = sys.version_info[0] == 2 -PYPY = hasattr(sys, "pypy_translation_info") -_identity = lambda x: x - -if not PY2: - unichr = chr - range_type = range - text_type = str - string_types = (str,) - integer_types = (int,) - - iterkeys = lambda d: iter(d.keys()) - itervalues = lambda d: iter(d.values()) - iteritems = lambda d: iter(d.items()) - - import pickle - from io import BytesIO, StringIO - - NativeStringIO = StringIO - - def reraise(tp, value, tb=None): - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - - ifilter = filter - imap = map - izip = zip - intern = sys.intern - - implements_iterator = _identity - implements_to_string = _identity - encode_filename = _identity - - marshal_dump = marshal.dump - marshal_load = marshal.load - -else: - unichr = unichr - text_type = unicode - range_type = xrange - string_types = (str, unicode) - integer_types = (int, long) - - iterkeys = lambda d: d.iterkeys() - itervalues = lambda d: d.itervalues() - iteritems = lambda d: d.iteritems() - - import cPickle as pickle - from cStringIO import StringIO as BytesIO, StringIO - - NativeStringIO = BytesIO - - exec("def reraise(tp, value, tb=None):\n raise tp, value, tb") - - from itertools import imap, izip, ifilter - - intern = intern - - def implements_iterator(cls): - cls.next = cls.__next__ - del cls.__next__ - return cls - - def implements_to_string(cls): - cls.__unicode__ = cls.__str__ - cls.__str__ = lambda x: x.__unicode__().encode("utf-8") - return cls - - def encode_filename(filename): - if isinstance(filename, unicode): - return filename.encode("utf-8") - return filename - - def marshal_dump(code, f): - if isinstance(f, file): - marshal.dump(code, f) - else: - f.write(marshal.dumps(code)) - - def marshal_load(f): - if isinstance(f, file): - return marshal.load(f) - return marshal.loads(f.read()) - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a - # dummy metaclass for one level of class instantiation that replaces - # itself with the actual metaclass. - class metaclass(type): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - - return type.__new__(metaclass, "temporary_class", (), {}) - - -try: - from urllib.parse import quote_from_bytes as url_quote -except ImportError: - from urllib import quote as url_quote - - -try: - from collections import abc -except ImportError: - import collections as abc - - -try: - from os import fspath -except ImportError: - try: - from pathlib import PurePath - except ImportError: - PurePath = None - - def fspath(path): - if hasattr(path, "__fspath__"): - return path.__fspath__() - - # Python 3.5 doesn't have __fspath__ yet, use str. - if PurePath is not None and isinstance(path, PurePath): - return str(path) - - return path diff --git a/src/jinja2/bccache.py b/src/jinja2/bccache.py index ff4d606f..b328b3b0 100644 --- a/src/jinja2/bccache.py +++ b/src/jinja2/bccache.py @@ -8,19 +8,15 @@ are initialized on the first request. """ import errno import fnmatch +import marshal import os +import pickle import stat import sys import tempfile from hashlib import sha1 -from os import listdir -from os import path - -from ._compat import BytesIO -from ._compat import marshal_dump -from ._compat import marshal_load -from ._compat import pickle -from ._compat import text_type +from io import BytesIO + from .utils import open_if_exists bc_version = 4 @@ -67,7 +63,7 @@ class Bucket(object): return # if marshal_load fails then we need to reload try: - self.code = marshal_load(f) + self.code = marshal.load(f) except (EOFError, ValueError, TypeError): self.reset() return @@ -78,7 +74,7 @@ class Bucket(object): raise TypeError("can't write empty bucket") f.write(bc_magic) pickle.dump(self.checksum, f, 2) - marshal_dump(self.code, f) + marshal.dump(self.code, f) def bytecode_from_string(self, string): """Load bytecode from a string.""" @@ -145,7 +141,7 @@ class BytecodeCache(object): hash = sha1(name.encode("utf-8")) if filename is not None: filename = "|" + filename - if isinstance(filename, text_type): + if isinstance(filename, str): filename = filename.encode("utf-8") hash.update(filename) return hash.hexdigest() @@ -241,7 +237,7 @@ class FileSystemBytecodeCache(BytecodeCache): return actual_dir def _get_cache_filename(self, bucket): - return path.join(self.directory, self.pattern % bucket.key) + return os.path.join(self.directory, self.pattern % bucket.key) def load_bytecode(self, bucket): f = open_if_exists(self._get_cache_filename(bucket), "rb") @@ -264,10 +260,10 @@ class FileSystemBytecodeCache(BytecodeCache): # normally. from os import remove - files = fnmatch.filter(listdir(self.directory), self.pattern % "*") + files = fnmatch.filter(os.listdir(self.directory), self.pattern % "*") for filename in files: try: - remove(path.join(self.directory, filename)) + remove(os.path.join(self.directory, filename)) except OSError: pass diff --git a/src/jinja2/compiler.py b/src/jinja2/compiler.py index 63297b42..8965b320 100644 --- a/src/jinja2/compiler.py +++ b/src/jinja2/compiler.py @@ -2,6 +2,7 @@ """Compiles nodes from the parser into Python code.""" from collections import namedtuple from functools import update_wrapper +from io import StringIO from itertools import chain from keyword import iskeyword as is_python_keyword @@ -9,13 +10,6 @@ from markupsafe import escape from markupsafe import Markup from . import nodes -from ._compat import imap -from ._compat import iteritems -from ._compat import izip -from ._compat import NativeStringIO -from ._compat import range_type -from ._compat import string_types -from ._compat import text_type from .exceptions import TemplateAssertionError from .idtracking import Symbols from .idtracking import VAR_LOAD_ALIAS @@ -38,30 +32,6 @@ operators = { "notin": "not in", } -# what method to iterate over items do we want to use for dict iteration -# in generated code? on 2.x let's go with iteritems, on 3.x with items -if hasattr(dict, "iteritems"): - dict_item_iter = "iteritems" -else: - dict_item_iter = "items" - -code_features = ["division"] - -# does this python version support generator stops? (PEP 0479) -try: - exec("from __future__ import generator_stop") - code_features.append("generator_stop") -except SyntaxError: - pass - -# does this python version support yield from? -try: - exec("def f(): yield from x()") -except SyntaxError: - supports_yield_from = False -else: - supports_yield_from = True - def optimizeconst(f): def new_func(self, node, frame, **kwargs): @@ -93,20 +63,16 @@ def has_safe_repr(value): """Does the node have a safe representation?""" if value is None or value is NotImplemented or value is Ellipsis: return True - if type(value) in (bool, int, float, complex, range_type, Markup) + string_types: - return True - if type(value) in (tuple, list, set, frozenset): - for item in value: - if not has_safe_repr(item): - return False - return True - elif type(value) is dict: - for key, value in iteritems(value): - if not has_safe_repr(key): - return False - if not has_safe_repr(value): - return False + + if type(value) in {bool, int, float, complex, range, str, Markup}: return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + return False @@ -249,7 +215,7 @@ class CodeGenerator(NodeVisitor): self, environment, name, filename, stream=None, defer_init=False, optimized=True ): if stream is None: - stream = NativeStringIO() + stream = StringIO() self.environment = environment self.name = name self.filename = filename @@ -432,7 +398,7 @@ class CodeGenerator(NodeVisitor): self.write(", ") self.visit(kwarg, frame) if extra_kwargs is not None: - for key, value in iteritems(extra_kwargs): + for key, value in extra_kwargs.items(): self.write(", %s=%s" % (key, value)) if node.dyn_args: self.write(", *") @@ -448,7 +414,7 @@ class CodeGenerator(NodeVisitor): self.visit(kwarg.value, frame) self.write(", ") if extra_kwargs is not None: - for key, value in iteritems(extra_kwargs): + for key, value in extra_kwargs.items(): self.write("%r: %s, " % (key, value)) if node.dyn_kwargs is not None: self.write("}, **") @@ -477,7 +443,7 @@ class CodeGenerator(NodeVisitor): def enter_frame(self, frame): undefs = [] - for target, (action, param) in iteritems(frame.symbols.loads): + for target, (action, param) in frame.symbols.loads.items(): if action == VAR_LOAD_PARAMETER: pass elif action == VAR_LOAD_RESOLVE: @@ -494,7 +460,7 @@ class CodeGenerator(NodeVisitor): def leave_frame(self, frame, with_python_scope=False): if not with_python_scope: undefs = [] - for target, _ in iteritems(frame.symbols.loads): + for target in frame.symbols.loads: undefs.append(target) if undefs: self.writeline("%s = missing" % " = ".join(undefs)) @@ -612,7 +578,7 @@ class CodeGenerator(NodeVisitor): def dump_local_context(self, frame): return "{%s}" % ", ".join( "%r: %s" % (name, target) - for name, target in iteritems(frame.symbols.dump_stores()) + for name, target in frame.symbols.dump_stores().items() ) def write_commons(self): @@ -704,7 +670,7 @@ class CodeGenerator(NodeVisitor): else: self.writeline( "context.exported_vars.update((%s))" - % ", ".join(imap(repr, public_names)) + % ", ".join(map(repr, public_names)) ) # -- Statement Visitors @@ -715,7 +681,6 @@ class CodeGenerator(NodeVisitor): from .runtime import exported - self.writeline("from __future__ import %s" % ", ".join(code_features)) self.writeline("from jinja2.runtime import " + ", ".join(exported)) if self.environment.is_async: @@ -781,7 +746,7 @@ class CodeGenerator(NodeVisitor): self.indent() self.writeline("if parent_template is not None:") self.indent() - if supports_yield_from and not self.environment.is_async: + if not self.environment.is_async: self.writeline("yield from parent_template.root_render_func(context)") else: self.writeline( @@ -795,7 +760,7 @@ class CodeGenerator(NodeVisitor): self.outdent(1 + (not self.has_known_extends)) # at this point we now have the blocks collected and can visit them too. - for name, block in iteritems(self.blocks): + for name, block in self.blocks.items(): self.writeline( "%s(context, missing=missing%s):" % (self.func("block_" + name), envenv), @@ -851,11 +816,7 @@ class CodeGenerator(NodeVisitor): else: context = self.get_context_ref() - if ( - supports_yield_from - and not self.environment.is_async - and frame.buffer is None - ): + if not self.environment.is_async and frame.buffer is None: self.writeline( "yield from context.blocks[%r][0](%s)" % (node.name, context), node ) @@ -900,9 +861,7 @@ class CodeGenerator(NodeVisitor): self.writeline("parent_template = environment.get_template(", node) self.visit(node.template, frame) self.write(", %r)" % self.name) - self.writeline( - "for name, parent_block in parent_template.blocks.%s():" % dict_item_iter - ) + self.writeline("for name, parent_block in parent_template.blocks.items():") self.indent() self.writeline("context.blocks.setdefault(name, []).append(parent_block)") self.outdent() @@ -924,7 +883,7 @@ class CodeGenerator(NodeVisitor): func_name = "get_or_select_template" if isinstance(node.template, nodes.Const): - if isinstance(node.template.value, string_types): + if isinstance(node.template.value, str): func_name = "get_template" elif isinstance(node.template.value, (tuple, list)): func_name = "select_template" @@ -958,13 +917,8 @@ class CodeGenerator(NodeVisitor): "._body_stream:" ) else: - if supports_yield_from: - self.writeline("yield from template._get_default_module()._body_stream") - skip_event_yield = True - else: - self.writeline( - "for event in template._get_default_module()._body_stream:" - ) + self.writeline("yield from template._get_default_module()._body_stream") + skip_event_yield = True if not skip_event_yield: self.indent() @@ -1071,7 +1025,7 @@ class CodeGenerator(NodeVisitor): else: self.writeline( "context.exported_vars.difference_" - "update((%s))" % ", ".join(imap(repr, discarded_names)) + "update((%s))" % ", ".join(map(repr, discarded_names)) ) def visit_For(self, node, frame): @@ -1262,7 +1216,7 @@ class CodeGenerator(NodeVisitor): with_frame = frame.inner() with_frame.symbols.analyze_node(node) self.enter_frame(with_frame) - for target, expr in izip(node.targets, node.values): + for target, expr in zip(node.targets, node.values): self.newline() self.visit(target, with_frame) self.write(" = ") @@ -1278,7 +1232,7 @@ class CodeGenerator(NodeVisitor): #: The default finalize function if the environment isn't configured #: with one. Or if the environment has one, this is called on that #: function's output for constants. - _default_finalize = text_type + _default_finalize = str _finalize = None def _make_finalize(self): @@ -1344,7 +1298,7 @@ class CodeGenerator(NodeVisitor): # Template data doesn't go through finalize. if isinstance(node, nodes.TemplateData): - return text_type(const) + return str(const) return finalize.const(const) @@ -1353,11 +1307,11 @@ class CodeGenerator(NodeVisitor): ``Output`` node. """ if frame.eval_ctx.volatile: - self.write("(escape if context.eval_ctx.autoescape else to_string)(") + self.write("(escape if context.eval_ctx.autoescape else str)(") elif frame.eval_ctx.autoescape: self.write("escape(") else: - self.write("to_string(") + self.write("str(") if finalize.src is not None: self.write(finalize.src) @@ -1615,11 +1569,11 @@ class CodeGenerator(NodeVisitor): @optimizeconst def visit_Concat(self, node, frame): if frame.eval_ctx.volatile: - func_name = "(context.eval_ctx.volatile and markup_join or unicode_join)" + func_name = "(context.eval_ctx.volatile and markup_join or str_join)" elif frame.eval_ctx.autoescape: func_name = "markup_join" else: - func_name = "unicode_join" + func_name = "str_join" self.write("%s((" % func_name) for arg in node.nodes: self.visit(arg, frame) diff --git a/src/jinja2/debug.py b/src/jinja2/debug.py index d2c5a06b..2854a9f7 100644 --- a/src/jinja2/debug.py +++ b/src/jinja2/debug.py @@ -1,8 +1,8 @@ +import platform import sys from types import CodeType from . import TemplateSyntaxError -from ._compat import PYPY from .utils import internal_code from .utils import missing @@ -14,13 +14,11 @@ def rewrite_traceback_stack(source=None): This must be called within an ``except`` block. - :param exc_info: A :meth:`sys.exc_info` tuple. If not provided, - the current ``exc_info`` is used. :param source: For ``TemplateSyntaxError``, the original source if known. - :return: A :meth:`sys.exc_info` tuple that can be re-raised. + :return: The original exception with the rewritten traceback. """ - exc_type, exc_value, tb = sys.exc_info() + _, exc_value, tb = sys.exc_info() if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: exc_value.translated = True @@ -70,7 +68,7 @@ def rewrite_traceback_stack(source=None): for tb in reversed(stack): tb_next = tb_set_next(tb, tb_next) - return exc_type, exc_value, tb_next + return exc_value.with_traceback(tb_next) def fake_traceback(exc_value, tb, filename, lineno): @@ -215,7 +213,7 @@ if sys.version_info >= (3, 7): return tb -elif PYPY: +elif platform.python_implementation() == "PyPy": # PyPy might have special support, and won't work with ctypes. try: import tputil diff --git a/src/jinja2/defaults.py b/src/jinja2/defaults.py index 8e0e7d77..72a93578 100644 --- a/src/jinja2/defaults.py +++ b/src/jinja2/defaults.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from ._compat import range_type from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 from .tests import TESTS as DEFAULT_TESTS # noqa: F401 from .utils import Cycler @@ -24,7 +23,7 @@ KEEP_TRAILING_NEWLINE = False # default filters, tests and namespace DEFAULT_NAMESPACE = { - "range": range_type, + "range": range, "dict": dict, "lipsum": generate_lorem_ipsum, "cycler": Cycler, diff --git a/src/jinja2/environment.py b/src/jinja2/environment.py index 63ac0c8b..da7a09f3 100644 --- a/src/jinja2/environment.py +++ b/src/jinja2/environment.py @@ -11,13 +11,6 @@ from functools import reduce from markupsafe import Markup from . import nodes -from ._compat import encode_filename -from ._compat import implements_iterator -from ._compat import implements_to_string -from ._compat import iteritems -from ._compat import reraise -from ._compat import string_types -from ._compat import text_type from .compiler import CodeGenerator from .compiler import generate from .defaults import BLOCK_END_STRING @@ -102,7 +95,7 @@ def load_extensions(environment, extensions): """ result = {} for extension in extensions: - if isinstance(extension, string_types): + if isinstance(extension, str): extension = import_string(extension) result[extension.identifier] = extension(environment) return result @@ -376,7 +369,7 @@ class Environment(object): yet. This is used by :ref:`extensions ` to register callbacks and configuration values without breaking inheritance. """ - for key, value in iteritems(attributes): + for key, value in attributes.items(): if not hasattr(self, key): setattr(self, key, value) @@ -421,7 +414,7 @@ class Environment(object): rv.overlayed = True rv.linked_to = self - for key, value in iteritems(args): + for key, value in args.items(): if value is not missing: setattr(rv, key, value) @@ -431,7 +424,7 @@ class Environment(object): rv.cache = copy_cache(self.cache) rv.extensions = {} - for key, value in iteritems(self.extensions): + for key, value in self.extensions.items(): rv.extensions[key] = value.bind(rv) if extensions is not missing: rv.extensions.update(load_extensions(rv, extensions)) @@ -449,7 +442,7 @@ class Environment(object): try: return obj[argument] except (AttributeError, TypeError, LookupError): - if isinstance(argument, string_types): + if isinstance(argument, str): try: attr = str(argument) except Exception: @@ -534,7 +527,7 @@ class Environment(object): def _parse(self, source, name, filename): """Internal parsing function used by `parse` and `compile`.""" - return Parser(self, source, name, encode_filename(filename)).parse() + return Parser(self, source, name, filename).parse() def lex(self, source, name=None, filename=None): """Lex the given sourcecode and return a generator that yields @@ -546,7 +539,7 @@ class Environment(object): of the extensions to be applied you have to filter source through the :meth:`preprocess` method. """ - source = text_type(source) + source = str(source) try: return self.lexer.tokeniter(source, name, filename) except TemplateSyntaxError: @@ -560,7 +553,7 @@ class Environment(object): return reduce( lambda s, e: e.preprocess(s, name, filename), self.iter_extensions(), - text_type(source), + str(source), ) def _tokenize(self, source, name, filename=None, state=None): @@ -621,7 +614,7 @@ class Environment(object): """ source_hint = None try: - if isinstance(source, string_types): + if isinstance(source, str): source_hint = source source = self._parse(source, name, filename) source = self._generate(source, name, filename, defer_init=defer_init) @@ -629,8 +622,6 @@ class Environment(object): return source if filename is None: filename = "