Apart from the node classes, the :mod:`ast` module defines these utility functions
and classes for traversing abstract syntax trees:
-.. function:: parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None, optimize=-1)
+.. function:: parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None, optimize=-1, module=None)
Parse the source into an AST node. Equivalent to ``compile(source,
- filename, mode, flags=FLAGS_VALUE, optimize=optimize)``,
+ filename, mode, flags=FLAGS_VALUE, optimize=optimize, module=module)``,
where ``FLAGS_VALUE`` is ``ast.PyCF_ONLY_AST`` if ``optimize <= 0``
and ``ast.PyCF_OPTIMIZED_AST`` otherwise.
The minimum supported version for ``feature_version`` is now ``(3, 7)``.
The ``optimize`` argument was added.
+ .. versionadded:: next
+ Added the *module* parameter.
+
.. function:: unparse(ast_obj)
:func:`property`.
-.. function:: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
+.. function:: compile(source, filename, mode, flags=0, \
+ dont_inherit=False, optimize=-1, \
+ *, module=None)
Compile the *source* into a code or AST object. Code objects can be executed
by :func:`exec` or :func:`eval`. *source* can either be a normal string, a
``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
or ``2`` (docstrings are removed too).
+ The optional argument *module* specifies the module name.
+ It is needed to unambiguous :ref:`filter <warning-filter>` syntax warnings
+ by module name.
+
This function raises :exc:`SyntaxError` if the compiled source is invalid,
and :exc:`ValueError` if the source contains null bytes.
``ast.PyCF_ALLOW_TOP_LEVEL_AWAIT`` can now be passed in flags to enable
support for top-level ``await``, ``async for``, and ``async with``.
+ .. versionadded:: next
+ Added the *module* parameter.
+
.. class:: complex(number=0, /)
complex(string, /)
.. versionchanged:: 3.4
Raises :exc:`ImportError` instead of :exc:`NotImplementedError`.
- .. staticmethod:: source_to_code(data, path='<string>')
+ .. staticmethod:: source_to_code(data, path='<string>', fullname=None)
Create a code object from Python source.
With the subsequent code object one can execute it in a module by
running ``exec(code, module.__dict__)``.
+ The optional argument *fullname* specifies the module name.
+ It is needed to unambiguous :ref:`filter <warning-filter>` syntax
+ warnings by module name.
+
.. versionadded:: 3.4
.. versionchanged:: 3.5
Made the method static.
+ .. versionadded:: next
+ Added the *fullname* parameter.
+
+
.. method:: exec_module(module)
Implementation of :meth:`Loader.exec_module`.
Generating Symbol Tables
------------------------
-.. function:: symtable(code, filename, compile_type)
+.. function:: symtable(code, filename, compile_type, *, module=None)
Return the toplevel :class:`SymbolTable` for the Python source *code*.
*filename* is the name of the file containing the code. *compile_type* is
like the *mode* argument to :func:`compile`.
+ The optional argument *module* specifies the module name.
+ It is needed to unambiguous :ref:`filter <warning-filter>` syntax warnings
+ by module name.
+
+ .. versionadded:: next
+ Added the *module* parameter.
Examining Symbol Tables
not only integers or floats, although this does not improve precision.
(Contributed by Serhiy Storchaka in :gh:`67795`.)
+* Many functions related to compiling or parsing Python code, such as
+ :func:`compile`, :func:`ast.parse`, :func:`symtable.symtable`,
+ and :func:`importlib.abc.InspectLoader.source_to_code`, now allow to pass
+ the module name. It is needed to unambiguous :ref:`filter <warning-filter>`
+ syntax warnings by module name.
+ (Contributed by Serhiy Storchaka in :gh:`135801`.)
+
New modules
===========
PyObject *filename,
PyCompilerFlags *flags,
int optimize,
- struct _arena *arena);
+ struct _arena *arena,
+ PyObject *module);
/* AST preprocessing */
extern int _PyCompile_AstPreprocess(
PyCompilerFlags *flags,
int optimize,
struct _arena *arena,
- int syntax_check_only);
+ int syntax_check_only,
+ PyObject *module);
extern int _PyAST_Preprocess(
struct _mod *,
int optimize,
int ff_features,
int syntax_check_only,
- int enable_warnings);
+ int enable_warnings,
+ PyObject *module);
typedef struct {
PyObject* filename,
int mode,
PyCompilerFlags *flags,
- PyArena *arena);
+ PyArena *arena,
+ PyObject *module);
extern struct _mod* _PyParser_ASTFromFile(
FILE *fp,
extern PyObject* _PyErr_NoMemory(PyThreadState *tstate);
extern int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset,
- int end_lineno, int end_col_offset);
+ int end_lineno, int end_col_offset,
+ PyObject *module);
extern void _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset,
int end_lineno, int end_col_offset);
PyCompilerFlags *cf,
PyObject **cmd_copy);
+extern PyObject * _Py_CompileStringObjectWithModule(
+ const char *str,
+ PyObject *filename, int start,
+ PyCompilerFlags *flags, int optimize,
+ PyObject *module);
+
/* Stack size, in "pointers". This must be large enough, so
* no two calls to check recursion depth are more than this far
const char *str,
PyObject *filename,
int start,
- PyCompilerFlags *flags);
+ PyCompilerFlags *flags,
+ PyObject *module);
int _PyFuture_FromAST(
struct _mod * mod,
def parse(source, filename='<unknown>', mode='exec', *,
- type_comments=False, feature_version=None, optimize=-1):
+ type_comments=False, feature_version=None, optimize=-1, module=None):
"""
Parse the source into an AST node.
Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
feature_version = minor
# Else it should be an int giving the minor version for 3.x.
return compile(source, filename, mode, flags,
- _feature_version=feature_version, optimize=optimize)
+ _feature_version=feature_version, optimize=optimize,
+ module=module)
def literal_eval(node_or_string):
name=fullname) from exc
return decode_source(source_bytes)
- def source_to_code(self, data, path, *, _optimize=-1):
+ def source_to_code(self, data, path, fullname=None, *, _optimize=-1):
"""Return the code object compiled from source.
The 'data' argument can be any object type that compile() supports.
"""
return _bootstrap._call_with_frames_removed(compile, data, path, 'exec',
- dont_inherit=True, optimize=_optimize)
+ dont_inherit=True, optimize=_optimize,
+ module=fullname)
def get_code(self, fullname):
"""Concrete implementation of InspectLoader.get_code.
source_path=source_path)
if source_bytes is None:
source_bytes = self.get_data(source_path)
- code_object = self.source_to_code(source_bytes, source_path)
+ code_object = self.source_to_code(source_bytes, source_path, fullname)
_bootstrap._verbose_message('code object from {}', source_path)
if (not sys.dont_write_bytecode and bytecode_path is not None and
source_mtime is not None):
return ''
def get_code(self, fullname):
- return compile('', '<string>', 'exec', dont_inherit=True)
+ return compile('', '<string>', 'exec', dont_inherit=True, module=fullname)
def create_module(self, spec):
"""Use default semantics for module creation."""
source = self.get_source(fullname)
if source is None:
return None
- return self.source_to_code(source)
+ return self.source_to_code(source, '<string>', fullname)
@abc.abstractmethod
def get_source(self, fullname):
raise ImportError
@staticmethod
- def source_to_code(data, path='<string>'):
+ def source_to_code(data, path='<string>', fullname=None):
"""Compile 'data' into a code object.
The 'data' argument can be anything that compile() can handle. The'path'
argument should be where the data was retrieved (when applicable)."""
- return compile(data, path, 'exec', dont_inherit=True)
+ return compile(data, path, 'exec', dont_inherit=True, module=fullname)
exec_module = _bootstrap_external._LoaderBasics.exec_module
load_module = _bootstrap_external._LoaderBasics.load_module
try:
path = self.get_filename(fullname)
except ImportError:
- return self.source_to_code(source)
- else:
- return self.source_to_code(source, path)
+ path = '<string>'
+ return self.source_to_code(source, path, fullname)
_register(
ExecutionLoader,
self.msgout(2, "load_module ->", m)
return m
if type == _PY_SOURCE:
- co = compile(fp.read(), pathname, 'exec')
+ co = compile(fp.read(), pathname, 'exec', module=fqname)
elif type == _PY_COMPILED:
try:
data = fp.read()
try:
# Compile and execute the script
- code = compile(source_code, script_path, 'exec')
+ code = compile(source_code, script_path, 'exec', module='__main__')
exec(code, {'__name__': '__main__', '__file__': script_path})
except SyntaxError as e:
raise TargetError(f"Syntax error in script {script_path}: {e}") from e
progname = args[0]
sys.path.insert(0, os.path.dirname(progname))
with io.open_code(progname) as fp:
- code = compile(fp.read(), progname, 'exec')
+ code = compile(fp.read(), progname, 'exec', module='__main__')
spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
origin=progname)
module = importlib.util.module_from_spec(spec)
sys.modules[main_name] = saved_main
-def _get_code_from_file(fname):
+def _get_code_from_file(fname, module):
# Check for a compiled file first
from pkgutil import read_code
code_path = os.path.abspath(fname)
if code is None:
# That didn't work, so try it as normal source code
with io.open_code(code_path) as f:
- code = compile(f.read(), fname, 'exec')
+ code = compile(f.read(), fname, 'exec', module=module)
return code
def run_path(path_name, init_globals=None, run_name=None):
if isinstance(importer, type(None)):
# Not a valid sys.path entry, so run the code directly
# execfile() doesn't help as we want to allow compiled files
- code = _get_code_from_file(path_name)
+ code = _get_code_from_file(path_name, run_name)
return _run_module_code(code, init_globals, run_name,
pkg_name=pkg_name, script_name=path_name)
else:
__all__ = ["symtable", "SymbolTableType", "SymbolTable", "Class", "Function", "Symbol"]
-def symtable(code, filename, compile_type):
+def symtable(code, filename, compile_type, *, module=None):
""" Return the toplevel *SymbolTable* for the source code.
*filename* is the name of the file with the code
and *compile_type* is the *compile()* mode argument.
"""
- top = _symtable.symtable(code, filename, compile_type)
+ top = _symtable.symtable(code, filename, compile_type, module=module)
return _newSymbolTable(top, filename)
class SymbolTableFactory:
self.assertEqual(wm.filename, '<unknown>')
self.assertIs(wm.category, SyntaxWarning)
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'package\.module\z')
+ warnings.filterwarnings('error', module=r'<unknown>')
+ ast.parse(source, filename, module='package.module')
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10])
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
class CopyTests(unittest.TestCase):
"""Test copying and pickling AST nodes."""
with warnings.catch_warnings(record=True) as wlog:
warnings.simplefilter('error')
- warnings.filterwarnings('always', module=r'<string>\z')
+ warnings.filterwarnings('always', module=r'package.module\z')
+ warnings.filterwarnings('error', module=r'<string>')
exec(source, {'__name__': 'package.module', '__file__': filename})
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
for wm in wlog:
filename = support.findfile('test_import/data/syntax_warnings.py')
rc, out, err = assert_python_ok(
'-Werror',
- '-Walways:::test.test_import.data.syntax_warnings',
+ '-Walways:::__main__',
+ '-Werror:::test.test_import.data.syntax_warnings',
+ '-Werror:::syntax_warnings',
filename)
self.assertEqual(err.count(b': SyntaxWarning: '), 6)
- rc, out, err = assert_python_ok(
- '-Werror',
- '-Walways:::syntax_warnings',
- filename)
- self.assertEqual(err.count(b': SyntaxWarning: '), 6)
+ def test_zipfile_run_filter_syntax_warnings_by_module(self):
+ filename = support.findfile('test_import/data/syntax_warnings.py')
+ with open(filename, 'rb') as f:
+ source = f.read()
+ with os_helper.temp_dir() as script_dir:
+ zip_name, _ = make_zip_pkg(
+ script_dir, 'test_zip', 'test_pkg', '__main__', source)
+ rc, out, err = assert_python_ok(
+ '-Werror',
+ '-Walways:::__main__',
+ '-Werror:::test_pkg.__main__',
+ os.path.join(zip_name, 'test_pkg')
+ )
+ self.assertEqual(err.count(b': SyntaxWarning: '), 12)
def tearDownModule():
self.assertEqual(wm.filename, filename)
self.assertIs(wm.category, SyntaxWarning)
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'package\.module\z')
+ warnings.filterwarnings('error', module=module_re)
+ compile(source, filename, 'exec', module='package.module')
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
@support.subTests('src', [
textwrap.dedent("""
def f():
warnings.catch_warnings(record=True) as wlog):
warnings.simplefilter('error')
warnings.filterwarnings('always', module=module_re)
- import test.test_import.data.syntax_warnings
- self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
- filename = test.test_import.data.syntax_warnings.__file__
- for wm in wlog:
- self.assertEqual(wm.filename, filename)
- self.assertIs(wm.category, SyntaxWarning)
-
- module_re = r'syntax_warnings\z'
- unload('test.test_import.data.syntax_warnings')
- with (os_helper.temp_dir() as tmpdir,
- temporary_pycache_prefix(tmpdir),
- warnings.catch_warnings(record=True) as wlog):
- warnings.simplefilter('error')
- warnings.filterwarnings('always', module=module_re)
+ warnings.filterwarnings('error', module='syntax_warnings')
import test.test_import.data.syntax_warnings
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
filename = test.test_import.data.syntax_warnings.__file__
requires_subprocess,
verbose,
)
+from test import support
from test.support.import_helper import forget, make_legacy_pyc, unload
from test.support.os_helper import create_empty_file, temp_dir, FakePath
from test.support.script_helper import make_script, make_zip_script
+from test.test_importlib.util import temporary_pycache_prefix
import runpy
result = run_path(filename)
self.assertEqual(result['s'], "non-ASCII: h\xe9")
+ def test_run_module_filter_syntax_warnings_by_module(self):
+ module_re = r'test\.test_import\.data\.syntax_warnings\z'
+ with (temp_dir() as tmpdir,
+ temporary_pycache_prefix(tmpdir),
+ warnings.catch_warnings(record=True) as wlog):
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=module_re)
+ warnings.filterwarnings('error', module='syntax_warnings')
+ ns = run_module('test.test_import.data.syntax_warnings')
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
+ filename = ns['__file__']
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
+ def test_run_path_filter_syntax_warnings_by_module(self):
+ filename = support.findfile('test_import/data/syntax_warnings.py')
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'<run_path>\z')
+ warnings.filterwarnings('error', module='test')
+ warnings.filterwarnings('error', module='syntax_warnings')
+ warnings.filterwarnings('error',
+ module=r'test\.test_import\.data\.syntax_warnings')
+ run_path(filename)
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'package\.script\z')
+ warnings.filterwarnings('error', module='<run_path>')
+ warnings.filterwarnings('error', module='test')
+ warnings.filterwarnings('error', module='syntax_warnings')
+ warnings.filterwarnings('error',
+ module=r'test\.test_import\.data\.syntax_warnings')
+ run_path(filename, run_name='package.script')
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
+
@force_not_colorized_test_class
class TestExit(unittest.TestCase):
self.assertEqual(wm.filename, filename)
self.assertIs(wm.category, SyntaxWarning)
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'package\.module\z')
+ warnings.filterwarnings('error', module=module_re)
+ symtable.symtable(source, filename, 'exec', module='package.module')
+ self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10])
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
class ComprehensionTests(unittest.TestCase):
def get_identifiers_recursive(self, st, res):
import inspect
import linecache
import unittest
+import warnings
+from test import support
from test.support import os_helper
from test.support.script_helper import (spawn_python, kill_python, assert_python_ok,
make_script, make_zip_script)
+from test.support import import_helper
verbose = test.support.verbose
# bdb/pdb applies normcase to its filename before displaying
self.assertIn(os.path.normcase(run_name.encode('utf-8')), data)
+ def test_import_filter_syntax_warnings_by_module(self):
+ filename = support.findfile('test_import/data/syntax_warnings.py')
+ with (os_helper.temp_dir() as tmpdir,
+ import_helper.DirsOnSysPath()):
+ zip_name, _ = make_zip_script(tmpdir, "test_zip",
+ filename, 'test_pkg/test_mod.py')
+ sys.path.insert(0, zip_name)
+ import_helper.unload('test_pkg.test_mod')
+ with warnings.catch_warnings(record=True) as wlog:
+ warnings.simplefilter('error')
+ warnings.filterwarnings('always', module=r'test_pkg\.test_mod\z')
+ warnings.filterwarnings('error', module='test_mod')
+ import test_pkg.test_mod
+ self.assertEqual(sorted(wm.lineno for wm in wlog),
+ sorted([4, 7, 10, 13, 14, 21]*2))
+ filename = test_pkg.test_mod.__file__
+ for wm in wlog:
+ self.assertEqual(wm.filename, filename)
+ self.assertIs(wm.category, SyntaxWarning)
+
def tearDownModule():
test.support.reap_children()
# Given a string buffer containing Python source code, compile it
# and return a code object.
-def _compile_source(pathname, source):
+def _compile_source(pathname, source, module):
source = _normalize_line_endings(source)
- return compile(source, pathname, 'exec', dont_inherit=True)
+ return compile(source, pathname, 'exec', dont_inherit=True, module=module)
# Convert the date/time values found in the Zip archive to a value
# that's compatible with the time stamp stored in .pyc files.
except ImportError as exc:
import_error = exc
else:
- code = _compile_source(modpath, data)
+ code = _compile_source(modpath, data, fullname)
if code is None:
# bad magic number or non-matching mtime
# in byte code, try next
--- /dev/null
+Many functions related to compiling or parsing Python code, such as
+:func:`compile`, :func:`ast.parse`, :func:`symtable.symtable`, and
+:func:`importlib.abc.InspectLoader.source_to_code` now allow to specify
+the module name.
+It is needed to unambiguous :ref:`filter <warning-filter>` syntax warnings
+by module name.
preserve
[clinic start generated code]*/
-#include "pycore_modsupport.h" // _PyArg_CheckPositional()
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(_symtable_symtable__doc__,
-"symtable($module, source, filename, startstr, /)\n"
+"symtable($module, source, filename, startstr, /, *, module=None)\n"
"--\n"
"\n"
"Return symbol and scope dictionaries used internally by compiler.");
#define _SYMTABLE_SYMTABLE_METHODDEF \
- {"symtable", _PyCFunction_CAST(_symtable_symtable), METH_FASTCALL, _symtable_symtable__doc__},
+ {"symtable", _PyCFunction_CAST(_symtable_symtable), METH_FASTCALL|METH_KEYWORDS, _symtable_symtable__doc__},
static PyObject *
_symtable_symtable_impl(PyObject *module, PyObject *source,
- PyObject *filename, const char *startstr);
+ PyObject *filename, const char *startstr,
+ PyObject *modname);
static PyObject *
-_symtable_symtable(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+_symtable_symtable(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(module), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"", "", "", "module", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "symtable",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[4];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3;
PyObject *source;
PyObject *filename = NULL;
const char *startstr;
+ PyObject *modname = Py_None;
- if (!_PyArg_CheckPositional("symtable", nargs, 3, 3)) {
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+ /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!args) {
goto exit;
}
source = args[0];
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
- return_value = _symtable_symtable_impl(module, source, filename, startstr);
+ if (!noptargs) {
+ goto skip_optional_kwonly;
+ }
+ modname = args[3];
+skip_optional_kwonly:
+ return_value = _symtable_symtable_impl(module, source, filename, startstr, modname);
exit:
/* Cleanup for filename */
return return_value;
}
-/*[clinic end generated code: output=7a8545d9a1efe837 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0137be60c487c841 input=a9049054013a1b77]*/
filename: unicode_fs_decoded
startstr: str
/
+ *
+ module as modname: object = None
Return symbol and scope dictionaries used internally by compiler.
[clinic start generated code]*/
static PyObject *
_symtable_symtable_impl(PyObject *module, PyObject *source,
- PyObject *filename, const char *startstr)
-/*[clinic end generated code: output=59eb0d5fc7285ac4 input=436ffff90d02e4f6]*/
+ PyObject *filename, const char *startstr,
+ PyObject *modname)
+/*[clinic end generated code: output=235ec5a87a9ce178 input=fbf9adaa33c7070d]*/
{
struct symtable *st;
PyObject *t;
Py_XDECREF(source_copy);
return NULL;
}
- st = _Py_SymtableStringObjectFlags(str, filename, start, &cf);
+ if (modname == Py_None) {
+ modname = NULL;
+ }
+ else if (!PyUnicode_Check(modname)) {
+ PyErr_Format(PyExc_TypeError,
+ "symtable() argument 'module' must be str or None, not %T",
+ modname);
+ Py_XDECREF(source_copy);
+ return NULL;
+ }
+ st = _Py_SymtableStringObjectFlags(str, filename, start, &cf, modname);
Py_XDECREF(source_copy);
if (st == NULL) {
return NULL;
tok->encoding = NULL;
tok->cont_line = 0;
tok->filename = NULL;
+ tok->module = NULL;
tok->decoding_readline = NULL;
tok->decoding_buffer = NULL;
tok->readline = NULL;
Py_XDECREF(tok->decoding_buffer);
Py_XDECREF(tok->readline);
Py_XDECREF(tok->filename);
+ Py_XDECREF(tok->module);
if ((tok->readline != NULL || tok->fp != NULL ) && tok->buf != NULL) {
PyMem_Free(tok->buf);
}
int parenlinenostack[MAXLEVEL];
int parencolstack[MAXLEVEL];
PyObject *filename;
+ PyObject *module;
/* Stuff for checking on different tab sizes */
int altindstack[MAXINDENT]; /* Stack of alternate indents */
/* Stuff for PEP 0263 */
mod_ty
_PyParser_ASTFromString(const char *str, PyObject* filename, int mode,
- PyCompilerFlags *flags, PyArena *arena)
+ PyCompilerFlags *flags, PyArena *arena,
+ PyObject *module)
{
if (PySys_Audit("compile", "yO", str, filename) < 0) {
return NULL;
}
- mod_ty result = _PyPegen_run_parser_from_string(str, mode, filename, flags, arena);
+ mod_ty result = _PyPegen_run_parser_from_string(str, mode, filename, flags,
+ arena, module);
return result;
}
// From here on we need to clean up even if there's an error
mod_ty result = NULL;
+ tok->module = PyUnicode_FromString("__main__");
+ if (tok->module == NULL) {
+ goto error;
+ }
+
int parser_flags = compute_parser_flags(flags);
Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION,
errcode, NULL, arena);
mod_ty
_PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filename_ob,
- PyCompilerFlags *flags, PyArena *arena)
+ PyCompilerFlags *flags, PyArena *arena, PyObject *module)
{
int exec_input = start_rule == Py_file_input;
}
// This transfers the ownership to the tokenizer
tok->filename = Py_NewRef(filename_ob);
+ tok->module = Py_XNewRef(module);
// We need to clear up from here on
mod_ty result = NULL;
const char *, const char *, PyCompilerFlags *, int *, PyObject **,
PyArena *);
void *_PyPegen_run_parser(Parser *);
-mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *);
+mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *, PyObject *);
asdl_stmt_seq *_PyPegen_interactive_exit(Parser *);
// Generated function in parse.c - function definition in python.gram
}
if (PyErr_WarnExplicitObject(category, msg, p->tok->filename,
- lineno, NULL, NULL) < 0) {
+ lineno, p->tok->module, NULL) < 0) {
if (PyErr_ExceptionMatches(category)) {
/* Replace the Syntax/DeprecationWarning exception with a SyntaxError
to get a more accurate error report */
}
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename,
- tok->lineno, NULL, NULL) < 0) {
+ tok->lineno, tok->module, NULL) < 0) {
Py_DECREF(msg);
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
}
if (PyErr_WarnExplicitObject(category, errmsg, tok->filename,
- tok->lineno, NULL, NULL) < 0) {
+ tok->lineno, tok->module, NULL) < 0) {
if (PyErr_ExceptionMatches(category)) {
/* Replace the DeprecationWarning exception with a SyntaxError
to get a more accurate error report */
def compile_and_marshal(name: str, text: bytes) -> bytes:
filename = f"<frozen {name}>"
# exec == Py_file_input
- code = compile(text, filename, "exec", optimize=0, dont_inherit=True)
+ code = compile(text, filename, "exec", optimize=0, dont_inherit=True, module=name)
return marshal.dumps(code)
with tokenize.open(filename) as source_fp:
source = source_fp.read()
- code = compile(source, code_filename, 'exec')
+ code = compile(source, code_filename, 'exec', module=name)
data = marshal.dumps(code)
writecode(fp, name, data)
typedef struct {
PyObject *filename;
+ PyObject *module;
int optimize;
int ff_features;
int syntax_check_only;
}
int ret = _PyErr_EmitSyntaxWarning(msg, state->filename, n->lineno,
n->col_offset + 1, n->end_lineno,
- n->end_col_offset + 1);
+ n->end_col_offset + 1,
+ state->module);
Py_DECREF(msg);
return ret < 0 ? 0 : 1;
}
int
_PyAST_Preprocess(mod_ty mod, PyArena *arena, PyObject *filename, int optimize,
- int ff_features, int syntax_check_only, int enable_warnings)
+ int ff_features, int syntax_check_only, int enable_warnings,
+ PyObject *module)
{
_PyASTPreprocessState state;
memset(&state, 0, sizeof(_PyASTPreprocessState));
state.filename = filename;
+ state.module = module;
state.optimize = optimize;
state.ff_features = ff_features;
state.syntax_check_only = syntax_check_only;
dont_inherit: bool = False
optimize: int = -1
*
+ module as modname: object = None
_feature_version as feature_version: int = -1
Compile source into a code object that can be executed by exec() or eval().
static PyObject *
builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
const char *mode, int flags, int dont_inherit,
- int optimize, int feature_version)
-/*[clinic end generated code: output=b0c09c84f116d3d7 input=8f0069edbdac381b]*/
+ int optimize, PyObject *modname, int feature_version)
+/*[clinic end generated code: output=9a0dce1945917a86 input=ddeae1e0253459dc]*/
{
PyObject *source_copy;
const char *str;
"compile(): invalid optimize value");
goto error;
}
+ if (modname == Py_None) {
+ modname = NULL;
+ }
+ else if (!PyUnicode_Check(modname)) {
+ PyErr_Format(PyExc_TypeError,
+ "compile() argument 'module' must be str or None, not %T",
+ modname);
+ goto error;
+ }
if (!dont_inherit) {
PyEval_MergeCompilerFlags(&cf);
goto error;
}
int syntax_check_only = ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */
- if (_PyCompile_AstPreprocess(mod, filename, &cf, optimize,
- arena, syntax_check_only) < 0) {
+ if (_PyCompile_AstPreprocess(mod, filename, &cf, optimize, arena,
+ syntax_check_only, modname) < 0)
+ {
_PyArena_Free(arena);
goto error;
}
goto error;
}
result = (PyObject*)_PyAST_Compile(mod, filename,
- &cf, optimize, arena);
+ &cf, optimize, arena, modname);
}
_PyArena_Free(arena);
goto finally;
tstate->suppress_co_const_immortalization++;
#endif
- result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize);
+ result = _Py_CompileStringObjectWithModule(str, filename,
+ start[compile_mode], &cf,
+ optimize, modname);
#ifdef Py_GIL_DISABLED
tstate->suppress_co_const_immortalization--;
PyDoc_STRVAR(builtin_compile__doc__,
"compile($module, /, source, filename, mode, flags=0,\n"
-" dont_inherit=False, optimize=-1, *, _feature_version=-1)\n"
+" dont_inherit=False, optimize=-1, *, module=None,\n"
+" _feature_version=-1)\n"
"--\n"
"\n"
"Compile source into a code object that can be executed by exec() or eval().\n"
static PyObject *
builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
const char *mode, int flags, int dont_inherit,
- int optimize, int feature_version);
+ int optimize, PyObject *modname, int feature_version);
static PyObject *
builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 7
+ #define NUM_KEYWORDS 8
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(source), &_Py_ID(filename), &_Py_ID(mode), &_Py_ID(flags), &_Py_ID(dont_inherit), &_Py_ID(optimize), &_Py_ID(_feature_version), },
+ .ob_item = { &_Py_ID(source), &_Py_ID(filename), &_Py_ID(mode), &_Py_ID(flags), &_Py_ID(dont_inherit), &_Py_ID(optimize), &_Py_ID(module), &_Py_ID(_feature_version), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "_feature_version", NULL};
+ static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "module", "_feature_version", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "compile",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[7];
+ PyObject *argsbuf[8];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3;
PyObject *source;
PyObject *filename = NULL;
int flags = 0;
int dont_inherit = 0;
int optimize = -1;
+ PyObject *modname = Py_None;
int feature_version = -1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
if (!noptargs) {
goto skip_optional_kwonly;
}
- feature_version = PyLong_AsInt(args[6]);
+ if (args[6]) {
+ modname = args[6];
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ feature_version = PyLong_AsInt(args[7]);
if (feature_version == -1 && PyErr_Occurred()) {
goto exit;
}
skip_optional_kwonly:
- return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, feature_version);
+ return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, modname, feature_version);
exit:
/* Cleanup for filename */
exit:
return return_value;
}
-/*[clinic end generated code: output=7eada753dc2e046f input=a9049054013a1b77]*/
+/*[clinic end generated code: output=06500bcc9a341e68 input=a9049054013a1b77]*/
* (including instructions for nested code objects)
*/
int c_disable_warning;
+ PyObject *c_module;
} compiler;
static int
compiler_setup(compiler *c, mod_ty mod, PyObject *filename,
- PyCompilerFlags *flags, int optimize, PyArena *arena)
+ PyCompilerFlags *flags, int optimize, PyArena *arena,
+ PyObject *module)
{
PyCompilerFlags local_flags = _PyCompilerFlags_INIT;
if (!_PyFuture_FromAST(mod, filename, &c->c_future)) {
return ERROR;
}
+ c->c_module = Py_XNewRef(module);
if (!flags) {
flags = &local_flags;
}
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
c->c_save_nested_seqs = false;
- if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged, 0, 1)) {
+ if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged,
+ 0, 1, module))
+ {
return ERROR;
}
c->c_st = _PySymtable_Build(mod, filename, &c->c_future);
_PySymtable_Free(c->c_st);
}
Py_XDECREF(c->c_filename);
+ Py_XDECREF(c->c_module);
Py_XDECREF(c->c_const_cache);
Py_XDECREF(c->c_stack);
PyMem_Free(c);
static compiler*
new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
- int optimize, PyArena *arena)
+ int optimize, PyArena *arena, PyObject *module)
{
compiler *c = PyMem_Calloc(1, sizeof(compiler));
if (c == NULL) {
return NULL;
}
- if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) {
+ if (compiler_setup(c, mod, filename, pflags, optimize, arena, module) < 0) {
compiler_free(c);
return NULL;
}
return ERROR;
}
int ret = _PyErr_EmitSyntaxWarning(msg, c->c_filename, loc.lineno, loc.col_offset + 1,
- loc.end_lineno, loc.end_col_offset + 1);
+ loc.end_lineno, loc.end_col_offset + 1,
+ c->c_module);
Py_DECREF(msg);
return ret;
}
PyCodeObject *
_PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
- int optimize, PyArena *arena)
+ int optimize, PyArena *arena, PyObject *module)
{
assert(!PyErr_Occurred());
- compiler *c = new_compiler(mod, filename, pflags, optimize, arena);
+ compiler *c = new_compiler(mod, filename, pflags, optimize, arena, module);
if (c == NULL) {
return NULL;
}
int
_PyCompile_AstPreprocess(mod_ty mod, PyObject *filename, PyCompilerFlags *cf,
- int optimize, PyArena *arena, int no_const_folding)
+ int optimize, PyArena *arena, int no_const_folding,
+ PyObject *module)
{
_PyFutureFeatures future;
if (!_PyFuture_FromAST(mod, filename, &future)) {
if (optimize == -1) {
optimize = _Py_GetConfig()->optimization_level;
}
- if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags, no_const_folding, 0)) {
+ if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags,
+ no_const_folding, 0, module))
+ {
return -1;
}
return 0;
return NULL;
}
- compiler *c = new_compiler(mod, filename, pflags, optimize, arena);
+ compiler *c = new_compiler(mod, filename, pflags, optimize, arena, NULL);
if (c == NULL) {
_PyArena_Free(arena);
return NULL;
*/
int
_PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset,
- int end_lineno, int end_col_offset)
+ int end_lineno, int end_col_offset,
+ PyObject *module)
{
- if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg,
- filename, lineno, NULL, NULL) < 0)
+ if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, filename, lineno,
+ module, NULL) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError
} else {
name = &_Py_STR(anon_string);
}
+ PyObject *module = NULL;
+ if (globals && PyDict_GetItemStringRef(globals, "__name__", &module) < 0) {
+ goto done;
+ }
- mod = _PyParser_ASTFromString(str, name, start, flags, arena);
+ mod = _PyParser_ASTFromString(str, name, start, flags, arena, module);
+ Py_XDECREF(module);
- if (mod != NULL) {
+ if (mod != NULL) {
ret = run_mod(mod, name, globals, locals, flags, arena, source, generate_new_source);
}
+
+done:
Py_XDECREF(source);
_PyArena_Free(arena);
return ret;
return NULL;
}
}
+ PyObject *module = NULL;
+ if (globals && PyDict_GetItemStringRef(globals, "__name__", &module) < 0) {
+ if (interactive_src) {
+ Py_DECREF(interactive_filename);
+ }
+ return NULL;
+ }
- PyCodeObject *co = _PyAST_Compile(mod, interactive_filename, flags, -1, arena);
+ PyCodeObject *co = _PyAST_Compile(mod, interactive_filename, flags, -1,
+ arena, module);
+ Py_XDECREF(module);
if (co == NULL) {
if (interactive_src) {
Py_DECREF(interactive_filename);
PyObject *
Py_CompileStringObject(const char *str, PyObject *filename, int start,
PyCompilerFlags *flags, int optimize)
+{
+ return _Py_CompileStringObjectWithModule(str, filename, start,
+ flags, optimize, NULL);
+}
+
+PyObject *
+_Py_CompileStringObjectWithModule(const char *str, PyObject *filename, int start,
+ PyCompilerFlags *flags, int optimize, PyObject *module)
{
PyCodeObject *co;
mod_ty mod;
if (arena == NULL)
return NULL;
- mod = _PyParser_ASTFromString(str, filename, start, flags, arena);
+ mod = _PyParser_ASTFromString(str, filename, start, flags, arena, module);
if (mod == NULL) {
_PyArena_Free(arena);
return NULL;
}
if (flags && (flags->cf_flags & PyCF_ONLY_AST)) {
int syntax_check_only = ((flags->cf_flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */
- if (_PyCompile_AstPreprocess(mod, filename, flags, optimize, arena, syntax_check_only) < 0) {
+ if (_PyCompile_AstPreprocess(mod, filename, flags, optimize, arena,
+ syntax_check_only, module) < 0)
+ {
_PyArena_Free(arena);
return NULL;
}
_PyArena_Free(arena);
return result;
}
- co = _PyAST_Compile(mod, filename, flags, optimize, arena);
+ co = _PyAST_Compile(mod, filename, flags, optimize, arena, module);
_PyArena_Free(arena);
return (PyObject *)co;
}
struct symtable *
_Py_SymtableStringObjectFlags(const char *str, PyObject *filename,
- int start, PyCompilerFlags *flags)
+ int start, PyCompilerFlags *flags, PyObject *module)
{
struct symtable *st;
mod_ty mod;
if (arena == NULL)
return NULL;
- mod = _PyParser_ASTFromString(str, filename, start, flags, arena);
+ mod = _PyParser_ASTFromString(str, filename, start, flags, arena, module);
if (mod == NULL) {
_PyArena_Free(arena);
return NULL;
PyObject *result = NULL;
if (mode == 2) {
- result = (PyObject *)_PyAST_Compile(module, filename_ob, NULL, -1, arena);
+ result = (PyObject *)_PyAST_Compile(module, filename_ob, NULL, -1, arena, NULL);
} else if (mode == 1) {
result = PyAST_mod2obj(module);
} else {
PyCompilerFlags flags = _PyCompilerFlags_INIT;
mod_ty res = _PyPegen_run_parser_from_string(the_string, Py_file_input, filename_ob,
- &flags, arena);
+ &flags, arena, NULL);
if (res == NULL) {
goto error;
}