System Details
- Python Version: Python 3.12.3
- Scenic Version: 3.2.0b1, source checkout at 2fc1634. Also reproduced on 3.1.1 installed from PyPI.
- Operating System / Platform: Ubuntu 24.04.4 LTS, Linux 7.0.0-28-generic x86_64
- Simulator Version: not applicable
Detailed Description
- Description
Nothing in this project checks for undefined names. .pre-commit-config.yaml pins black and isort. No workflow, pyproject.toml, tox.ini or toxfile.py runs flake8, ruff or pyflakes. pyflakes 3.4.0 reports 15 undefined names across 10 files in src/scenic. Three of them raise NameError when the line runs, and I ran all three.
src/scenic/core/distributions.py:822:33: undefined name 'arg'
src/scenic/core/object_types.py:313:50: undefined name 'name'
src/scenic/core/object_types.py:361:57: undefined name 'name'
src/scenic/core/regions.py:2563:23: undefined name 'other'
src/scenic/core/regions.py:2566:23: undefined name 'other'
src/scenic/core/sensors.py:92:15: undefined name 'Optional'
src/scenic/core/utils.py:115:16: undefined name 'oldHandler'
src/scenic/core/vectors.py:561:19: undefined name 'bz'
src/scenic/core/vectors.py:562:29: undefined name 'bz'
src/scenic/core/visibility.py:569:17: undefined name 'SpheroidRegion'
src/scenic/domains/driving/roads.py:590:25: undefined name 'Dict'
src/scenic/domains/driving/roads.py:848:15: undefined name 'Dict'
src/scenic/simulators/carla/utils/visuals.py:241:19: undefined name 'collections'
src/scenic/simulators/carla/utils/visuals.py:311:9: undefined name 'set_transform'
src/scenic/simulators/webots/simulator.py:139:19: undefined name 'SimulationCreationError'
syntax/veneer.py produces 18 more of the form undefined name 'Left' in __all__. Those are names Scenic injects itself and are not counted above. ruff classifies them F822 rather than F821, so an F821 check does not fire on them.
The three that run:
OperatorDistribution.evaluateInner, distributions.py:822. Line 820 binds arg in its generator expression and uses it. The dict comprehension two lines below binds kwarg and uses arg. Reached whenever a random value is called with a keyword argument whose value needs lazy evaluation.
Vector.cross, vectors.py:559, unpacks into bx, by, ba while lines 561 and 562 use bz. Vector.dot immediately above it uses ox, oy, oz and is correct.
PolygonalFootprintRegion.containsRegionInner(self, reg, tolerance), regions.py:2560, tests isinstance(other, ...) at 2563 and 2566. The parameter is reg. Region.containsRegion ends with return self.containsRegionInner(reg, tolerance).
Those three account for five of the fifteen lines. The other ten I have not run, so please read them as places where a name is used with no binding pyflakes can see, not as ten more failures. utils.py:115 is at least dead: noNesting=True is passed nowhere in src or tests.
The suite is green at this commit. pytest --no-graphics -q -p no:randomly, after pip install -e ".[test-full]", gives 1761 passed, 391 skipped, 1 xfailed, 0 failed in 669s. Three lines that raise NameError when executed, and nothing red. The skip count depends on which optional simulators are installed.
This class of defect has reached a user once already. Issue #189, October 2023: someone hit NameError: name 'cubic_elem' is not defined in xodr_parser.py. The reply was "Unfortunately it wasn't detected by our test suite because we don't have an XODR file with that kind of curve in it." Three days later ea74a672, a one line change whose message is "Attempt bugfix, but new error pops up", corrected the name on the OpendriveParser branch, and that branch never reached main. On main the name survived until 62da37a1 deleted the surrounding block on 2026-05-15 as part of #467, which is about inconsistent planView lengths. That name is in v3.0.0, v3.1.0 and v3.1.1, and v3.1.1 went out eight days before it disappeared from main. Running the same pyflakes command over the 3.1.1 sdist reports 16 rather than 15, and the extra one is:
src/scenic/formats/opendrive/xodr_parser.py:1450:25: undefined name 'cubic_elem'
A check like this pays for itself on unfinished work, which is where it would run. PR #487, "[WIP] Various Improvements", is an open draft, head cefd7ec3, last commit dated 2026-07-27. Nothing there is finished and I am not treating it as a bug report. Sweeping it with the same command is just what a commit hook would have done: that branch fixes containsRegionInner (line 2741 there uses reg), still carries the cross one, and has two new ones:
src/scenic/core/regions.py:4195:26: undefined name 'point'
src/scenic/core/simulators.py:1089:42: undefined name 'collections'
PointSetRegion.closestPointTo(self, target) there begins point = toVector(point).coordinates, which is the first line of distanceTo directly above it. closestPointTo appears nowhere in src on main, so that method is new. A hook would have flagged both at the commit that wrote them rather than at review or after a merge.
A check that catches all 15:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.1
hooks:
- id: ruff-check
files: ^src/
args: [--select, F821, --target-version, py311]
pre-commit run --all-files with that config, on a clean checkout of 2fc1634, ends with Found 15 errors. and they are the same 15.
Both extra arguments are load bearing, and I only found that out by running it. All four combinations, same command, same clean checkout:
files: ^src/ |
--target-version py311 |
errors |
| yes |
yes |
15 |
| no |
yes |
43 |
| yes |
no |
16 |
| no |
no |
359 |
The 359 is 44 F821 plus 315 invalid-syntax, the latter from match statements in tests/ that ruff refuses to parse because pyproject.toml:20 sets requires-python = ">=3.8". Of the 43, 27 are in tests/ and 26 of those are in tests/syntax/polychrome.py.
--target-version py311 is doing two separate jobs, and I would not suggest it as a project setting since it contradicts tox.ini's py38 through py314. Without files: ^src/ it is what lets ruff parse your test files at all. With files: ^src/ it is still what keeps the count at 15 rather than 16: the extra one is core/errors.py:158 BaseExceptionGroup, which ruff flags correctly under requires-python = ">=3.8" even though the line is guarded by sys.version_info >= (3, 11) at runtime. If you would rather not pin a version in the hook, # noqa: F821 on that line gets the same 15. I checked that: files: ^src/, args: [--select, F821], noqa added, Found 15 errors.
The existing 15 need a decision either way. pre-commit runs on changed files, so the hook does not report them by itself. What it does is hand the next person who touches regions.py or roads.py a failing commit for a line they did not write.
If you would rather have three separate bug reports and no process argument, say so and close this.
- Command
scenic --2d -S -b lazykw.scenic
- Error log
Tail of the -b traceback, which is 95 lines in full. Only the path prefix up to the checkout root is cut:
File ".../src/scenic/core/lazy_eval.py", line 226, in valueInContext
return value.evaluateIn(context)
^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../src/scenic/core/distributions.py", line 180, in evaluateIn
value = super().evaluateIn(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../src/scenic/core/lazy_eval.py", line 57, in evaluateIn
value = self.evaluateInner(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../src/scenic/core/distributions.py", line 822, in evaluateInner
key: valueInContext(arg, context) for key, kwarg in self.kwoperands.items()
^^^
NameError: name 'arg' is not defined
Steps To Reproduce
The list of 15:
git clone https://github.com/BerkeleyLearnVerify/Scenic && cd Scenic
python -m pip install -e . pyflakes
python -m pyflakes src/scenic | grep "undefined name '" | grep -v "in __all__" | sort
That prints the block above and takes a second or two here. The grep -v drops the 18 veneer.py __all__ entries.
lazykw.scenic, for the traceback above:
def scaled(value, factor=1):
return value * factor
def shifted(value, factor=1):
return value + factor
vf = VectorField("Foo", lambda pos: 2 * pos.x)
x = (0 relative to vf).yaw
ego = new Object at 0.5 @ 0, with output Uniform(scaled, shifted)(10, factor=x)
The other two, in Python:
from scenic.core.vectors import Vector
Vector(1, 0, 0).dot(Vector(0, 1, 0)) # 0
Vector(1, 0, 0).cross(Vector(0, 1, 0)) # NameError: name 'bz' is not defined
from scenic.core.regions import PolygonalRegion
import shapely.geometry as sg
big = PolygonalRegion(polygon=sg.box(-10, -10, 10, 10)).footprint
small = PolygonalRegion(polygon=sg.box(-1, -1, 1, 1)).footprint
big.containsRegion(small) # NameError: name 'other' is not defined
All three behave the same on 3.1.1 from PyPI, at the same line numbers. No seed is needed, since all three fail before anything is sampled.
Nothing calls Vector.cross: git grep -n '\.cross(' -- src tests returns one hit and it is numpy.cross at regions.py:2810.
Issue Submission Checklist
System Details
Detailed Description
Nothing in this project checks for undefined names.
.pre-commit-config.yamlpinsblackandisort. No workflow,pyproject.toml,tox.iniortoxfile.pyruns flake8, ruff or pyflakes.pyflakes 3.4.0reports 15 undefined names across 10 files insrc/scenic. Three of them raiseNameErrorwhen the line runs, and I ran all three.syntax/veneer.pyproduces 18 more of the formundefined name 'Left' in __all__. Those are names Scenic injects itself and are not counted above. ruff classifies them F822 rather than F821, so an F821 check does not fire on them.The three that run:
OperatorDistribution.evaluateInner,distributions.py:822. Line 820 bindsargin its generator expression and uses it. The dict comprehension two lines below bindskwargand usesarg. Reached whenever a random value is called with a keyword argument whose value needs lazy evaluation.Vector.cross,vectors.py:559, unpacks intobx, by, bawhile lines 561 and 562 usebz.Vector.dotimmediately above it usesox, oy, ozand is correct.PolygonalFootprintRegion.containsRegionInner(self, reg, tolerance),regions.py:2560, testsisinstance(other, ...)at 2563 and 2566. The parameter isreg.Region.containsRegionends withreturn self.containsRegionInner(reg, tolerance).Those three account for five of the fifteen lines. The other ten I have not run, so please read them as places where a name is used with no binding pyflakes can see, not as ten more failures.
utils.py:115is at least dead:noNesting=Trueis passed nowhere insrcortests.The suite is green at this commit.
pytest --no-graphics -q -p no:randomly, afterpip install -e ".[test-full]", gives 1761 passed, 391 skipped, 1 xfailed, 0 failed in 669s. Three lines that raiseNameErrorwhen executed, and nothing red. The skip count depends on which optional simulators are installed.This class of defect has reached a user once already. Issue #189, October 2023: someone hit
NameError: name 'cubic_elem' is not definedinxodr_parser.py. The reply was "Unfortunately it wasn't detected by our test suite because we don't have an XODR file with that kind of curve in it." Three days laterea74a672, a one line change whose message is "Attempt bugfix, but new error pops up", corrected the name on theOpendriveParserbranch, and that branch never reachedmain. Onmainthe name survived until62da37a1deleted the surrounding block on 2026-05-15 as part of #467, which is about inconsistent planView lengths. That name is in v3.0.0, v3.1.0 and v3.1.1, and v3.1.1 went out eight days before it disappeared frommain. Running the same pyflakes command over the 3.1.1 sdist reports 16 rather than 15, and the extra one is:A check like this pays for itself on unfinished work, which is where it would run. PR #487, "[WIP] Various Improvements", is an open draft, head
cefd7ec3, last commit dated 2026-07-27. Nothing there is finished and I am not treating it as a bug report. Sweeping it with the same command is just what a commit hook would have done: that branch fixescontainsRegionInner(line 2741 there usesreg), still carries thecrossone, and has two new ones:PointSetRegion.closestPointTo(self, target)there beginspoint = toVector(point).coordinates, which is the first line ofdistanceTodirectly above it.closestPointToappears nowhere insrconmain, so that method is new. A hook would have flagged both at the commit that wrote them rather than at review or after a merge.A check that catches all 15:
pre-commit run --all-fileswith that config, on a clean checkout of 2fc1634, ends withFound 15 errors.and they are the same 15.Both extra arguments are load bearing, and I only found that out by running it. All four combinations, same command, same clean checkout:
files: ^src/--target-version py311The 359 is 44 F821 plus 315
invalid-syntax, the latter frommatchstatements intests/that ruff refuses to parse becausepyproject.toml:20setsrequires-python = ">=3.8". Of the 43, 27 are intests/and 26 of those are intests/syntax/polychrome.py.--target-version py311is doing two separate jobs, and I would not suggest it as a project setting since it contradictstox.ini'spy38throughpy314. Withoutfiles: ^src/it is what lets ruff parse your test files at all. Withfiles: ^src/it is still what keeps the count at 15 rather than 16: the extra one iscore/errors.py:158BaseExceptionGroup, which ruff flags correctly underrequires-python = ">=3.8"even though the line is guarded bysys.version_info >= (3, 11)at runtime. If you would rather not pin a version in the hook,# noqa: F821on that line gets the same 15. I checked that:files: ^src/,args: [--select, F821],noqaadded,Found 15 errors.The existing 15 need a decision either way. pre-commit runs on changed files, so the hook does not report them by itself. What it does is hand the next person who touches
regions.pyorroads.pya failing commit for a line they did not write.If you would rather have three separate bug reports and no process argument, say so and close this.
Tail of the
-btraceback, which is 95 lines in full. Only the path prefix up to the checkout root is cut:Steps To Reproduce
The list of 15:
That prints the block above and takes a second or two here. The
grep -vdrops the 18veneer.py__all__entries.lazykw.scenic, for the traceback above:The other two, in Python:
All three behave the same on 3.1.1 from PyPI, at the same line numbers. No seed is needed, since all three fail before anything is sampled.
Nothing calls
Vector.cross:git grep -n '\.cross(' -- src testsreturns one hit and it isnumpy.crossatregions.py:2810.Issue Submission Checklist