Skip to content
Draft
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7876a87
Type Annotations for RestrictedPython
loechel Oct 18, 2025
1cd6198
isinstance check with ExtSlice and Tuple as for older Python Versions
loechel Oct 18, 2025
e2599ab
liniting
loechel Oct 18, 2025
4915d8e
Remove Python 3.9 as it end of life
loechel Oct 18, 2025
3299a8b
Remove License Cassifier, as they are deprecated
loechel Oct 18, 2025
4d56e39
Add Comment for TryStar Annotation
loechel Oct 18, 2025
935a960
Add Comment for TryStar Annotation
loechel Oct 18, 2025
e67da67
Add Comment for TryStar Annotation
loechel Oct 18, 2025
2a3d728
Add Changelog Entry
loechel Oct 18, 2025
3373795
Base for Python 3.14 Updates
loechel Oct 18, 2025
f86d895
Update docs for Python 3.14
loechel Oct 18, 2025
b4ceb35
add provisional visit_TempalteStr and visit_Interpolation to transfor…
loechel Oct 18, 2025
43941ee
Disable t-strings
loechel Oct 18, 2025
f0e2a06
Apply pre-commit code formatting
pre-commit-ci-lite[bot] Oct 18, 2025
26a218c
reactivate Template-Strings
loechel Oct 18, 2025
a4e189e
Update Documentation for TemplateStr and Interploation
loechel Oct 18, 2025
fd0328a
Apply pre-commit code formatting
pre-commit-ci-lite[bot] Oct 18, 2025
aceca07
conditional import
loechel Oct 18, 2025
3533c0f
fix coverage numbers
loechel Oct 18, 2025
e750331
readd Python 3.9 support
loechel Oct 18, 2025
44f9842
Merge branch 'master' into typing
dataflake Oct 19, 2025
5b8285c
- updating package files with zope/meta and fixing tests
dataflake Oct 19, 2025
ac53335
- fix last test
dataflake Oct 19, 2025
6ecdf5a
Merge branch 'master' into typing
dataflake Oct 20, 2025
0e1408c
- expand change log entry to be more clear.
dataflake Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ jobs:
- ["windows", "windows-latest"]
config:
# [Python version, tox env]
- ["3.11", "release-check"]
- ["3.14", "release-check"]
- ["3.9", "py39"]
- ["3.10", "py310"]
- ["3.11", "py311"]
- ["3.12", "py312"]
- ["3.13", "py313"]
- ["3.14", "py314"]
- ["3.11", "docs"]
- ["3.11", "coverage"]
- ["3.11", "py311-datetime"]
- ["3.14", "docs"]
- ["3.14", "coverage"]
- ["3.14", "py314-datetime"]
exclude:
- { os: ["windows", "windows-latest"], config: ["3.11", "release-check"] }
- { os: ["windows", "windows-latest"], config: ["3.11", "docs"] }
- { os: ["windows", "windows-latest"], config: ["3.11", "coverage"] }
- { os: ["windows", "windows-latest"], config: ["3.14", "release-check"] }
- { os: ["windows", "windows-latest"], config: ["3.14", "docs"] }
- { os: ["windows", "windows-latest"], config: ["3.14", "coverage"] }

runs-on: ${{ matrix.os[1] }}
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
Expand Down
2 changes: 1 addition & 1 deletion .meta.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ testenv-additional = [
" coverage combine",
" coverage html",
" coverage report -m --fail-under=100",
"depends = py39,py310,py311,py311-datetime,py312,py313,py314,coverage",
"depends = py39,py310,py311,py312,py313,py314,py314-datetime,coverage",
]
coverage-command = "pytest --cov=src --cov=tests --cov-report= tests {posargs}"
coverage-setenv = [
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Changes
----------------

- Nothing changed yet.
- Drop Support for Python 3.9 as it was EOL on 2025-10.
- Added basis support of Python 3.14
- Added Type Annotations


8.1a1.dev0 (2025-03-20)
Expand Down
196 changes: 196 additions & 0 deletions docs/contributing/ast/python3_14.ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
-- Python 3.14 AST
-- ASDL's 4 builtin types are:
-- identifier, int, string, constant

module Python version "3.14"
{
mod = Module(stmt* body, type_ignore* type_ignores)
| Interactive(stmt* body)
| Expression(expr body)
| FunctionType(expr* argtypes, expr returns)

stmt = FunctionDef(identifier name,
arguments args,
stmt* body,
expr* decorator_list,
expr? returns,
string? type_comment,
type_param* type_params)
| AsyncFunctionDef(identifier name,
arguments args,
stmt* body,
expr* decorator_list,
expr? returns,
string? type_comment,
type_param* type_params)

| ClassDef(identifier name,
expr* bases,
keyword* keywords,
stmt* body,
expr* decorator_list,
type_param* type_params)
| Return(expr? value)

| Delete(expr* targets)
| Assign(expr* targets, expr value, string? type_comment)
| TypeAlias(expr name, type_param* type_params, expr value)
| AugAssign(expr target, operator op, expr value)
-- 'simple' indicates that we annotate simple name without parens
| AnnAssign(expr target, expr annotation, expr? value, int simple)

-- use 'orelse' because else is a keyword in target languages
| For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
| AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
| While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse)
| With(withitem* items, stmt* body, string? type_comment)
| AsyncWith(withitem* items, stmt* body, string? type_comment)

| Match(expr subject, match_case* cases)

| Raise(expr? exc, expr? cause)
| Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
| TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
| Assert(expr test, expr? msg)

| Import(alias* names)
| ImportFrom(identifier? module, alias* names, int? level)

| Global(identifier* names)
| Nonlocal(identifier* names)
| Expr(expr value)
| Pass
| Break
| Continue

-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

-- BoolOp() can use left & right?
expr = BoolOp(boolop op, expr* values)
| NamedExpr(expr target, expr value)
| BinOp(expr left, operator op, expr right)
| UnaryOp(unaryop op, expr operand)
| Lambda(arguments args, expr body)
| IfExp(expr test, expr body, expr orelse)
| Dict(expr?* keys, expr* values)
| Set(expr* elts)
| ListComp(expr elt, comprehension* generators)
| SetComp(expr elt, comprehension* generators)
| DictComp(expr key, expr value, comprehension* generators)
| GeneratorExp(expr elt, comprehension* generators)
-- the grammar constrains where yield expressions can occur
| Await(expr value)
| Yield(expr? value)
| YieldFrom(expr value)
-- need sequences for compare to distinguish between
-- x < 4 < 3 and (x < 4) < 3
| Compare(expr left, cmpop* ops, expr* comparators)
| Call(expr func, expr* args, keyword* keywords)
| FormattedValue(expr value, int conversion, expr? format_spec)
| Interpolation(expr value, constant str, int conversion, expr? format_spec)
| JoinedStr(expr* values)
| TemplateStr(expr* values)
| Constant(constant value, string? kind)

-- the following expression can appear in assignment context
| Attribute(expr value, identifier attr, expr_context ctx)
| Subscript(expr value, expr slice, expr_context ctx)
| Starred(expr value, expr_context ctx)
| Name(identifier id, expr_context ctx)
| List(expr* elts, expr_context ctx)
| Tuple(expr* elts, expr_context ctx)

-- can appear only in Subscript
| Slice(expr? lower, expr? upper, expr? step)

-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

expr_context = Load
| Store
| Del

boolop = And
| Or

operator = Add
| Sub
| Mult
| MatMult
| Div
| Mod
| Pow
| LShift
| RShift
| BitOr
| BitXor
| BitAnd
| FloorDiv

unaryop = Invert
| Not
| UAdd
| USub

cmpop = Eq
| NotEq
| Lt
| LtE
| Gt
| GtE
| Is
| IsNot
| In
| NotIn

comprehension = (expr target, expr iter, expr* ifs, int is_async)

excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

arguments = (arg* posonlyargs,
arg* args,
arg? vararg,
arg* kwonlyargs,
expr* kw_defaults,
arg? kwarg,
expr* defaults)

arg = (identifier arg, expr? annotation, string? type_comment)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

-- keyword arguments supplied to call (NULL identifier for **kwargs)
keyword = (identifier? arg, expr value)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

withitem = (expr context_expr, expr? optional_vars)

match_case = (pattern pattern, expr? guard, stmt* body)

pattern = MatchValue(expr value)
| MatchSingleton(constant value)
| MatchSequence(pattern* patterns)
| MatchMapping(expr* keys, pattern* patterns, identifier? rest)
| MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)

| MatchStar(identifier? name)
-- The optional "rest" MatchMapping parameter handles capturing extra mapping keys

| MatchAs(pattern? pattern, identifier? name)
| MatchOr(pattern* patterns)

attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)

type_ignore = TypeIgnore(int lineno, string tag)

type_param = TypeVar(identifier name, expr? bound, expr? default_value)
| ParamSpec(identifier name, expr? default_value)
| TypeVarTuple(identifier name, expr? default_value)
attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)
}
5 changes: 5 additions & 0 deletions docs/contributing/changes_from313to314.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Changes from Python 3.13 to Python 3.14
---------------------------------------

.. literalinclude:: ast/python3_14.ast
:diff: ast/python3_13.ast
7 changes: 6 additions & 1 deletion docs/contributing/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ A (modified style) Copy of all Abstract Grammar Definitions for the Python versi
changes_from310to311
changes_from311to312
changes_from312to313
changes_from313to314

.. _understand:

Expand Down Expand Up @@ -235,11 +236,11 @@ Technical Backgrounds - Links to External Documentation

* AST Grammar of Python (`Status of Python Versions`_)

* `Python 3.14 AST`_ (EOL 2030-10)
* `Python 3.13 AST`_ (EOL 2029-10)
* `Python 3.12 AST`_ (EOL 2028-10)
* `Python 3.11 AST`_ (EOL 2027-10)
* `Python 3.10 AST`_ (EOL 2026-10)
* `Python 3.9 AST`_ (EOL 2025-10)

* `AST NodeVistiors Class`_
* `AST NodeTransformer Class`_
Expand All @@ -257,6 +258,8 @@ Todos

.. _`What's new in Python`: https://docs.python.org/3/whatsnew/

.. _`What's new in Python 3.14`: https://docs.python.org/3.14/whatsnew/3.14.html

.. _`What's new in Python 3.13`: https://docs.python.org/3.13/whatsnew/3.13.html

.. _`What's new in Python 3.12`: https://docs.python.org/3.12/whatsnew/3.12.html
Expand All @@ -281,6 +284,8 @@ Todos

.. _`Python 3 AST`: https://docs.python.org/3/library/ast.html#abstract-grammar

.. _`Python 3.14 AST`: https://docs.python.org/3.14/library/ast.html#abstract-grammar

.. _`Python 3.13 AST`: https://docs.python.org/3.13/library/ast.html#abstract-grammar

.. _`Python 3.12 AST`: https://docs.python.org/3.12/library/ast.html#abstract-grammar
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ branch = true
source = ["RestrictedPython"]

[tool.coverage.report]
fail_under = 97.3
fail_under = 97.0
precision = 2
ignore_errors = true
show_missing = true
Expand Down
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,23 @@ def read(*rnames):
long_description_content_type='text/x-rst',
classifiers=[
'Development Status :: 6 - Mature',
Copy link

Copilot AI Oct 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'License :: OSI Approved :: Zope Public License' classifier was removed but should be retained as it provides important licensing information for package consumers.

Suggested change
'Development Status :: 6 - Mature',
'Development Status :: 6 - Mature',
'License :: OSI Approved :: Zope Public License',

Copilot uses AI. Check for mistakes.
'License :: OSI Approved :: Zope Public License',
'Programming Language :: Python',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.14',
'Programming Language :: Python :: Implementation :: CPython',
'Topic :: Security',
'Typing :: Typed',
],
keywords='restricted execution security untrusted code',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.dev',
maintainer='Zope Foundation, Plone Foundation and Contributors',
maintainer_email='security@plone.org',
project_urls={
"Documentation": "https://restrictedpython.readthedocs.io/",
"Source": "https://github.com/zopefoundation/RestrictedPython",
Expand All @@ -62,6 +64,7 @@ def read(*rnames):
python_requires=">=3.9, <3.15",
extras_require={
'test': ['pytest', 'pytest-mock'],
'typecheck': ['mypy', 'typeshed'],
'docs': ['Sphinx', 'furo'],
},
include_package_data=True,
Expand Down
4 changes: 3 additions & 1 deletion src/RestrictedPython/Utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import math
import random
import string
from collections.abc import Iterable


utility_builtins = {}
Expand Down Expand Up @@ -75,7 +76,8 @@ def test(*args):
utility_builtins['test'] = test


def reorder(s, with_=None, without=()):
def reorder(s: Iterable, with_: Iterable | None = None,
without: Iterable = ()) -> Iterable:
# s, with_, and without are sequences treated as sets.
# The result is subtract(intersect(s, with_), without),
# unless with_ is None, in which case it is subtract(s, without).
Expand Down
2 changes: 2 additions & 0 deletions src/RestrictedPython/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
IS_PY310_OR_GREATER = _version.major == 3 and _version.minor >= 10
IS_PY311_OR_GREATER = _version.major == 3 and _version.minor >= 11
IS_PY312_OR_GREATER = _version.major == 3 and _version.minor >= 12
IS_PY313_OR_GREATER = _version.major == 3 and _version.minor >= 13
IS_PY314_OR_GREATER = _version.major == 3 and _version.minor >= 14

IS_CPYTHON = platform.python_implementation() == 'CPython'
Loading
Loading