annotate mercurial/__init__.py @ 43104:74802979dd9d

py3: define and use pycompat.itervalues() .itervalues() only exists on Python 2. Python 3's equivalent is .values(). But we don't want to blindly use .values() everywhere because on Python 2, it will create a list, which will have performance implications. This commit introduces pycompat.itervalues() which will call the appropriate method on the passed object. We update all callers of obj.itervalues() to pycompat.itervalues(obj) instead. With this commit, the only source tranforming remaining is for iteritems(). Victory is near... Differential Revision: https://phab.mercurial-scm.org/D7013
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 06 Oct 2019 17:59:15 -0400
parents c95b2f40db7c
children 649d3ac37a12
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
27220
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
1 # __init__.py - Startup and module loading logic for Mercurial.
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
2 #
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
4 #
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
5 # This software may be used and distributed according to the terms of the
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
6 # GNU General Public License version 2 or any later version.
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
7
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
8 from __future__ import absolute_import
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
9
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
10 import sys
29266
b3a677c82a35 debuginstall: expose modulepolicy
timeless <timeless@mozdev.org>
parents: 28513
diff changeset
11
32420
0906b85bf222 demandimport: move to separate package
Siddharth Agarwal <sid0@fb.com>
parents: 32373
diff changeset
12 # Allow 'from mercurial import demandimport' to keep working.
0906b85bf222 demandimport: move to separate package
Siddharth Agarwal <sid0@fb.com>
parents: 32373
diff changeset
13 import hgdemandimport
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
14
32420
0906b85bf222 demandimport: move to separate package
Siddharth Agarwal <sid0@fb.com>
parents: 32373
diff changeset
15 demandimport = hgdemandimport
0906b85bf222 demandimport: move to separate package
Siddharth Agarwal <sid0@fb.com>
parents: 32373
diff changeset
16
27220
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
17 __all__ = []
4374d819ccd5 mercurial: implement import hook for handling C/Python modules
Gregory Szorc <gregory.szorc@gmail.com>
parents: 0
diff changeset
18
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
19 # Python 3 uses a custom module loader that transforms source code between
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
20 # source file reading and compilation. This is done by registering a custom
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
21 # finder that changes the spec for Mercurial modules to use a custom loader.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
22 if sys.version_info[0] >= 3:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
23 import importlib
32373
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
24 import importlib.abc
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
25 import io
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
26 import token
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
27 import tokenize
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
28
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
29 class hgpathentryfinder(importlib.abc.MetaPathFinder):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
30 """A sys.meta_path finder that uses a custom module loader."""
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
31
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
32 def find_spec(self, fullname, path, target=None):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
33 # Only handle Mercurial-related modules.
42574
d28d91f9f35a py3: don't run source transformer on hgext3rd (extensions)
Martin von Zweigbergk <martinvonz@google.com>
parents: 42207
diff changeset
34 if not fullname.startswith(('mercurial.', 'hgext.')):
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
35 return None
36617
5246f940a48e py3: don't try to mangle C extension blob by code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 35245
diff changeset
36 # don't try to parse binary
5246f940a48e py3: don't try to mangle C extension blob by code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 35245
diff changeset
37 if fullname.startswith('mercurial.cext.'):
5246f940a48e py3: don't try to mangle C extension blob by code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 35245
diff changeset
38 return None
34396
9fb9f8440b71 python3: don't byte mangle third-party packages
Siddharth Agarwal <sid0@fb.com>
parents: 33502
diff changeset
39 # third-party packages are expected to be dual-version clean
9fb9f8440b71 python3: don't byte mangle third-party packages
Siddharth Agarwal <sid0@fb.com>
parents: 33502
diff changeset
40 if fullname.startswith('mercurial.thirdparty'):
9fb9f8440b71 python3: don't byte mangle third-party packages
Siddharth Agarwal <sid0@fb.com>
parents: 33502
diff changeset
41 return None
31307
f8d41edd0357 init: zstd is already python3-ready, so don't run it through our importer
Augie Fackler <raf@durin42.com>
parents: 31150
diff changeset
42 # zstd is already dual-version clean, don't try and mangle it
f8d41edd0357 init: zstd is already python3-ready, so don't run it through our importer
Augie Fackler <raf@durin42.com>
parents: 31150
diff changeset
43 if fullname.startswith('mercurial.zstd'):
f8d41edd0357 init: zstd is already python3-ready, so don't run it through our importer
Augie Fackler <raf@durin42.com>
parents: 31150
diff changeset
44 return None
40985
4277e20cfec4 rust-cpython: build and support for Python3
Georges Racinet <gracinet@anybox.fr>
parents: 38785
diff changeset
45 # rustext is built for the right python version,
4277e20cfec4 rust-cpython: build and support for Python3
Georges Racinet <gracinet@anybox.fr>
parents: 38785
diff changeset
46 # don't try and mangle it
4277e20cfec4 rust-cpython: build and support for Python3
Georges Racinet <gracinet@anybox.fr>
parents: 38785
diff changeset
47 if fullname.startswith('mercurial.rustext'):
4277e20cfec4 rust-cpython: build and support for Python3
Georges Racinet <gracinet@anybox.fr>
parents: 38785
diff changeset
48 return None
32521
942051a29fb6 loader: pywatchman appears to already be py3 compatible
Augie Fackler <raf@durin42.com>
parents: 32425
diff changeset
49 # pywatchman is already dual-version clean, don't try and mangle it
942051a29fb6 loader: pywatchman appears to already be py3 compatible
Augie Fackler <raf@durin42.com>
parents: 32425
diff changeset
50 if fullname.startswith('hgext.fsmonitor.pywatchman'):
942051a29fb6 loader: pywatchman appears to already be py3 compatible
Augie Fackler <raf@durin42.com>
parents: 32425
diff changeset
51 return None
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
52
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
53 # Try to find the module using other registered finders.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
54 spec = None
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
55 for finder in sys.meta_path:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
56 if finder == self:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
57 continue
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
58
42207
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
59 # Originally the API was a `find_module` method, but it was
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
60 # renamed to `find_spec` in python 3.4, with a new `target`
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
61 # argument.
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
62 find_spec_method = getattr(finder, 'find_spec', None)
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
63 if find_spec_method:
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
64 spec = find_spec_method(fullname, path, target=target)
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
65 else:
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
66 spec = finder.find_module(fullname)
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
67 if spec is not None:
7ed472e79096 py3: handle meta-path finders that only use pre-python3.4 API
Ludovic Chabant <ludovic@chabant.com>
parents: 40985
diff changeset
68 spec = importlib.util.spec_from_loader(fullname, spec)
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
69 if spec:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
70 break
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
71
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
72 # This is a Mercurial-related module but we couldn't find it
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
73 # using the previously-registered finders. This likely means
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
74 # the module doesn't exist.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
75 if not spec:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
76 return None
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
77
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
78 # TODO need to support loaders from alternate specs, like zip
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
79 # loaders.
32425
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
80 loader = hgloader(spec.name, spec.origin)
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
81 # Can't use util.safehasattr here because that would require
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
82 # importing util, and we're in import code.
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
83 if hasattr(spec.loader, 'loader'): # hasattr-py3-only
32425
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
84 # This is a nested loader (maybe a lazy loader?)
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
85 spec.loader.loader = loader
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
86 else:
397e3a2e9347 python3: allow hgloader to work with lazy loaders
Siddharth Agarwal <sid0@fb.com>
parents: 32420
diff changeset
87 spec.loader = loader
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
88 return spec
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
89
29800
178c89e8519a py3: import builtin wrappers automagically by code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 29550
diff changeset
90 def replacetokens(tokens, fullname):
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
91 """Transform a stream of tokens from raw to Python 3.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
92
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
93 It is called by the custom module loading machinery to rewrite
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
94 source/tokens between source decoding and compilation.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
95
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
96 Returns a generator of possibly rewritten tokens.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
97
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
98 The input token list may be mutated as part of processing. However,
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
99 its changes do not necessarily match the output token stream.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
100
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
101 REMEMBER TO CHANGE ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
102 OR CACHED FILES WON'T GET INVALIDATED PROPERLY.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
103 """
30165
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
104 # The following utility functions access the tokens list and i index of
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
105 # the for i, t enumerate(tokens) loop below
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
106 def _isop(j, *o):
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
107 """Assert that tokens[j] is an OP with one of the given values"""
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
108 try:
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
109 return tokens[j].type == token.OP and tokens[j].string in o
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
110 except IndexError:
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
111 return False
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
112
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
113 for i, t in enumerate(tokens):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
114 # This looks like a function call.
30165
423377290a3a py3: refactor token parsing to handle call args properly
Martijn Pieters <mjpieters@fb.com>
parents: 30118
diff changeset
115 if t.type == token.NAME and _isop(i + 1, '('):
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
116 fn = t.string
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
117
31445
83e080144faf py3: rewrite itervalues() as values() by importer
Yuya Nishihara <yuya@tcha.org>
parents: 31361
diff changeset
118 # It changes iteritems/values to items/values as they are not
30052
eaaedad68011 py3: switch to .items() using transformer
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30051
diff changeset
119 # present in Python 3 world.
43104
74802979dd9d py3: define and use pycompat.itervalues()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43103
diff changeset
120 if fn == 'iteritems' and not (
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
121 tokens[i - 1].type == token.NAME
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
122 and tokens[i - 1].string == 'def'
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
123 ):
31445
83e080144faf py3: rewrite itervalues() as values() by importer
Yuya Nishihara <yuya@tcha.org>
parents: 31361
diff changeset
124 yield t._replace(string=fn[4:])
30052
eaaedad68011 py3: switch to .items() using transformer
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30051
diff changeset
125 continue
eaaedad68011 py3: switch to .items() using transformer
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30051
diff changeset
126
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
127 # Emit unmodified token.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
128 yield t
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
129
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
130 # Header to add to bytecode files. This MUST be changed when
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
131 # ``replacetoken`` or any mechanism that changes semantics of module
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
132 # loading is changed. Otherwise cached bytecode may get loaded without
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
133 # the new transformation mechanisms applied.
43104
74802979dd9d py3: define and use pycompat.itervalues()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43103
diff changeset
134 BYTECODEHEADER = b'HG\x00\x15'
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
135
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
136 class hgloader(importlib.machinery.SourceFileLoader):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
137 """Custom module loader that transforms source code.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
138
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
139 When the source code is converted to a code object, we transform
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
140 certain patterns to be Python 3 compatible. This allows us to write code
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
141 that is natively Python 2 and compatible with Python 3 without
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
142 making the code excessively ugly.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
143
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
144 We do this by transforming the token stream between parse and compile.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
145
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
146 Implementing transformations invalidates caching assumptions made
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
147 by the built-in importer. The built-in importer stores a header on
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
148 saved bytecode files indicating the Python/bytecode version. If the
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
149 version changes, the cached bytecode is ignored. The Mercurial
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
150 transformations could change at any time. This means we need to check
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
151 that cached bytecode was generated with the current transformation
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
152 code or there could be a mismatch between cached bytecode and what
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
153 would be generated from this class.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
154
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
155 We supplement the bytecode caching layer by wrapping ``get_data``
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
156 and ``set_data``. These functions are called when the
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
157 ``SourceFileLoader`` retrieves and saves bytecode cache files,
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
158 respectively. We simply add an additional header on the file. As
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
159 long as the version in this file is changed when semantics change,
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
160 cached bytecode should be invalidated when transformations change.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
161
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
162 The added header has the form ``HG<VERSION>``. That is a literal
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
163 ``HG`` with 2 binary bytes indicating the transformation version.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
164 """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42603
diff changeset
165
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
166 def get_data(self, path):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
167 data = super(hgloader, self).get_data(path)
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
168
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
169 if not path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
170 return data
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
171
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
172 # There should be a header indicating the Mercurial transformation
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
173 # version. If it doesn't exist or doesn't match the current version,
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
174 # we raise an OSError because that is what
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
175 # ``SourceFileLoader.get_code()`` expects when loading bytecode
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
176 # paths to indicate the cached file is "bad."
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
177 if data[0:2] != b'HG':
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
178 raise OSError('no hg header')
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
179 if data[0:4] != BYTECODEHEADER:
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
180 raise OSError('hg header version mismatch')
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
181
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
182 return data[4:]
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
183
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
184 def set_data(self, path, data, *args, **kwargs):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
185 if path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
186 data = BYTECODEHEADER + data
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
187
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
188 return super(hgloader, self).set_data(path, data, *args, **kwargs)
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
189
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
190 def source_to_code(self, data, path):
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
191 """Perform token transformation before compilation."""
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
192 buf = io.BytesIO(data)
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
193 tokens = tokenize.tokenize(buf.readline)
29800
178c89e8519a py3: import builtin wrappers automagically by code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 29550
diff changeset
194 data = tokenize.untokenize(replacetokens(list(tokens), self.name))
29550
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
195 # Python's built-in importer strips frames from exceptions raised
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
196 # for this code. Unfortunately, that mechanism isn't extensible
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
197 # and our frame will be blamed for the import failure. There
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
198 # are extremely hacky ways to do frame stripping. We haven't
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
199 # implemented them because they are very ugly.
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
200 return super(hgloader, self).source_to_code(data, path)
1c22400db72d mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29490
diff changeset
201
32373
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
202 # We automagically register our custom importer as a side-effect of
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
203 # loading. This is necessary to ensure that any entry points are able
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
204 # to import mercurial.* modules without having to perform this
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
205 # registration themselves.
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
206 if not any(isinstance(x, hgpathentryfinder) for x in sys.meta_path):
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
207 # meta_path is used before any implicit finders and before sys.path.
5700825889fb policy: drop custom importer for pure modules
Yuya Nishihara <yuya@tcha.org>
parents: 32372
diff changeset
208 sys.meta_path.insert(0, hgpathentryfinder())