strip-hints 0.1.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strip_hints/__init__.py +14 -0
- strip_hints/import_hooks.py +119 -0
- strip_hints/import_hooks_py3.py +72 -0
- strip_hints/strip_hints_main.py +598 -0
- strip_hints/token_list.py +430 -0
- strip_hints-0.1.11.dist-info/LICENSE.txt +22 -0
- strip_hints-0.1.11.dist-info/METADATA +278 -0
- strip_hints-0.1.11.dist-info/RECORD +11 -0
- strip_hints-0.1.11.dist-info/WHEEL +5 -0
- strip_hints-0.1.11.dist-info/entry_points.txt +2 -0
- strip_hints-0.1.11.dist-info/top_level.txt +1 -0
strip_hints/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
Strip type hints from Python code files.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import print_function, division, absolute_import
|
|
10
|
+
|
|
11
|
+
# Just import all for now.
|
|
12
|
+
from .strip_hints_main import *
|
|
13
|
+
from .token_list import *
|
|
14
|
+
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
Code to set up import hooks for Python 2 to automatically strip hints from
|
|
5
|
+
modules when they are loaded. Note the use of `imp` is deprecated for Python 3.
|
|
6
|
+
|
|
7
|
+
This example code was very helpful: https://github.com/aroberge/splore
|
|
8
|
+
|
|
9
|
+
Note: Consider also this `importlib` backport to Python 2:
|
|
10
|
+
https://pypi.org/project/importlib2/
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import print_function, division, absolute_import
|
|
15
|
+
import imp
|
|
16
|
+
import sys
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
version = sys.version_info[0]
|
|
20
|
+
|
|
21
|
+
strip_importer_instance = None # Only install one, then modify its static attributes.
|
|
22
|
+
|
|
23
|
+
class StripHintsImporter(object):
|
|
24
|
+
"""Strip hints on import."""
|
|
25
|
+
stripper_fun_to_use = {} # Dict of stripper funs keyed by canonical dir paths.
|
|
26
|
+
|
|
27
|
+
def find_module(self, module_name, path=None):
|
|
28
|
+
"""Find the module with the given name. Uses `path`, or `sys.path` if
|
|
29
|
+
it is omitted. Returns `(file, pathname, description)`."""
|
|
30
|
+
split_module_name = module_name.split(".")
|
|
31
|
+
first_name = split_module_name[0]
|
|
32
|
+
rest_name = split_module_name[1:]
|
|
33
|
+
|
|
34
|
+
full_name = first_name
|
|
35
|
+
file_object, pathname, description = imp.find_module(first_name)
|
|
36
|
+
self.module_info = file_object, pathname, description
|
|
37
|
+
self.load_module(first_name)
|
|
38
|
+
for name in rest_name:
|
|
39
|
+
full_name += "." + name
|
|
40
|
+
path = [pathname]
|
|
41
|
+
file_object, pathname, description = imp.find_module(name, path)
|
|
42
|
+
self.module_info = file_object, pathname, description
|
|
43
|
+
self.load_module(full_name)
|
|
44
|
+
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def load_module(self, module_name):
|
|
48
|
+
"""Load the module."""
|
|
49
|
+
if module_name in sys.modules:
|
|
50
|
+
return sys.modules[module_name]
|
|
51
|
+
|
|
52
|
+
module_path = self.module_info[1]
|
|
53
|
+
file_object, pathname, description = self.module_info
|
|
54
|
+
|
|
55
|
+
# Use regular loader unless in a dir that was registered.
|
|
56
|
+
canonical_module_dir_path = os.path.dirname(os.path.realpath(module_path))
|
|
57
|
+
if canonical_module_dir_path not in self.stripper_fun_to_use:
|
|
58
|
+
try:
|
|
59
|
+
module = imp.load_module(module_name, *self.module_info)
|
|
60
|
+
finally:
|
|
61
|
+
if file_object is not None:
|
|
62
|
+
file_object.close()
|
|
63
|
+
return module
|
|
64
|
+
else:
|
|
65
|
+
stripper_fun_to_use = self.stripper_fun_to_use[canonical_module_dir_path]
|
|
66
|
+
|
|
67
|
+
# Attempt to process the module with strip hints.
|
|
68
|
+
try:
|
|
69
|
+
source = stripper_fun_to_use(module_path)
|
|
70
|
+
# TODO: Really should read the encoding magic comment, if there is one,
|
|
71
|
+
# and encode the string in that encoding.
|
|
72
|
+
if version == 2:
|
|
73
|
+
source = source.encode("utf-8")
|
|
74
|
+
module = imp.new_module(module_name)
|
|
75
|
+
|
|
76
|
+
# =========================================
|
|
77
|
+
# Below is based on example and other text in
|
|
78
|
+
# https://www.python.org/dev/peps/pep-0302/
|
|
79
|
+
mod = sys.modules.setdefault(module_path, module)
|
|
80
|
+
mod.__file__ = "<%s>" % self.__class__.__name__
|
|
81
|
+
mod.__loader__ = self
|
|
82
|
+
|
|
83
|
+
ispkg = self.module_info[0] is None and self.module_info[1] is not None
|
|
84
|
+
if ispkg:
|
|
85
|
+
mod.__path__ = []
|
|
86
|
+
mod.__package__ = module_path
|
|
87
|
+
else:
|
|
88
|
+
mod.__package__ = module_path.rpartition('.')[0]
|
|
89
|
+
# =========================================
|
|
90
|
+
|
|
91
|
+
sys.modules[module_name] = module
|
|
92
|
+
# https://stackoverflow.com/questions/30621772/what-encoding-does-the-exec-function-assume
|
|
93
|
+
exec(source, module.__dict__)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
print("strip_hints error in loading module {0}: {1}."
|
|
96
|
+
.format(module_name, e.__class__.__name__), file=sys.stderr)
|
|
97
|
+
raise # Re-raise instead of fallback to regular import.
|
|
98
|
+
# module = imp.load_module(module_name, *self.module_info)
|
|
99
|
+
finally:
|
|
100
|
+
if file_object is not None:
|
|
101
|
+
file_object.close()
|
|
102
|
+
return module
|
|
103
|
+
|
|
104
|
+
def register_stripper_fun(calling_module_file, stripper_fun, py3_also=False):
|
|
105
|
+
"""The function called from a module `__init__` or from a script file to
|
|
106
|
+
declare that all later imports from that directory should be processed on
|
|
107
|
+
import to strip type hints. This is based on the `realpath` of the
|
|
108
|
+
directory of the module."""
|
|
109
|
+
if version == 3:
|
|
110
|
+
raise ImportError("Wrong `register_stripper_fun` imported for Python 3")
|
|
111
|
+
|
|
112
|
+
global strip_importer_instance
|
|
113
|
+
if not strip_importer_instance:
|
|
114
|
+
strip_importer_instance = StripHintsImporter()
|
|
115
|
+
sys.meta_path.insert(0, strip_importer_instance)
|
|
116
|
+
|
|
117
|
+
canonical_module_dir = os.path.dirname(os.path.realpath(calling_module_file))
|
|
118
|
+
strip_importer_instance.stripper_fun_to_use[canonical_module_dir] = stripper_fun
|
|
119
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
Code to set up import hooks for Python 3 to automatically strip hints from
|
|
5
|
+
modules when they are loaded.
|
|
6
|
+
|
|
7
|
+
The import hook part of the code is based on an example from here:
|
|
8
|
+
https://stackoverflow.com/questions/43571737/how-to-implement-an-import-hook-that-can-modify-the-source-code-on-the-fly-using/43573798#43573798
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import print_function, division, absolute_import
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
import os
|
|
16
|
+
from importlib import invalidate_caches
|
|
17
|
+
from importlib.abc import SourceLoader
|
|
18
|
+
from importlib.machinery import FileFinder
|
|
19
|
+
|
|
20
|
+
version = sys.version_info[0]
|
|
21
|
+
|
|
22
|
+
stripper_funs = {}
|
|
23
|
+
registered = False
|
|
24
|
+
|
|
25
|
+
class StripHintsSourceLoader(SourceLoader):
|
|
26
|
+
def __init__(self, fullname, path):
|
|
27
|
+
self.fullname = fullname
|
|
28
|
+
self.path = path
|
|
29
|
+
|
|
30
|
+
def get_filename(self, fullname):
|
|
31
|
+
return self.path
|
|
32
|
+
|
|
33
|
+
def get_data(self, module_path):
|
|
34
|
+
"""Get the source code and modify it if necessary; `exec_module` is already
|
|
35
|
+
defined."""
|
|
36
|
+
assert not os.path.isdir(module_path) # Assume a file module is passed.
|
|
37
|
+
canonical_module_dir_path = os.path.dirname(os.path.realpath(module_path))
|
|
38
|
+
|
|
39
|
+
if canonical_module_dir_path in stripper_funs:
|
|
40
|
+
stripper_fun_to_use = stripper_funs[canonical_module_dir_path]
|
|
41
|
+
source = stripper_fun_to_use(module_path)
|
|
42
|
+
else:
|
|
43
|
+
with open(module_path) as f:
|
|
44
|
+
source = f.read()
|
|
45
|
+
return source
|
|
46
|
+
|
|
47
|
+
def install(loader_details):
|
|
48
|
+
# Insert the path hook ahead of other path hooks.
|
|
49
|
+
sys.path_hooks.insert(0, FileFinder.path_hook(loader_details))
|
|
50
|
+
# Clear any loaders that might already be in use by the FileFinder.
|
|
51
|
+
sys.path_importer_cache.clear()
|
|
52
|
+
invalidate_caches()
|
|
53
|
+
|
|
54
|
+
def register_stripper_fun(calling_module_file, stripper_fun, py3_also=False):
|
|
55
|
+
"""The function called from a module `__init__` or from a script file to
|
|
56
|
+
declare that all later imports from that directory should be processed on
|
|
57
|
+
import to strip type hints. This is based on the `realpath` of the
|
|
58
|
+
directory of the module."""
|
|
59
|
+
if version != 3:
|
|
60
|
+
raise ImportError("Importing wrong `register_stripper_fun` for Python 2.")
|
|
61
|
+
if not py3_also:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
global registered
|
|
65
|
+
if not registered:
|
|
66
|
+
loader_details = StripHintsSourceLoader, [".py"]
|
|
67
|
+
install(loader_details)
|
|
68
|
+
registered = True
|
|
69
|
+
|
|
70
|
+
canonical_dir_path = os.path.dirname(os.path.realpath(calling_module_file))
|
|
71
|
+
stripper_funs[canonical_dir_path] = stripper_fun
|
|
72
|
+
|