Implement PEP 366

This commit is contained in:
Nick Coghlan 2007-12-03 12:55:17 +00:00
parent f19b951126
commit ef01d822aa
7 changed files with 212 additions and 81 deletions

View File

@ -23,19 +23,20 @@ __all__ = [
def _run_code(code, run_globals, init_globals=None, def _run_code(code, run_globals, init_globals=None,
mod_name=None, mod_fname=None, mod_name=None, mod_fname=None,
mod_loader=None): mod_loader=None, pkg_name=None):
"""Helper for _run_module_code""" """Helper for _run_module_code"""
if init_globals is not None: if init_globals is not None:
run_globals.update(init_globals) run_globals.update(init_globals)
run_globals.update(__name__ = mod_name, run_globals.update(__name__ = mod_name,
__file__ = mod_fname, __file__ = mod_fname,
__loader__ = mod_loader) __loader__ = mod_loader,
__package__ = pkg_name)
exec code in run_globals exec code in run_globals
return run_globals return run_globals
def _run_module_code(code, init_globals=None, def _run_module_code(code, init_globals=None,
mod_name=None, mod_fname=None, mod_name=None, mod_fname=None,
mod_loader=None): mod_loader=None, pkg_name=None):
"""Helper for run_module""" """Helper for run_module"""
# Set up the top level namespace dictionary # Set up the top level namespace dictionary
temp_module = imp.new_module(mod_name) temp_module = imp.new_module(mod_name)
@ -49,7 +50,8 @@ def _run_module_code(code, init_globals=None,
sys.modules[mod_name] = temp_module sys.modules[mod_name] = temp_module
try: try:
_run_code(code, mod_globals, init_globals, _run_code(code, mod_globals, init_globals,
mod_name, mod_fname, mod_loader) mod_name, mod_fname,
mod_loader, pkg_name)
finally: finally:
sys.argv[0] = saved_argv0 sys.argv[0] = saved_argv0
if restore_module: if restore_module:
@ -95,11 +97,12 @@ def _run_module_as_main(mod_name, set_argv0=True):
__loader__ __loader__
""" """
loader, code, fname = _get_module_details(mod_name) loader, code, fname = _get_module_details(mod_name)
pkg_name = mod_name.rpartition('.')[0]
main_globals = sys.modules["__main__"].__dict__ main_globals = sys.modules["__main__"].__dict__
if set_argv0: if set_argv0:
sys.argv[0] = fname sys.argv[0] = fname
return _run_code(code, main_globals, None, return _run_code(code, main_globals, None,
"__main__", fname, loader) "__main__", fname, loader, pkg_name)
def run_module(mod_name, init_globals=None, def run_module(mod_name, init_globals=None,
run_name=None, alter_sys=False): run_name=None, alter_sys=False):
@ -110,13 +113,14 @@ def run_module(mod_name, init_globals=None,
loader, code, fname = _get_module_details(mod_name) loader, code, fname = _get_module_details(mod_name)
if run_name is None: if run_name is None:
run_name = mod_name run_name = mod_name
pkg_name = mod_name.rpartition('.')[0]
if alter_sys: if alter_sys:
return _run_module_code(code, init_globals, run_name, return _run_module_code(code, init_globals, run_name,
fname, loader) fname, loader, pkg_name)
else: else:
# Leave the sys module alone # Leave the sys module alone
return _run_code(code, {}, init_globals, return _run_code(code, {}, init_globals, run_name,
run_name, fname, loader) fname, loader, pkg_name)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -35,15 +35,15 @@ def temp_dir():
finally: finally:
shutil.rmtree(dirname) shutil.rmtree(dirname)
test_source = ("""\ test_source = """\
# Script may be run with optimisation enabled, so don't rely on assert # Script may be run with optimisation enabled, so don't rely on assert
# statements being executed # statements being executed
def assertEqual(lhs, rhs): def assertEqual(lhs, rhs):
if lhs != rhs: if lhs != rhs:
raise AssertionError("%r != %r" % (lhs, rhs)) raise AssertionError('%r != %r' % (lhs, rhs))
def assertIdentical(lhs, rhs): def assertIdentical(lhs, rhs):
if lhs is not rhs: if lhs is not rhs:
raise AssertionError("%r is not %r" % (lhs, rhs)) raise AssertionError('%r is not %r' % (lhs, rhs))
# Check basic code execution # Check basic code execution
result = ['Top level assignment'] result = ['Top level assignment']
def f(): def f():
@ -53,17 +53,18 @@ assertEqual(result, ['Top level assignment', 'Lower level reference'])
# Check population of magic variables # Check population of magic variables
assertEqual(__name__, '__main__') assertEqual(__name__, '__main__')
print '__file__==%r' % __file__ print '__file__==%r' % __file__
print '__package__==%r' % __package__
# Check the sys module # Check the sys module
import sys import sys
assertIdentical(globals(), sys.modules[__name__].__dict__) assertIdentical(globals(), sys.modules[__name__].__dict__)
print 'sys.argv[0]==%r' % sys.argv[0] print 'sys.argv[0]==%r' % sys.argv[0]
""") """
def _make_test_script(script_dir, script_basename): def _make_test_script(script_dir, script_basename, source=test_source):
script_filename = script_basename+os.extsep+"py" script_filename = script_basename+os.extsep+'py'
script_name = os.path.join(script_dir, script_filename) script_name = os.path.join(script_dir, script_filename)
script_file = open(script_name, "w") script_file = open(script_name, 'w')
script_file.write(test_source) script_file.write(source)
script_file.close() script_file.close()
return script_name return script_name
@ -76,71 +77,108 @@ def _compile_test_script(script_name):
return compiled_name return compiled_name
def _make_test_zip(zip_dir, zip_basename, script_name): def _make_test_zip(zip_dir, zip_basename, script_name):
zip_filename = zip_basename+os.extsep+"zip" zip_filename = zip_basename+os.extsep+'zip'
zip_name = os.path.join(zip_dir, zip_filename) zip_name = os.path.join(zip_dir, zip_filename)
zip_file = zipfile.ZipFile(zip_name, 'w') zip_file = zipfile.ZipFile(zip_name, 'w')
zip_file.write(script_name, os.path.basename(script_name)) zip_file.write(script_name, os.path.basename(script_name))
zip_file.close() zip_file.close()
# if verbose: # if verbose:
# zip_file = zipfile.ZipFile(zip_name, 'r') # zip_file = zipfile.ZipFile(zip_name, 'r')
# print "Contents of %r:" % zip_name # print 'Contents of %r:' % zip_name
# zip_file.printdir() # zip_file.printdir()
# zip_file.close() # zip_file.close()
return zip_name return zip_name
def _make_test_pkg(pkg_dir):
os.mkdir(pkg_dir)
_make_test_script(pkg_dir, '__init__', '')
# There's no easy way to pass the script directory in to get
# -m to work (avoiding that is the whole point of making
# directories and zipfiles executable!)
# So we fake it for testing purposes with a custom launch script
launch_source = """\
import sys, os.path, runpy
sys.path[0:0] = os.path.dirname(__file__)
runpy._run_module_as_main(%r)
"""
def _make_launch_script(script_dir, script_basename, module_name):
return _make_test_script(script_dir, script_basename,
launch_source % module_name)
class CmdLineTest(unittest.TestCase): class CmdLineTest(unittest.TestCase):
def _check_script(self, script_name, expected_file, expected_argv0): def _check_script(self, script_name, expected_file,
exit_code, data = _run_python(script_name) expected_argv0, expected_package,
*cmd_line_switches):
run_args = cmd_line_switches + (script_name,)
exit_code, data = _run_python(*run_args)
if verbose: if verbose:
print "Output from test script %r:" % script_name print 'Output from test script %r:' % script_name
print data print data
self.assertEqual(exit_code, 0) self.assertEqual(exit_code, 0)
printed_file = '__file__==%r' % expected_file printed_file = '__file__==%r' % expected_file
printed_argv0 = 'sys.argv[0]==%r' % expected_argv0 printed_argv0 = 'sys.argv[0]==%r' % expected_argv0
printed_package = '__package__==%r' % expected_package
if verbose:
print 'Expected output:'
print printed_file
print printed_package
print printed_argv0
self.assert_(printed_file in data) self.assert_(printed_file in data)
self.assert_(printed_package in data)
self.assert_(printed_argv0 in data) self.assert_(printed_argv0 in data)
def test_basic_script(self): def test_basic_script(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "script") script_name = _make_test_script(script_dir, 'script')
self._check_script(script_name, script_name, script_name) self._check_script(script_name, script_name, script_name, None)
def test_script_compiled(self): def test_script_compiled(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "script") script_name = _make_test_script(script_dir, 'script')
compiled_name = _compile_test_script(script_name) compiled_name = _compile_test_script(script_name)
os.remove(script_name) os.remove(script_name)
self._check_script(compiled_name, compiled_name, compiled_name) self._check_script(compiled_name, compiled_name, compiled_name, None)
def test_directory(self): def test_directory(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "__main__") script_name = _make_test_script(script_dir, '__main__')
self._check_script(script_dir, script_name, script_dir) self._check_script(script_dir, script_name, script_dir, '')
def test_directory_compiled(self): def test_directory_compiled(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "__main__") script_name = _make_test_script(script_dir, '__main__')
compiled_name = _compile_test_script(script_name) compiled_name = _compile_test_script(script_name)
os.remove(script_name) os.remove(script_name)
self._check_script(script_dir, compiled_name, script_dir) self._check_script(script_dir, compiled_name, script_dir, '')
def test_zipfile(self): def test_zipfile(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "__main__") script_name = _make_test_script(script_dir, '__main__')
zip_name = _make_test_zip(script_dir, "test_zip", script_name) zip_name = _make_test_zip(script_dir, 'test_zip', script_name)
self._check_script(zip_name, None, zip_name) self._check_script(zip_name, None, zip_name, '')
def test_zipfile_compiled(self): def test_zipfile_compiled(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, "__main__") script_name = _make_test_script(script_dir, '__main__')
compiled_name = _compile_test_script(script_name) compiled_name = _compile_test_script(script_name)
zip_name = _make_test_zip(script_dir, "test_zip", compiled_name) zip_name = _make_test_zip(script_dir, 'test_zip', compiled_name)
self._check_script(zip_name, None, zip_name) self._check_script(zip_name, None, zip_name, '')
def test_module_in_package(self):
with temp_dir() as script_dir:
pkg_dir = os.path.join(script_dir, 'test_pkg')
_make_test_pkg(pkg_dir)
script_name = _make_test_script(pkg_dir, 'script')
launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script')
self._check_script(launch_name, script_name,
script_name, 'test_pkg')
def test_main(): def test_main():
test.test_support.run_unittest(CmdLineTest) test.test_support.run_unittest(CmdLineTest)
test.test_support.reap_children() test.test_support.reap_children()
if __name__ == "__main__": if __name__ == '__main__':
test_main() test_main()

View File

@ -188,11 +188,13 @@ class Test(unittest.TestCase):
import t5 import t5
self.assertEqual(fixdir(dir(t5)), self.assertEqual(fixdir(dir(t5)),
['__doc__', '__file__', '__name__', ['__doc__', '__file__', '__name__',
'__path__', 'foo', 'string', 't5']) '__package__', '__path__', 'foo', 'string', 't5'])
self.assertEqual(fixdir(dir(t5.foo)), self.assertEqual(fixdir(dir(t5.foo)),
['__doc__', '__file__', '__name__', 'string']) ['__doc__', '__file__', '__name__', '__package__',
'string'])
self.assertEqual(fixdir(dir(t5.string)), self.assertEqual(fixdir(dir(t5.string)),
['__doc__', '__file__', '__name__', 'spam']) ['__doc__', '__file__', '__name__','__package__',
'spam'])
def test_6(self): def test_6(self):
hier = [ hier = [
@ -208,14 +210,14 @@ class Test(unittest.TestCase):
import t6 import t6
self.assertEqual(fixdir(dir(t6)), self.assertEqual(fixdir(dir(t6)),
['__all__', '__doc__', '__file__', ['__all__', '__doc__', '__file__',
'__name__', '__path__']) '__name__', '__package__', '__path__'])
s = """ s = """
import t6 import t6
from t6 import * from t6 import *
self.assertEqual(fixdir(dir(t6)), self.assertEqual(fixdir(dir(t6)),
['__all__', '__doc__', '__file__', ['__all__', '__doc__', '__file__',
'__name__', '__path__', 'eggs', '__name__', '__package__', '__path__',
'ham', 'spam']) 'eggs', 'ham', 'spam'])
self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6'])
""" """
self.run_code(s) self.run_code(s)
@ -241,17 +243,19 @@ class Test(unittest.TestCase):
t7, sub, subsub = None, None, None t7, sub, subsub = None, None, None
import t7 as tas import t7 as tas
self.assertEqual(fixdir(dir(tas)), self.assertEqual(fixdir(dir(tas)),
['__doc__', '__file__', '__name__', '__path__']) ['__doc__', '__file__', '__name__',
'__package__', '__path__'])
self.failIf(t7) self.failIf(t7)
from t7 import sub as subpar from t7 import sub as subpar
self.assertEqual(fixdir(dir(subpar)), self.assertEqual(fixdir(dir(subpar)),
['__doc__', '__file__', '__name__', '__path__']) ['__doc__', '__file__', '__name__',
'__package__', '__path__'])
self.failIf(t7) self.failIf(t7)
self.failIf(sub) self.failIf(sub)
from t7.sub import subsub as subsubsub from t7.sub import subsub as subsubsub
self.assertEqual(fixdir(dir(subsubsub)), self.assertEqual(fixdir(dir(subsubsub)),
['__doc__', '__file__', '__name__', '__path__', ['__doc__', '__file__', '__name__',
'spam']) '__package__', '__path__', 'spam'])
self.failIf(t7) self.failIf(t7)
self.failIf(sub) self.failIf(sub)
self.failIf(subsub) self.failIf(subsub)

View File

@ -5,7 +5,12 @@ import os.path
import sys import sys
import tempfile import tempfile
from test.test_support import verbose, run_unittest, forget from test.test_support import verbose, run_unittest, forget
from runpy import _run_code, _run_module_code, _run_module_as_main, run_module from runpy import _run_code, _run_module_code, run_module
# Note: This module can't safely test _run_module_as_main as it
# runs its tests in the current process, which would mess with the
# real __main__ module (usually test.regrtest)
# See test_cmd_line_script for a test that executes that code path
# Set up the test code and expected results # Set up the test code and expected results
@ -36,6 +41,7 @@ class RunModuleCodeTest(unittest.TestCase):
self.failUnless(d["__name__"] is None) self.failUnless(d["__name__"] is None)
self.failUnless(d["__file__"] is None) self.failUnless(d["__file__"] is None)
self.failUnless(d["__loader__"] is None) self.failUnless(d["__loader__"] is None)
self.failUnless(d["__package__"] is None)
self.failUnless(d["run_argv0"] is saved_argv0) self.failUnless(d["run_argv0"] is saved_argv0)
self.failUnless("run_name" not in d) self.failUnless("run_name" not in d)
self.failUnless(sys.argv[0] is saved_argv0) self.failUnless(sys.argv[0] is saved_argv0)
@ -45,13 +51,15 @@ class RunModuleCodeTest(unittest.TestCase):
name = "<Nonsense>" name = "<Nonsense>"
file = "Some other nonsense" file = "Some other nonsense"
loader = "Now you're just being silly" loader = "Now you're just being silly"
package = '' # Treat as a top level module
d1 = dict(initial=initial) d1 = dict(initial=initial)
saved_argv0 = sys.argv[0] saved_argv0 = sys.argv[0]
d2 = _run_module_code(self.test_source, d2 = _run_module_code(self.test_source,
d1, d1,
name, name,
file, file,
loader) loader,
package)
self.failUnless("result" not in d1) self.failUnless("result" not in d1)
self.failUnless(d2["initial"] is initial) self.failUnless(d2["initial"] is initial)
self.failUnless(d2["result"] == self.expected_result) self.failUnless(d2["result"] == self.expected_result)
@ -62,6 +70,7 @@ class RunModuleCodeTest(unittest.TestCase):
self.failUnless(d2["__file__"] is file) self.failUnless(d2["__file__"] is file)
self.failUnless(d2["run_argv0"] is file) self.failUnless(d2["run_argv0"] is file)
self.failUnless(d2["__loader__"] is loader) self.failUnless(d2["__loader__"] is loader)
self.failUnless(d2["__package__"] is package)
self.failUnless(sys.argv[0] is saved_argv0) self.failUnless(sys.argv[0] is saved_argv0)
self.failUnless(name not in sys.modules) self.failUnless(name not in sys.modules)
@ -164,7 +173,7 @@ class RunModuleTest(unittest.TestCase):
self._del_pkg(pkg_dir, depth, mod_name) self._del_pkg(pkg_dir, depth, mod_name)
if verbose: print "Module executed successfully" if verbose: print "Module executed successfully"
def _add_relative_modules(self, base_dir, depth): def _add_relative_modules(self, base_dir, source, depth):
if depth <= 1: if depth <= 1:
raise ValueError("Relative module test needs depth > 1") raise ValueError("Relative module test needs depth > 1")
pkg_name = "__runpy_pkg__" pkg_name = "__runpy_pkg__"
@ -190,7 +199,7 @@ class RunModuleTest(unittest.TestCase):
if verbose: print " Added nephew module:", nephew_fname if verbose: print " Added nephew module:", nephew_fname
def _check_relative_imports(self, depth, run_name=None): def _check_relative_imports(self, depth, run_name=None):
contents = """\ contents = r"""\
from __future__ import absolute_import from __future__ import absolute_import
from . import sibling from . import sibling
from ..uncle.cousin import nephew from ..uncle.cousin import nephew
@ -198,16 +207,21 @@ from ..uncle.cousin import nephew
pkg_dir, mod_fname, mod_name = ( pkg_dir, mod_fname, mod_name = (
self._make_pkg(contents, depth)) self._make_pkg(contents, depth))
try: try:
self._add_relative_modules(pkg_dir, depth) self._add_relative_modules(pkg_dir, contents, depth)
pkg_name = mod_name.rpartition('.')[0]
if verbose: print "Running from source:", mod_name if verbose: print "Running from source:", mod_name
d1 = run_module(mod_name) # Read from source d1 = run_module(mod_name, run_name=run_name) # Read from source
self.failUnless("__package__" in d1)
self.failUnless(d1["__package__"] == pkg_name)
self.failUnless("sibling" in d1) self.failUnless("sibling" in d1)
self.failUnless("nephew" in d1) self.failUnless("nephew" in d1)
del d1 # Ensure __loader__ entry doesn't keep file open del d1 # Ensure __loader__ entry doesn't keep file open
__import__(mod_name) __import__(mod_name)
os.remove(mod_fname) os.remove(mod_fname)
if verbose: print "Running from compiled:", mod_name if verbose: print "Running from compiled:", mod_name
d2 = run_module(mod_name) # Read from bytecode d2 = run_module(mod_name, run_name=run_name) # Read from bytecode
self.failUnless("__package__" in d2)
self.failUnless(d2["__package__"] == pkg_name)
self.failUnless("sibling" in d2) self.failUnless("sibling" in d2)
self.failUnless("nephew" in d2) self.failUnless("nephew" in d2)
del d2 # Ensure __loader__ entry doesn't keep file open del d2 # Ensure __loader__ entry doesn't keep file open
@ -225,6 +239,11 @@ from ..uncle.cousin import nephew
if verbose: print "Testing relative imports at depth:", depth if verbose: print "Testing relative imports at depth:", depth
self._check_relative_imports(depth) self._check_relative_imports(depth)
def test_main_relative_import(self):
for depth in range(2, 5):
if verbose: print "Testing main relative imports at depth:", depth
self._check_relative_imports(depth, "__main__")
def test_main(): def test_main():
run_unittest(RunModuleCodeTest) run_unittest(RunModuleCodeTest)

View File

@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
Core and builtins Core and builtins
----------------- -----------------
- PEP 366: Allow explicit relative imports when executing modules
inside packages with the -m switch via a new module level
__package__ attribute.
- Issue #1534: Added ``PyFloat_GetMax()``, ``PyFloat_GetMin()`` and - Issue #1534: Added ``PyFloat_GetMax()``, ``PyFloat_GetMin()`` and
``PyFloat_GetInfo()`` to the float API. ``PyFloat_GetInfo()`` to the float API.

View File

@ -30,6 +30,8 @@ PyModule_New(const char *name)
goto fail; goto fail;
if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0) if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0)
goto fail; goto fail;
if (PyDict_SetItemString(m->md_dict, "__package__", Py_None) != 0)
goto fail;
Py_DECREF(nameobj); Py_DECREF(nameobj);
PyObject_GC_Track(m); PyObject_GC_Track(m);
return (PyObject *)m; return (PyObject *)m;

View File

@ -2106,7 +2106,8 @@ get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
{ {
static PyObject *namestr = NULL; static PyObject *namestr = NULL;
static PyObject *pathstr = NULL; static PyObject *pathstr = NULL;
PyObject *modname, *modpath, *modules, *parent; static PyObject *pkgstr = NULL;
PyObject *pkgname, *modname, *modpath, *modules, *parent;
if (globals == NULL || !PyDict_Check(globals) || !level) if (globals == NULL || !PyDict_Check(globals) || !level)
return Py_None; return Py_None;
@ -2121,34 +2122,82 @@ get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
if (pathstr == NULL) if (pathstr == NULL)
return NULL; return NULL;
} }
if (pkgstr == NULL) {
pkgstr = PyString_InternFromString("__package__");
if (pkgstr == NULL)
return NULL;
}
*buf = '\0'; *buf = '\0';
*p_buflen = 0; *p_buflen = 0;
pkgname = PyDict_GetItem(globals, pkgstr);
if ((pkgname != NULL) && (pkgname != Py_None)) {
/* __package__ is set, so use it */
Py_ssize_t len;
if (!PyString_Check(pkgname)) {
PyErr_SetString(PyExc_ValueError,
"__package__ set to non-string");
return NULL;
}
len = PyString_GET_SIZE(pkgname);
if (len == 0) {
if (level > 0) {
PyErr_SetString(PyExc_ValueError,
"Attempted relative import in non-package");
return NULL;
}
return Py_None;
}
if (len > MAXPATHLEN) {
PyErr_SetString(PyExc_ValueError,
"Package name too long");
return NULL;
}
strcpy(buf, PyString_AS_STRING(pkgname));
} else {
/* __package__ not set, so figure it out and set it */
modname = PyDict_GetItem(globals, namestr); modname = PyDict_GetItem(globals, namestr);
if (modname == NULL || !PyString_Check(modname)) if (modname == NULL || !PyString_Check(modname))
return Py_None; return Py_None;
modpath = PyDict_GetItem(globals, pathstr); modpath = PyDict_GetItem(globals, pathstr);
if (modpath != NULL) { if (modpath != NULL) {
/* __path__ is set, so modname is already the package name */
Py_ssize_t len = PyString_GET_SIZE(modname); Py_ssize_t len = PyString_GET_SIZE(modname);
int error;
if (len > MAXPATHLEN) { if (len > MAXPATHLEN) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Module name too long"); "Module name too long");
return NULL; return NULL;
} }
strcpy(buf, PyString_AS_STRING(modname)); strcpy(buf, PyString_AS_STRING(modname));
error = PyDict_SetItem(globals, pkgstr, modname);
if (error) {
PyErr_SetString(PyExc_ValueError,
"Could not set __package__");
return NULL;
} }
else { } else {
/* Normal module, so work out the package name if any */
char *start = PyString_AS_STRING(modname); char *start = PyString_AS_STRING(modname);
char *lastdot = strrchr(start, '.'); char *lastdot = strrchr(start, '.');
size_t len; size_t len;
int error;
if (lastdot == NULL && level > 0) { if (lastdot == NULL && level > 0) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Attempted relative import in non-package"); "Attempted relative import in non-package");
return NULL; return NULL;
} }
if (lastdot == NULL) if (lastdot == NULL) {
error = PyDict_SetItem(globals, pkgstr, Py_None);
if (error) {
PyErr_SetString(PyExc_ValueError,
"Could not set __package__");
return NULL;
}
return Py_None; return Py_None;
}
len = lastdot - start; len = lastdot - start;
if (len >= MAXPATHLEN) { if (len >= MAXPATHLEN) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
@ -2157,8 +2206,19 @@ get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
} }
strncpy(buf, start, len); strncpy(buf, start, len);
buf[len] = '\0'; buf[len] = '\0';
pkgname = PyString_FromString(buf);
if (pkgname == NULL) {
return NULL;
}
error = PyDict_SetItem(globals, pkgstr, pkgname);
Py_DECREF(pkgname);
if (error) {
PyErr_SetString(PyExc_ValueError,
"Could not set __package__");
return NULL;
}
}
} }
while (--level > 0) { while (--level > 0) {
char *dot = strrchr(buf, '.'); char *dot = strrchr(buf, '.');
if (dot == NULL) { if (dot == NULL) {