Skip to content

Commit e38e2c8

Browse files
committed
Use runpy to run modules with -m
1 parent 6d3180b commit e38e2c8

File tree

3 files changed

+112
-17
lines changed

3 files changed

+112
-17
lines changed

Lib/__importlib_util.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""Utility code for constructing importers, etc."""
2+
from _frozen_importlib import _resolve_name
3+
from _frozen_importlib import _find_spec
4+
5+
import sys
6+
7+
8+
def resolve_name(name, package):
9+
"""Resolve a relative module name to an absolute one."""
10+
if not name.startswith('.'):
11+
return name
12+
elif not package:
13+
raise ValueError(f'no package specified for {repr(name)} '
14+
'(required for relative module names)')
15+
level = 0
16+
for character in name:
17+
if character != '.':
18+
break
19+
level += 1
20+
return _resolve_name(name[level:], package, level)
21+
22+
23+
def _find_spec_from_path(name, path=None):
24+
"""Return the spec for the specified module.
25+
26+
First, sys.modules is checked to see if the module was already imported. If
27+
so, then sys.modules[name].__spec__ is returned. If that happens to be
28+
set to None, then ValueError is raised. If the module is not in
29+
sys.modules, then sys.meta_path is searched for a suitable spec with the
30+
value of 'path' given to the finders. None is returned if no spec could
31+
be found.
32+
33+
Dotted names do not have their parent packages implicitly imported. You will
34+
most likely need to explicitly import all parent packages in the proper
35+
order for a submodule to get the correct spec.
36+
37+
"""
38+
if name not in sys.modules:
39+
return _find_spec(name, path)
40+
else:
41+
module = sys.modules[name]
42+
if module is None:
43+
return None
44+
try:
45+
spec = module.__spec__
46+
except AttributeError:
47+
raise ValueError('{}.__spec__ is not set'.format(name)) from None
48+
else:
49+
if spec is None:
50+
raise ValueError('{}.__spec__ is None'.format(name))
51+
return spec
52+
53+
54+
def find_spec(name, package=None):
55+
"""Return the spec for the specified module.
56+
57+
First, sys.modules is checked to see if the module was already imported. If
58+
so, then sys.modules[name].__spec__ is returned. If that happens to be
59+
set to None, then ValueError is raised. If the module is not in
60+
sys.modules, then sys.meta_path is searched for a suitable spec with the
61+
value of 'path' given to the finders. None is returned if no spec could
62+
be found.
63+
64+
If the name is for submodule (contains a dot), the parent module is
65+
automatically imported.
66+
67+
The name and package arguments work the same as importlib.import_module().
68+
In other words, relative module names (with leading dots) work.
69+
70+
"""
71+
fullname = resolve_name(name, package) if name.startswith('.') else name
72+
if fullname not in sys.modules:
73+
parent_name = fullname.rpartition('.')[0]
74+
if parent_name:
75+
parent = __import__(parent_name, fromlist=['__path__'])
76+
try:
77+
parent_path = parent.__path__
78+
except AttributeError as e:
79+
raise ModuleNotFoundError(
80+
f"__path__ attribute not found on {parent_name!r} "
81+
f"while trying to find {fullname!r}", name=fullname) from e
82+
else:
83+
parent_path = None
84+
return _find_spec(fullname, parent_path)
85+
else:
86+
module = sys.modules[fullname]
87+
if module is None:
88+
return None
89+
try:
90+
spec = module.__spec__
91+
except AttributeError:
92+
raise ValueError('{}.__spec__ is not set'.format(name)) from None
93+
else:
94+
if spec is None:
95+
raise ValueError('{}.__spec__ is None'.format(name))
96+
return spec
97+

Lib/runpy.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111

1212

1313
import sys
14-
import importlib.machinery # importlib first so we can test #15386 via -m
15-
import importlib.util
14+
import __importlib_util
15+
# FIXME replace above with below once we can import importlib
16+
# import importlib.machinery # importlib first so we can test #15386 via -m
17+
# import importlib.util
1618
import types
17-
from pkgutil import read_code, get_importer
19+
# FIXME uncomment line below once we can import pkgutil
20+
# from pkgutil import read_code, get_importer
1821

1922
__all__ = [
2023
"run_module", "run_path",
@@ -125,7 +128,8 @@ def _get_module_details(mod_name, error=ImportError):
125128
warn(RuntimeWarning(msg))
126129

127130
try:
128-
spec = importlib.util.find_spec(mod_name)
131+
# FIXME replace with importlib.util.find_spec() once we can import importlib
132+
spec = __importlib_util.find_spec(mod_name)
129133
except (ImportError, AttributeError, TypeError, ValueError) as ex:
130134
# This hack fixes an impedance mismatch between pkgutil and
131135
# importlib, where the latter raises other errors for cases where

src/main.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ fn create_settings(matches: &ArgMatches) -> PySettings {
204204
let argv = if let Some(script) = matches.values_of("script") {
205205
script.map(ToOwned::to_owned).collect()
206206
} else if let Some(module) = matches.values_of("m") {
207-
std::iter::once("PLACEHOLEDER".to_owned())
207+
std::iter::once("PLACEHOLDER".to_owned())
208208
.chain(module.skip(1).map(ToOwned::to_owned))
209209
.collect()
210210
} else if let Some(cmd) = matches.values_of("c") {
@@ -353,18 +353,12 @@ fn run_command(vm: &VirtualMachine, source: String) -> PyResult<()> {
353353

354354
fn run_module(vm: &VirtualMachine, module: &str) -> PyResult<()> {
355355
debug!("Running module {}", module);
356-
let importlib = vm.import("_frozen_importlib", &vm.ctx.new_tuple(vec![]), 0)?;
357-
let find_spec = vm.get_attribute(importlib, "_find_spec")?;
358-
let spec = vm.invoke(
359-
find_spec,
360-
vec![vm.ctx.new_str(module.to_owned()), vm.get_none()],
361-
)?;
362-
if !vm.is_none(&spec) {
363-
let origin = vm.get_attribute(spec, "origin")?;
364-
let sys_path = vm.get_attribute(vm.sys_module.clone(), "argv")?;
365-
sys_path.set_item(0, origin, vm)?;
366-
}
367-
vm.import(module, &vm.ctx.new_tuple(vec![]), 0)?;
356+
let main_module = vm.ctx.new_module("__main__", vm.ctx.new_dict());
357+
vm.get_attribute(vm.sys_module.clone(), "modules")?
358+
.set_item("__main__", main_module, vm)?;
359+
let runpy = vm.import("runpy", &vm.ctx.new_tuple(vec![]), 0)?;
360+
let run_module_as_main = vm.get_attribute(runpy, "_run_module_as_main")?;
361+
vm.invoke(run_module_as_main, vec![vm.new_str(module.to_owned())])?;
368362
Ok(())
369363
}
370364

0 commit comments

Comments
 (0)