-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy path__main__.py
More file actions
132 lines (92 loc) · 4.04 KB
/
Copy path__main__.py
File metadata and controls
132 lines (92 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Copyright (C) 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=invalid-name
"""Enables use of Python Fire as a "main" function (i.e. "python -m fire").
This allows using Fire with third-party libraries without modifying their code.
"""
import importlib
from importlib import util
import os
import sys
import fire
cli_string = """usage: python -m fire [module] [arg] ..."
Python Fire is a library for creating CLIs from absolutely any Python
object or program. To run Python Fire from the command line on an
existing Python file, it can be invoked with "python -m fire [module]"
and passed a Python module using module notation:
"python -m fire packageA.packageB.module"
or with a file path:
"python -m fire packageA/packageB/module.py" """
def import_from_file_path(path):
"""Performs a module import given the filename.
Args:
path (str): the path to the file to be imported.
Raises:
IOError: if the given file does not exist or importlib fails to load it.
Returns:
Tuple[ModuleType, str]: returns the imported module and the module name,
usually extracted from the path itself. If the file is __main__.py, the
package name (parent directory) is used instead.
"""
if not os.path.exists(path):
raise OSError('Given file path does not exist.')
module_name = os.path.basename(path)
# If the file is __main__.py, use the parent directory name as the module name
# This fixes the issue where "python -m mypackage" shows "__main__.py" in usage
if module_name == '__main__.py':
module_name = os.path.basename(os.path.dirname(path))
spec = util.spec_from_file_location(module_name, path)
if spec is None or spec.loader is None:
raise OSError('Unable to load module from specified path.')
module = util.module_from_spec(spec) # pylint: disable=no-member
spec.loader.exec_module(module)
return module, module_name
def import_from_module_name(module_name):
"""Imports a module and returns it and its name."""
module = importlib.import_module(module_name)
return module, module_name
def import_module(module_or_filename):
"""Imports a given module or filename.
If the module_or_filename exists in the file system and ends with .py, we
attempt to import it. If that import fails, try to import it as a module.
Args:
module_or_filename (str): string name of path or module.
Raises:
ValueError: if the given file is invalid.
IOError: if the file or module can not be found or imported.
Returns:
Tuple[ModuleType, str]: returns the imported module and the module name,
usually extracted from the path itself.
"""
if os.path.exists(module_or_filename):
# importlib.util.spec_from_file_location requires .py
if not module_or_filename.endswith('.py'):
try: # try as module instead
return import_from_module_name(module_or_filename)
except ImportError:
raise ValueError('Fire can only be called on .py files.')
return import_from_file_path(module_or_filename)
if os.path.sep in module_or_filename: # Use / to detect if it was a filename.
raise OSError('Fire was passed a filename which could not be found.')
return import_from_module_name(module_or_filename) # Assume it's a module.
def main(args):
"""Entrypoint for fire when invoked as a module with python -m fire."""
if len(args) < 2:
print(cli_string)
sys.exit(1)
module_or_filename = args[1]
module, module_name = import_module(module_or_filename)
fire.Fire(module, name=module_name, command=args[2:])
if __name__ == '__main__':
main(sys.argv)