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.
@@ -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
+