-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy path__main__.py
143 lines (100 loc) · 4.39 KB
/
__main__.py
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
133
134
135
136
137
138
139
140
141
142
143
# 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.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import importlib
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 not os.path.exists(path):
raise IOError('Given file path does not exist.')
module_name = os.path.basename(path)
if sys.version_info.major == 3 and sys.version_info.minor < 5:
loader = importlib.machinery.SourceFileLoader( # pylint: disable=no-member
fullname=module_name,
path=path,
)
module = loader.load_module(module_name) # pylint: disable=deprecated-method
elif sys.version_info.major == 3:
from importlib import util # pylint: disable=g-import-not-at-top,import-outside-toplevel,no-name-in-module
spec = util.spec_from_file_location(module_name, path)
if spec is None:
raise IOError('Unable to load module from specified path.')
module = util.module_from_spec(spec) # pylint: disable=no-member
spec.loader.exec_module(module) # pytype: disable=attribute-error
else:
import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel,deprecated-module,import-error
module = imp.load_source(module_name, path)
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 IOError('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)