From 7956ba344e16afb69aa3637fdee18dbd145322c1 Mon Sep 17 00:00:00 2001 From: L2501 Date: Mon, 29 Apr 2024 07:52:15 +0000 Subject: [PATCH] [script.module.future] 1.0.0+matrix.1 --- script.module.future/addon.xml | 2 +- script.module.future/lib/future/__init__.py | 19 +- .../lib/future/backports/datetime.py | 2 +- .../backports/email/_header_value_parser.py | 2 +- .../lib/future/backports/email/parser.py | 4 +- .../lib/future/backports/http/cookiejar.py | 2 +- .../lib/future/backports/test/support.py | 32 --- .../lib/future/backports/xmlrpc/client.py | 9 +- .../lib/future/builtins/__init__.py | 2 +- .../lib/future/moves/_dummy_thread.py | 11 +- .../lib/future/moves/multiprocessing.py | 7 + .../lib/future/moves/test/support.py | 9 + .../lib/future/standard_library/__init__.py | 14 +- .../lib/future/types/newint.py | 8 +- .../lib/future/types/newrange.py | 2 +- .../lib/libfuturize/fixer_util.py | 12 +- .../lib/libfuturize/fixes/fix_metaclass.py | 4 +- .../lib/libpasteurize/fixes/fix_imports.py | 1 + .../lib/libpasteurize/fixes/fix_unpacking.py | 8 +- script.module.future/lib/past/__init__.py | 4 +- .../lib/past/builtins/misc.py | 9 +- .../lib/past/translation/__init__.py | 258 ++++++++---------- 22 files changed, 195 insertions(+), 226 deletions(-) create mode 100644 script.module.future/lib/future/moves/multiprocessing.py diff --git a/script.module.future/addon.xml b/script.module.future/addon.xml index c52104fd1..ba43439ad 100644 --- a/script.module.future/addon.xml +++ b/script.module.future/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.module.future/lib/future/__init__.py b/script.module.future/lib/future/__init__.py index b609299a7..b097fd81e 100644 --- a/script.module.future/lib/future/__init__.py +++ b/script.module.future/lib/future/__init__.py @@ -52,7 +52,7 @@ -------------------- An included script called `futurize -`_ aids in converting +`_ aids in converting code (from either Python 2 or Python 3) to code compatible with both platforms. It is similar to ``python-modernize`` but goes further in providing Python 3 compatibility through the use of the backported types @@ -62,21 +62,20 @@ Documentation ------------- -See: http://python-future.org +See: https://python-future.org Credits ------- :Author: Ed Schofield, Jordan M. Adler, et al -:Sponsor: Python Charmers Pty Ltd, Australia, and Python Charmers Pte - Ltd, Singapore. http://pythoncharmers.com -:Others: See docs/credits.rst or http://python-future.org/credits.html +:Sponsor: Python Charmers: https://pythoncharmers.com +:Others: See docs/credits.rst or https://python-future.org/credits.html Licensing --------- -Copyright 2013-2019 Python Charmers Pty Ltd, Australia. +Copyright 2013-2024 Python Charmers, Australia. The software is distributed under an MIT licence. See LICENSE.txt. """ @@ -84,10 +83,10 @@ __title__ = 'future' __author__ = 'Ed Schofield' __license__ = 'MIT' -__copyright__ = 'Copyright 2013-2019 Python Charmers Pty Ltd' -__ver_major__ = 0 -__ver_minor__ = 18 -__ver_patch__ = 3 +__copyright__ = 'Copyright 2013-2024 Python Charmers (https://pythoncharmers.com)' +__ver_major__ = 1 +__ver_minor__ = 0 +__ver_patch__ = 0 __ver_sub__ = '' __version__ = "%d.%d.%d%s" % (__ver_major__, __ver_minor__, __ver_patch__, __ver_sub__) diff --git a/script.module.future/lib/future/backports/datetime.py b/script.module.future/lib/future/backports/datetime.py index 3261014e0..8cd62ddfa 100644 --- a/script.module.future/lib/future/backports/datetime.py +++ b/script.module.future/lib/future/backports/datetime.py @@ -689,7 +689,7 @@ def today(cls): @classmethod def fromordinal(cls, n): - """Contruct a date from a proleptic Gregorian ordinal. + """Construct a date from a proleptic Gregorian ordinal. January 1 of year 1 is day 1. Only the year, month and day are non-zero in the result. diff --git a/script.module.future/lib/future/backports/email/_header_value_parser.py b/script.module.future/lib/future/backports/email/_header_value_parser.py index 43957edc1..59b1b318f 100644 --- a/script.module.future/lib/future/backports/email/_header_value_parser.py +++ b/script.module.future/lib/future/backports/email/_header_value_parser.py @@ -2867,7 +2867,7 @@ def parse_content_type_header(value): _find_mime_parameters(ctype, value) return ctype ctype.append(token) - # XXX: If we really want to follow the formal grammer we should make + # XXX: If we really want to follow the formal grammar we should make # mantype and subtype specialized TokenLists here. Probably not worth it. if not value or value[0] != '/': ctype.defects.append(errors.InvalidHeaderDefect( diff --git a/script.module.future/lib/future/backports/email/parser.py b/script.module.future/lib/future/backports/email/parser.py index df1c6e286..79f0e5a33 100644 --- a/script.module.future/lib/future/backports/email/parser.py +++ b/script.module.future/lib/future/backports/email/parser.py @@ -26,7 +26,7 @@ def __init__(self, _class=Message, **_3to2kwargs): textual representation of the message. The string must be formatted as a block of RFC 2822 headers and header - continuation lines, optionally preceeded by a `Unix-from' header. The + continuation lines, optionally preceded by a `Unix-from' header. The header block is terminated either by the end of the string or by a blank line. @@ -92,7 +92,7 @@ def __init__(self, *args, **kw): textual representation of the message. The input must be formatted as a block of RFC 2822 headers and header - continuation lines, optionally preceeded by a `Unix-from' header. The + continuation lines, optionally preceded by a `Unix-from' header. The header block is terminated either by the end of the input or by a blank line. diff --git a/script.module.future/lib/future/backports/http/cookiejar.py b/script.module.future/lib/future/backports/http/cookiejar.py index 0ad80a025..a39242c08 100644 --- a/script.module.future/lib/future/backports/http/cookiejar.py +++ b/script.module.future/lib/future/backports/http/cookiejar.py @@ -1851,7 +1851,7 @@ def lwp_cookie_str(cookie): class LWPCookieJar(FileCookieJar): """ The LWPCookieJar saves a sequence of "Set-Cookie3" lines. - "Set-Cookie3" is the format used by the libwww-perl libary, not known + "Set-Cookie3" is the format used by the libwww-perl library, not known to be compatible with any browser, but which is easy to read and doesn't lose information about RFC 2965 cookies. diff --git a/script.module.future/lib/future/backports/test/support.py b/script.module.future/lib/future/backports/test/support.py index 1999e208f..6639372bc 100644 --- a/script.module.future/lib/future/backports/test/support.py +++ b/script.module.future/lib/future/backports/test/support.py @@ -28,7 +28,6 @@ # import collections.abc # not present on Py2.7 import re import subprocess -import imp import time try: import sysconfig @@ -341,37 +340,6 @@ def rmtree(path): if error.errno != errno.ENOENT: raise -def make_legacy_pyc(source): - """Move a PEP 3147 pyc/pyo file to its legacy pyc/pyo location. - - The choice of .pyc or .pyo extension is done based on the __debug__ flag - value. - - :param source: The file system path to the source file. The source file - does not need to exist, however the PEP 3147 pyc file must exist. - :return: The file system path to the legacy pyc file. - """ - pyc_file = imp.cache_from_source(source) - up_one = os.path.dirname(os.path.abspath(source)) - legacy_pyc = os.path.join(up_one, source + ('c' if __debug__ else 'o')) - os.rename(pyc_file, legacy_pyc) - return legacy_pyc - -def forget(modname): - """'Forget' a module was ever imported. - - This removes the module from sys.modules and deletes any PEP 3147 or - legacy .pyc and .pyo files. - """ - unload(modname) - for dirname in sys.path: - source = os.path.join(dirname, modname + '.py') - # It doesn't matter if they exist or not, unlink all possible - # combinations of PEP 3147 and legacy pyc and pyo files. - unlink(source + 'c') - unlink(source + 'o') - unlink(imp.cache_from_source(source, debug_override=True)) - unlink(imp.cache_from_source(source, debug_override=False)) # On some platforms, should not run gui test even if it is allowed # in `use_resources'. diff --git a/script.module.future/lib/future/backports/xmlrpc/client.py b/script.module.future/lib/future/backports/xmlrpc/client.py index b78e5bad6..0838f61af 100644 --- a/script.module.future/lib/future/backports/xmlrpc/client.py +++ b/script.module.future/lib/future/backports/xmlrpc/client.py @@ -134,10 +134,11 @@ from future.builtins import bytes, dict, int, range, str import base64 -# Py2.7 compatibility hack -base64.encodebytes = base64.encodestring -base64.decodebytes = base64.decodestring import sys +if sys.version_info < (3, 9): + # Py2.7 compatibility hack + base64.encodebytes = base64.encodestring + base64.decodebytes = base64.decodestring import time from datetime import datetime from future.backports.http import client as http_client @@ -1251,7 +1252,7 @@ def close(self): # Send HTTP request. # # @param host Host descriptor (URL or (URL, x509 info) tuple). - # @param handler Targer RPC handler (a path relative to host) + # @param handler Target RPC handler (a path relative to host) # @param request_body The XML-RPC request body # @param debug Enable debugging if debug is true. # @return An HTTPConnection. diff --git a/script.module.future/lib/future/builtins/__init__.py b/script.module.future/lib/future/builtins/__init__.py index 8bc1649d2..1734cd45f 100644 --- a/script.module.future/lib/future/builtins/__init__.py +++ b/script.module.future/lib/future/builtins/__init__.py @@ -2,7 +2,7 @@ A module that brings in equivalents of the new and modified Python 3 builtins into Py2. Has no effect on Py3. -See the docs `here `_ +See the docs `here `_ (``docs/what-else.rst``) for more information. """ diff --git a/script.module.future/lib/future/moves/_dummy_thread.py b/script.module.future/lib/future/moves/_dummy_thread.py index 688d249bb..6633f42e0 100644 --- a/script.module.future/lib/future/moves/_dummy_thread.py +++ b/script.module.future/lib/future/moves/_dummy_thread.py @@ -1,8 +1,13 @@ from __future__ import absolute_import -from future.utils import PY3 +from future.utils import PY3, PY39_PLUS -if PY3: - from _dummy_thread import * + +if PY39_PLUS: + # _dummy_thread and dummy_threading modules were both deprecated in + # Python 3.7 and removed in Python 3.9 + from _thread import * +elif PY3: + from _dummy_thread import * else: __future_module__ = True from dummy_thread import * diff --git a/script.module.future/lib/future/moves/multiprocessing.py b/script.module.future/lib/future/moves/multiprocessing.py new file mode 100644 index 000000000..a871b676f --- /dev/null +++ b/script.module.future/lib/future/moves/multiprocessing.py @@ -0,0 +1,7 @@ +from __future__ import absolute_import +from future.utils import PY3 + +from multiprocessing import * +if not PY3: + __future_module__ = True + from multiprocessing.queues import SimpleQueue diff --git a/script.module.future/lib/future/moves/test/support.py b/script.module.future/lib/future/moves/test/support.py index e9aa0f48f..f70c9d7db 100644 --- a/script.module.future/lib/future/moves/test/support.py +++ b/script.module.future/lib/future/moves/test/support.py @@ -1,9 +1,18 @@ from __future__ import absolute_import + +import sys + from future.standard_library import suspend_hooks from future.utils import PY3 if PY3: from test.support import * + if sys.version_info[:2] >= (3, 10): + from test.support.os_helper import ( + EnvironmentVarGuard, + TESTFN, + ) + from test.support.warnings_helper import check_warnings else: __future_module__ = True with suspend_hooks(): diff --git a/script.module.future/lib/future/standard_library/__init__.py b/script.module.future/lib/future/standard_library/__init__.py index cff02f959..d467aaf49 100644 --- a/script.module.future/lib/future/standard_library/__init__.py +++ b/script.module.future/lib/future/standard_library/__init__.py @@ -17,7 +17,7 @@ import socketserver import winreg # on Windows only import test.support - import html, html.parser, html.entites + import html, html.parser, html.entities import http, http.client, http.server import http.cookies, http.cookiejar import urllib.parse, urllib.request, urllib.response, urllib.error, urllib.robotparser @@ -33,6 +33,7 @@ from collections import OrderedDict, Counter, ChainMap # even on Py2.6 from subprocess import getoutput, getstatusoutput from subprocess import check_output # even on Py2.6 + from multiprocessing import SimpleQueue (The renamed modules and functions are still available under their old names on Python 2.) @@ -62,9 +63,12 @@ import sys import logging -import imp +# imp was deprecated in python 3.6 +if sys.version_info >= (3, 6): + import importlib as imp +else: + import imp import contextlib -import types import copy import os @@ -108,6 +112,7 @@ 'future.moves.socketserver': 'socketserver', 'ConfigParser': 'configparser', 'repr': 'reprlib', + 'multiprocessing.queues': 'multiprocessing', # 'FileDialog': 'tkinter.filedialog', # 'tkFileDialog': 'tkinter.filedialog', # 'SimpleDialog': 'tkinter.simpledialog', @@ -125,7 +130,7 @@ # 'Tkinter': 'tkinter', '_winreg': 'winreg', 'thread': '_thread', - 'dummy_thread': '_dummy_thread', + 'dummy_thread': '_dummy_thread' if sys.version_info < (3, 9) else '_thread', # 'anydbm': 'dbm', # causes infinite import loop # 'whichdb': 'dbm', # causes infinite import loop # anydbm and whichdb are handled by fix_imports2 @@ -184,6 +189,7 @@ ('itertools', 'filterfalse','itertools', 'ifilterfalse'), ('itertools', 'zip_longest','itertools', 'izip_longest'), ('sys', 'intern','__builtin__', 'intern'), + ('multiprocessing', 'SimpleQueue', 'multiprocessing.queues', 'SimpleQueue'), # The re module has no ASCII flag in Py2, but this is the default. # Set re.ASCII to a zero constant. stat.ST_MODE just happens to be one # (and it exists on Py2.6+). diff --git a/script.module.future/lib/future/types/newint.py b/script.module.future/lib/future/types/newint.py index 04a411e93..ebc5715e2 100644 --- a/script.module.future/lib/future/types/newint.py +++ b/script.module.future/lib/future/types/newint.py @@ -223,9 +223,11 @@ def __pow__(self, other): def __rpow__(self, other): value = super(newint, self).__rpow__(other) - if value is NotImplemented: + if isint(value): + return newint(value) + elif value is NotImplemented: return other ** long(self) - return newint(value) + return value def __lshift__(self, other): if not isint(other): @@ -318,7 +320,7 @@ def to_bytes(self, length, byteorder='big', signed=False): bits = length * 8 num = (2**bits) + self if num <= 0: - raise OverflowError("int too smal to convert") + raise OverflowError("int too small to convert") else: if self < 0: raise OverflowError("can't convert negative int to unsigned") diff --git a/script.module.future/lib/future/types/newrange.py b/script.module.future/lib/future/types/newrange.py index 6d4ebe2f8..dc5eb8022 100644 --- a/script.module.future/lib/future/types/newrange.py +++ b/script.module.future/lib/future/types/newrange.py @@ -105,7 +105,7 @@ def index(self, value): raise ValueError('%r is not in range' % value) def count(self, value): - """Return the number of ocurrences of integer `value` + """Return the number of occurrences of integer `value` in the sequence this range represents.""" # a value can occur exactly zero or one times return int(value in self) diff --git a/script.module.future/lib/libfuturize/fixer_util.py b/script.module.future/lib/libfuturize/fixer_util.py index 48e4689db..b5c123f6c 100644 --- a/script.module.future/lib/libfuturize/fixer_util.py +++ b/script.module.future/lib/libfuturize/fixer_util.py @@ -9,11 +9,11 @@ """ from lib2to3.fixer_util import (FromImport, Newline, is_import, - find_root, does_tree_import, Comma) + find_root, does_tree_import, + Call, Name, Comma) from lib2to3.pytree import Leaf, Node -from lib2to3.pygram import python_symbols as syms, python_grammar +from lib2to3.pygram import python_symbols as syms from lib2to3.pygram import token -from lib2to3.fixer_util import (Node, Call, Name, syms, Comma, Number) import re @@ -116,7 +116,7 @@ def suitify(parent): """ for node in parent.children: if node.type == syms.suite: - # already in the prefered format, do nothing + # already in the preferred format, do nothing return # One-liners have no suite node, we have to fake one up @@ -390,6 +390,7 @@ def touch_import_top(package, name_to_import, node): break insert_pos = idx + children_hooks = [] if package is None: import_ = Node(syms.import_name, [ Leaf(token.NAME, u"import"), @@ -413,8 +414,6 @@ def touch_import_top(package, name_to_import, node): ] ) children_hooks = [install_hooks, Newline()] - else: - children_hooks = [] # FromImport(package, [Leaf(token.NAME, name_to_import, prefix=u" ")]) @@ -448,7 +447,6 @@ def check_future_import(node): else: node = node.children[3] # now node is the import_as_name[s] - # print(python_grammar.number2symbol[node.type]) # breaks sometimes if node.type == syms.import_as_names: result = set() for n in node.children: diff --git a/script.module.future/lib/libfuturize/fixes/fix_metaclass.py b/script.module.future/lib/libfuturize/fixes/fix_metaclass.py index 2ac41c972..a7eee40d3 100644 --- a/script.module.future/lib/libfuturize/fixes/fix_metaclass.py +++ b/script.module.future/lib/libfuturize/fixes/fix_metaclass.py @@ -37,7 +37,7 @@ def has_metaclass(parent): """ we have to check the cls_node without changing it. - There are two possiblities: + There are two possibilities: 1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta') 2) clsdef => simple_stmt => expr_stmt => Leaf('__meta') """ @@ -63,7 +63,7 @@ def fixup_parse_tree(cls_node): # already in the preferred format, do nothing return - # !%@#! oneliners have no suite node, we have to fake one up + # !%@#! one-liners have no suite node, we have to fake one up for i, node in enumerate(cls_node.children): if node.type == token.COLON: break diff --git a/script.module.future/lib/libpasteurize/fixes/fix_imports.py b/script.module.future/lib/libpasteurize/fixes/fix_imports.py index 2d6718f16..b18ecf3df 100644 --- a/script.module.future/lib/libpasteurize/fixes/fix_imports.py +++ b/script.module.future/lib/libpasteurize/fixes/fix_imports.py @@ -16,6 +16,7 @@ u"winreg": u"_winreg", u"configparser": u"ConfigParser", u"copyreg": u"copy_reg", + u"multiprocessing.SimpleQueue": u"multiprocessing.queues.SimpleQueue", u"queue": u"Queue", u"socketserver": u"SocketServer", u"_markupbase": u"markupbase", diff --git a/script.module.future/lib/libpasteurize/fixes/fix_unpacking.py b/script.module.future/lib/libpasteurize/fixes/fix_unpacking.py index c2d3207a2..6e839e6bf 100644 --- a/script.module.future/lib/libpasteurize/fixes/fix_unpacking.py +++ b/script.module.future/lib/libpasteurize/fixes/fix_unpacking.py @@ -18,8 +18,12 @@ def assignment_source(num_pre, num_post, LISTNAME, ITERNAME): Returns a source fit for Assign() from fixer_util """ children = [] - pre = unicode(num_pre) - post = unicode(num_post) + try: + pre = unicode(num_pre) + post = unicode(num_post) + except NameError: + pre = str(num_pre) + post = str(num_post) # This code builds the assignment source from lib2to3 tree primitives. # It's not very readable, but it seems like the most correct way to do it. if num_pre > 0: diff --git a/script.module.future/lib/past/__init__.py b/script.module.future/lib/past/__init__.py index 147130393..54619e0a6 100644 --- a/script.module.future/lib/past/__init__.py +++ b/script.module.future/lib/past/__init__.py @@ -75,12 +75,12 @@ ------- :Author: Ed Schofield, Jordan M. Adler, et al -:Sponsor: Python Charmers Pty Ltd, Australia: http://pythoncharmers.com +:Sponsor: Python Charmers: https://pythoncharmers.com Licensing --------- -Copyright 2013-2019 Python Charmers Pty Ltd, Australia. +Copyright 2013-2024 Python Charmers, Australia. The software is distributed under an MIT licence. See LICENSE.txt. """ diff --git a/script.module.future/lib/past/builtins/misc.py b/script.module.future/lib/past/builtins/misc.py index 3600695c0..0b8e6a986 100644 --- a/script.module.future/lib/past/builtins/misc.py +++ b/script.module.future/lib/past/builtins/misc.py @@ -1,11 +1,13 @@ from __future__ import unicode_literals import inspect +import sys import math import numbers from future.utils import PY2, PY3, exec_ + if PY2: from collections import Mapping else: @@ -103,13 +105,12 @@ def oct(number): return '0' + builtins.oct(number)[2:] raw_input = input - - try: + # imp was deprecated in python 3.6 + if sys.version_info >= (3, 6): from importlib import reload - except ImportError: + else: # for python2, python3 <= 3.4 from imp import reload - unicode = str unichr = chr xrange = range diff --git a/script.module.future/lib/past/translation/__init__.py b/script.module.future/lib/past/translation/__init__.py index 7c6788668..ae6c0d90f 100644 --- a/script.module.future/lib/past/translation/__init__.py +++ b/script.module.future/lib/past/translation/__init__.py @@ -32,17 +32,31 @@ Inspired by and based on ``uprefix`` by Vinay M. Sajip. """ -import imp +import sys +# imp was deprecated in python 3.6 +if sys.version_info >= (3, 6): + import importlib as imp +else: + import imp import logging -import marshal import os -import sys import copy from lib2to3.pgen2.parse import ParseError from lib2to3.refactor import RefactoringTool from libfuturize import fixes +try: + from importlib.machinery import ( + PathFinder, + SourceFileLoader, + ) +except ImportError: + PathFinder = None + SourceFileLoader = object + +if sys.version_info[:2] < (3, 4): + import imp logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -225,6 +239,81 @@ def detect_python2(source, pathname): return False +def transform(source, pathname): + # This implementation uses lib2to3, + # you can override and use something else + # if that's better for you + + # lib2to3 likes a newline at the end + RTs.setup() + source += '\n' + try: + tree = RTs._rt.refactor_string(source, pathname) + except ParseError as e: + if e.msg != 'bad input' or e.value != '=': + raise + tree = RTs._rtp.refactor_string(source, pathname) + # could optimise a bit for only doing str(tree) if + # getattr(tree, 'was_changed', False) returns True + return str(tree)[:-1] # remove added newline + + +class PastSourceFileLoader(SourceFileLoader): + exclude_paths = [] + include_paths = [] + + def _convert_needed(self): + fullname = self.name + if any(fullname.startswith(path) for path in self.exclude_paths): + convert = False + elif any(fullname.startswith(path) for path in self.include_paths): + convert = True + else: + convert = False + return convert + + def _exec_transformed_module(self, module): + source = self.get_source(self.name) + pathname = self.path + if detect_python2(source, pathname): + source = transform(source, pathname) + code = compile(source, pathname, "exec") + exec(code, module.__dict__) + + # For Python 3.3 + def load_module(self, fullname): + logger.debug("Running load_module for %s", fullname) + if fullname in sys.modules: + mod = sys.modules[fullname] + else: + if self._convert_needed(): + logger.debug("Autoconverting %s", fullname) + mod = imp.new_module(fullname) + sys.modules[fullname] = mod + + # required by PEP 302 + mod.__file__ = self.path + mod.__loader__ = self + if self.is_package(fullname): + mod.__path__ = [] + mod.__package__ = fullname + else: + mod.__package__ = fullname.rpartition('.')[0] + self._exec_transformed_module(mod) + else: + mod = super().load_module(fullname) + return mod + + # For Python >=3.4 + def exec_module(self, module): + logger.debug("Running exec_module for %s", module) + if self._convert_needed(): + logger.debug("Autoconverting %s", self.name) + self._exec_transformed_module(module) + else: + super().exec_module(module) + + class Py2Fixer(object): """ An import hook class that uses lib2to3 for source-to-source translation of @@ -258,151 +347,30 @@ def exclude(self, paths): """ self.exclude_paths += paths + # For Python 3.3 def find_module(self, fullname, path=None): - logger.debug('Running find_module: {0}...'.format(fullname)) - if '.' in fullname: - parent, child = fullname.rsplit('.', 1) - if path is None: - loader = self.find_module(parent, path) - mod = loader.load_module(parent) - path = mod.__path__ - fullname = child - - # Perhaps we should try using the new importlib functionality in Python - # 3.3: something like this? - # thing = importlib.machinery.PathFinder.find_module(fullname, path) - try: - self.found = imp.find_module(fullname, path) - except Exception as e: - logger.debug('Py2Fixer could not find {0}') - logger.debug('Exception was: {0})'.format(fullname, e)) + logger.debug("Running find_module: (%s, %s)", fullname, path) + loader = PathFinder.find_module(fullname, path) + if not loader: + logger.debug("Py2Fixer could not find %s", fullname) return None - self.kind = self.found[-1][-1] - if self.kind == imp.PKG_DIRECTORY: - self.pathname = os.path.join(self.found[1], '__init__.py') - elif self.kind == imp.PY_SOURCE: - self.pathname = self.found[1] - return self - - def transform(self, source): - # This implementation uses lib2to3, - # you can override and use something else - # if that's better for you - - # lib2to3 likes a newline at the end - RTs.setup() - source += '\n' - try: - tree = RTs._rt.refactor_string(source, self.pathname) - except ParseError as e: - if e.msg != 'bad input' or e.value != '=': - raise - tree = RTs._rtp.refactor_string(source, self.pathname) - # could optimise a bit for only doing str(tree) if - # getattr(tree, 'was_changed', False) returns True - return str(tree)[:-1] # remove added newline - - def load_module(self, fullname): - logger.debug('Running load_module for {0}...'.format(fullname)) - if fullname in sys.modules: - mod = sys.modules[fullname] - else: - if self.kind in (imp.PY_COMPILED, imp.C_EXTENSION, imp.C_BUILTIN, - imp.PY_FROZEN): - convert = False - # elif (self.pathname.startswith(_stdlibprefix) - # and 'site-packages' not in self.pathname): - # # We assume it's a stdlib package in this case. Is this too brittle? - # # Please file a bug report at https://github.com/PythonCharmers/python-future - # # if so. - # convert = False - # in theory, other paths could be configured to be excluded here too - elif any([fullname.startswith(path) for path in self.exclude_paths]): - convert = False - elif any([fullname.startswith(path) for path in self.include_paths]): - convert = True - else: - convert = False - if not convert: - logger.debug('Excluded {0} from translation'.format(fullname)) - mod = imp.load_module(fullname, *self.found) - else: - logger.debug('Autoconverting {0} ...'.format(fullname)) - mod = imp.new_module(fullname) - sys.modules[fullname] = mod - - # required by PEP 302 - mod.__file__ = self.pathname - mod.__name__ = fullname - mod.__loader__ = self - - # This: - # mod.__package__ = '.'.join(fullname.split('.')[:-1]) - # seems to result in "SystemError: Parent module '' not loaded, - # cannot perform relative import" for a package's __init__.py - # file. We use the approach below. Another option to try is the - # minimal load_module pattern from the PEP 302 text instead. - - # Is the test in the next line more or less robust than the - # following one? Presumably less ... - # ispkg = self.pathname.endswith('__init__.py') - - if self.kind == imp.PKG_DIRECTORY: - mod.__path__ = [ os.path.dirname(self.pathname) ] - mod.__package__ = fullname - else: - #else, regular module - mod.__path__ = [] - mod.__package__ = fullname.rpartition('.')[0] + loader.__class__ = PastSourceFileLoader + loader.exclude_paths = self.exclude_paths + loader.include_paths = self.include_paths + return loader + + # For Python >=3.4 + def find_spec(self, fullname, path=None, target=None): + logger.debug("Running find_spec: (%s, %s, %s)", fullname, path, target) + spec = PathFinder.find_spec(fullname, path, target) + if not spec: + logger.debug("Py2Fixer could not find %s", fullname) + return None + spec.loader.__class__ = PastSourceFileLoader + spec.loader.exclude_paths = self.exclude_paths + spec.loader.include_paths = self.include_paths + return spec - try: - cachename = imp.cache_from_source(self.pathname) - if not os.path.exists(cachename): - update_cache = True - else: - sourcetime = os.stat(self.pathname).st_mtime - cachetime = os.stat(cachename).st_mtime - update_cache = cachetime < sourcetime - # # Force update_cache to work around a problem with it being treated as Py3 code??? - # update_cache = True - if not update_cache: - with open(cachename, 'rb') as f: - data = f.read() - try: - code = marshal.loads(data) - except Exception: - # pyc could be corrupt. Regenerate it - update_cache = True - if update_cache: - if self.found[0]: - source = self.found[0].read() - elif self.kind == imp.PKG_DIRECTORY: - with open(self.pathname) as f: - source = f.read() - - if detect_python2(source, self.pathname): - source = self.transform(source) - - code = compile(source, self.pathname, 'exec') - - dirname = os.path.dirname(cachename) - try: - if not os.path.exists(dirname): - os.makedirs(dirname) - with open(cachename, 'wb') as f: - data = marshal.dumps(code) - f.write(data) - except Exception: # could be write-protected - pass - exec(code, mod.__dict__) - except Exception as e: - # must remove module from sys.modules - del sys.modules[fullname] - raise # keep it simple - - if self.found[0]: - self.found[0].close() - return mod _hook = Py2Fixer()