Skip to content

Commit 85eb91d

Browse files
authored
Add Python 3.12 support via "trace" method
2 parents 71835ec + d9f6eda commit 85eb91d

File tree

9 files changed

+83
-55
lines changed

9 files changed

+83
-55
lines changed

.codecov.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
informational: true
6+
patch:
7+
default:
8+
informational: true
9+
changes: false
10+
comment:
11+
layout: "header, diff"
12+
behavior: default
13+
github_checks:
14+
annotations: false

.github/workflows/lint.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ jobs:
1616
name: pre-commit-hooks
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v3
20-
- uses: actions/setup-python@v4
19+
- uses: actions/checkout@v4
20+
- uses: actions/setup-python@v5
2121
with:
2222
python-version: "3.10"
23-
- uses: pre-commit/action@v3.0.0
23+
- uses: pre-commit/action@v3.0.1

.github/workflows/pypi.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ jobs:
1111
if: github.repository == 'eriknw/innerscope'
1212
steps:
1313
- name: Checkout
14-
uses: actions/checkout@v3
14+
uses: actions/checkout@v4
1515
with:
1616
fetch-depth: 0
1717
- name: Set up Python
18-
uses: actions/setup-python@v4
18+
uses: actions/setup-python@v5
1919
with:
2020
python-version: "3.8"
2121
- name: Install build dependencies
@@ -24,7 +24,7 @@ jobs:
2424
python -m pip install build twine
2525
- name: Build wheel and sdist
2626
run: python -m build --sdist --wheel
27-
- uses: actions/upload-artifact@v3
27+
- uses: actions/upload-artifact@v4
2828
with:
2929
name: releases
3030
path: dist
@@ -33,7 +33,7 @@ jobs:
3333
run: python -m twine check --strict dist/*
3434
- name: Publish to PyPI
3535
if: contains(github.ref, 'refs/tags/')
36-
uses: pypa/gh-action-pypi-publish@v1.8.6
36+
uses: pypa/gh-action-pypi-publish@v1.8.11
3737
with:
3838
user: __token__
3939
password: ${{ secrets.PYPI_TOKEN }}

.github/workflows/test.yml

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ on:
88
jobs:
99
test:
1010
runs-on: ${{ matrix.os }}
11+
defaults:
12+
run:
13+
shell: bash -l {0}
1114
strategy:
1215
fail-fast: false
1316
matrix:
1417
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
15-
python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.8", "pypy-3.9"]
18+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8", "pypy-3.9", "pypy-3.10"]
1619
steps:
1720
- name: Checkout
18-
uses: actions/checkout@v3
21+
uses: actions/checkout@v4
1922
with:
2023
fetch-depth: 0
2124
- name: Set up Python
22-
uses: actions/setup-python@v4
25+
uses: actions/setup-python@v5
2326
with:
2427
python-version: ${{ matrix.python-version }}
2528
- name: Install dependencies
@@ -29,27 +32,14 @@ jobs:
2932
pip install -e . --no-deps
3033
- name: PyTest
3134
run: |
32-
coverage run --branch -m pytest --doctest-modules --method bytecode
35+
if [[ ${{ matrix.python-version }} != '3.12' ]]; then
36+
coverage run --branch -m pytest --doctest-modules --method bytecode
37+
fi
3338
coverage run -a --branch -m pytest --doctest-modules --method trace
3439
pytest --doctest-modules --method trace
3540
- name: Coverage
36-
if: (! contains(matrix.python-version, 'pypy'))
37-
env:
38-
GITHUB_TOKEN: ${{ secrets.github_token }}
39-
COVERALLS_FLAG_NAME: ${{ matrix.python-version}}
40-
COVERALLS_PARALLEL: true
4141
run: |
42-
pip install coveralls
42+
coverage xml
4343
coverage report --show-missing
44-
coveralls --service=github
45-
46-
finish:
47-
needs: test
48-
if: always()
49-
runs-on: ubuntu-latest
50-
steps:
51-
- name: Coveralls Finished
52-
uses: coverallsapp/github-action@v2
53-
with:
54-
github-token: ${{ secrets.github_token }}
55-
parallel-finished: true
44+
- name: codecov
45+
uses: codecov/codecov-action@v4

.pre-commit-config.yaml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ default_language_version:
1717
python: python3
1818
repos:
1919
- repo: https://github.com/pre-commit/pre-commit-hooks
20-
rev: v4.4.0
20+
rev: v4.5.0
2121
hooks:
2222
- id: check-added-large-files
2323
- id: check-case-conflict
@@ -33,58 +33,58 @@ repos:
3333
- id: name-tests-test
3434
args: ["--pytest-test-first"]
3535
- repo: https://github.com/abravalheri/validate-pyproject
36-
rev: v0.13
36+
rev: v0.16
3737
hooks:
3838
- id: validate-pyproject
3939
name: Validate pyproject.toml
4040
# I don't yet trust ruff to do what autoflake does
4141
- repo: https://github.com/PyCQA/autoflake
42-
rev: v2.1.1
42+
rev: v2.2.1
4343
hooks:
4444
- id: autoflake
4545
args: [--in-place]
4646
- repo: https://github.com/pycqa/isort
47-
rev: 5.12.0
47+
rev: 5.13.2
4848
hooks:
4949
- id: isort
5050
- repo: https://github.com/asottile/pyupgrade
51-
rev: v3.6.0
51+
rev: v3.15.0
5252
hooks:
5353
- id: pyupgrade
5454
args: [--py38-plus]
5555
- repo: https://github.com/psf/black
56-
rev: 23.3.0
56+
rev: 24.2.0
5757
hooks:
5858
- id: black
59-
# - repo: https://github.com/charliermarsh/ruff-pre-commit
60-
# rev: v0.0.272
59+
# - repo: https://github.com/astral-sh/ruff-pre-commit
60+
# rev: v0.1.14
6161
# hooks:
6262
# - id: ruff
6363
# args: [--fix-only, --show-fixes]
6464
- repo: https://github.com/PyCQA/flake8
65-
rev: 6.0.0
65+
rev: 7.0.0
6666
hooks:
6767
- id: flake8
6868
additional_dependencies: &flake8_dependencies
6969
# These versions need updated manually
70-
- flake8==6.0.0
70+
- flake8==7.0.0
7171
- flake8-comprehensions==3.12.0
72-
- flake8-bugbear==23.6.5
73-
- flake8-simplify==0.20.0
72+
- flake8-bugbear==24.2.6
73+
- flake8-simplify==0.21.0
7474
- repo: https://github.com/asottile/yesqa
7575
rev: v1.5.0
7676
hooks:
7777
- id: yesqa
7878
additional_dependencies: *flake8_dependencies
7979
- repo: https://github.com/codespell-project/codespell
80-
rev: v2.2.4
80+
rev: v2.2.6
8181
hooks:
8282
- id: codespell
8383
types_or: [python, rst, markdown]
8484
additional_dependencies: [tomli]
8585
files: ^(innerscope|docs)/
86-
- repo: https://github.com/charliermarsh/ruff-pre-commit
87-
rev: v0.0.272
86+
- repo: https://github.com/astral-sh/ruff-pre-commit
87+
rev: v0.2.1
8888
hooks:
8989
- id: ruff
9090
# `pyroma` may help keep our package standards up to date if best practices change.
@@ -95,6 +95,6 @@ repos:
9595
- id: pyroma
9696
args: [-n, "10", .]
9797
- repo: https://github.com/pre-commit/pre-commit-hooks
98-
rev: v4.4.0
98+
rev: v4.5.0
9999
hooks:
100100
- id: no-commit-to-branch # no commit directly to main

innerscope/cfg.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
default_method = "bytecode"
1+
import sys
2+
3+
if sys.version_info < (3, 12):
4+
default_method = "bytecode"
5+
else:
6+
default_method = "trace"
7+
del sys

innerscope/core.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
+ b"%b"
2121
+ bytes([dis.opmap["BUILD_TUPLE"], 3, dis.opmap["RETURN_VALUE"], 0])
2222
)
23-
else:
23+
elif sys.version_info < (3, 12):
2424
NEW_CODE = (
2525
bytes([dis.opmap["LOAD_GLOBAL"]])
2626
+ b"%b"
@@ -73,6 +73,8 @@
7373
]
7474
)
7575
)
76+
else:
77+
NEW_CODE = b"" # NOT YET SUPPORTED
7678
BUILTINS = set(dir(builtins))
7779

7880

@@ -460,7 +462,7 @@ def __init__(self, func, *mappings, use_closures=True, use_globals=True, method=
460462
self.missing.update(name for name in code.co_freevars if name not in outer_scope)
461463
self.builtin_names -= self.outer_scope.keys()
462464

463-
if self._code is None:
465+
if self._code is None and method == "bytecode":
464466
self._create_code()
465467

466468
def _create_code(self):
@@ -503,11 +505,15 @@ def _create_code(self):
503505
co_names = (*code.co_names, "_innerscope_locals_", "_innerscope_secret_")
504506
if sys.version_info < (3, 11):
505507
new_code = NEW_CODE % (bytes([len(code.co_names)]), bytes([len(code.co_names) + 1]))
506-
else:
508+
elif sys.version_info < (3, 12):
507509
new_code = NEW_CODE % (
508510
bytes([2 * len(code.co_names) + 1]),
509511
bytes([2 * len(code.co_names) + 2]),
510512
)
513+
else:
514+
raise NotImplementedError(
515+
'Unable to create bytecode for method="bytecode" in this Python version'
516+
)
511517
co_code = co_code + new_code
512518

513519
# stacksize must be at least 3, because we make a length three tuple
@@ -615,7 +621,11 @@ def trace_returns(frame, event, arg):
615621
del outer_scope["_innerscope_locals_"]
616622
del outer_scope["_innerscope_secret_"]
617623
# closures show up in locals, but we want them only in outer_scope
618-
for key in self._code.co_freevars:
624+
if is_trace:
625+
freevars = self.func.__code__.co_freevars
626+
else:
627+
freevars = self._code.co_freevars
628+
for key in freevars:
619629
del inner_scope[key]
620630
rv = Scope(self, outer_scope, return_value, inner_scope)
621631
if type(self) is ScopedGeneratorFunction:
@@ -734,7 +744,8 @@ def __getstate__(self):
734744

735745
def __setstate__(self, state):
736746
self.__dict__.update(state)
737-
self._create_code()
747+
if self.method == "bytecode":
748+
self._create_code()
738749

739750

740751
class ScopedGeneratorFunction(ScopedFunction):

pyproject.toml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ classifiers = [
3535
"Programming Language :: Python :: 3.9",
3636
"Programming Language :: Python :: 3.10",
3737
"Programming Language :: Python :: 3.11",
38+
"Programming Language :: Python :: 3.12",
3839
"Programming Language :: Python :: 3 :: Only",
3940
"Programming Language :: Python :: Implementation :: CPython",
4041
"Programming Language :: Python :: Implementation :: PyPy",
@@ -70,7 +71,7 @@ dirty_template = "{tag}+{ccount}.g{sha}.dirty"
7071

7172
[tool.black]
7273
line-length = 100
73-
target-version = ["py38", "py39", "py310", "py311"]
74+
target-version = ["py38", "py39", "py310", "py311", "py312"]
7475

7576
[tool.isort]
7677
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
@@ -112,9 +113,14 @@ exclude_lines = [
112113
]
113114

114115
[tool.ruff]
115-
# https://github.com/charliermarsh/ruff/
116+
# https://github.com/astral-sh/ruff/
116117
line-length = 100
117118
target-version = "py38"
119+
[tool.ruff.lint]
120+
unfixable = [
121+
"F841", # unused-variable (Note: can leave useless expression)
122+
"B905", # zip-without-explicit-strict (Note: prefer `zip(x, y, strict=True)`)
123+
]
118124
select = [
119125
"ALL",
120126
]
@@ -171,14 +177,14 @@ ignore = [
171177
"PD", # pandas-vet (Intended for scripts that use pandas, not libraries)
172178
]
173179

174-
[tool.ruff.per-file-ignores]
180+
[tool.ruff.lint.per-file-ignores]
175181
"__init__.py" = ["F401"] # Allow unused imports (w/o defining `__all__`)
176182
"innerscope/tests/*py" = [
177183
"S101", "S301", "T201", "D103", "D100", # Allow assert, print, pickle, and no docstring
178184
"A001", "A002", "B018", "C408", "C416", "E702", "E703", "F821", "F841", # Let us test messy code
179185
]
180186
"innerscope/tests/test_repr.py" = ["E501"]
181187

182-
[tool.ruff.flake8-pytest-style]
188+
[tool.ruff.lint.flake8-pytest-style]
183189
fixture-parentheses = false
184190
mark-parentheses = false

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Simple setuptools script; see pyproject.toml for package info."""
2+
23
from setuptools import setup
34

45
setup()

0 commit comments

Comments
 (0)