-
Notifications
You must be signed in to change notification settings - Fork 362
rfc: Migrate most configs from setup.py to pyproject.toml #5962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
c7b2dc8 to
09420d5
Compare
|
Hi @PaulYuuu , we've dropped Python 3.8 so this may be a simpler task now. Let me know if you want to evolve this. |
Hello @clebergnu, thanks for the heads-up. Avocado has quite a few subprojects, so I’d like to confirm the exact scope of this PR before making updates. From my view, I hope we can split to much tasks, e.g. a PR for subprojects pyproject.toml, a PR for avocado pyproject, and one or more for some usage update? |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughWalkthroughProject-wide migration from setup.py to PEP 517/621 packaging and pip installs: add a top-level pyproject.toml, convert many plugins to pyproject.toml, simplify setup.py, update Makefiles, refactor CI/workflows to use python -m pip and python -m selftests.check, and move remote spawner logic into a new spawner module. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5962 +/- ##
==========================================
+ Coverage 73.46% 73.48% +0.01%
==========================================
Files 206 206
Lines 22487 22488 +1
==========================================
+ Hits 16521 16526 +5
+ Misses 5966 5962 -4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (6)
.github/workflows/push_ci.yml (1)
95-98: Drop--userfrom the editable install.The preceding
pip install -r requirements-dev.txtalready installs dependencies into the toolcache site-packages, so adding--userhere puts Avocado’s editable install under~/.local/libwhile its deps stay in the global site. That split setup makes reproducibility harder (and raises PATH warnings on the runner) without buying anything inside CI. Please install into the same environment as the dependencies instead:- - name: Avocado build - run: pip install -e . --user + - name: Avocado build + run: pip install -e ..github/workflows/setup.yml (1)
33-43: LGTM with optional consolidation suggestion.The migration from
setup.py install --usertopip install . --useris correct. The individual plugin installations are explicit and functional.Consider consolidating the plugin installations for brevity:
- - name: Installing plugins - run: | - pip install ./optional_plugins/golang --user - pip install ./optional_plugins/html --user - pip install ./optional_plugins/result_upload --user - pip install ./optional_plugins/resultsdb --user - pip install ./optional_plugins/robot --user - pip install ./optional_plugins/varianter_cit --user - pip install ./optional_plugins/varianter_pict --user - pip install ./optional_plugins/varianter_yaml_to_mux --user + - name: Installing plugins + run: | + for plugin in golang html result_upload resultsdb robot varianter_cit varianter_pict varianter_yaml_to_mux; do + pip install "./optional_plugins/$plugin" --user + doneoptional_plugins/ansible/pyproject.toml (1)
14-21: Document the rationale for Python-version-specific dependency constraints.The dependencies include specific version pinning for older Python versions:
cffi==1.17.1for Python < 3.10cryptography<46.0.0for Python < 3.10While these constraints suggest known compatibility issues, they should be documented. Consider:
- Adding comments in pyproject.toml explaining why these constraints exist
- Documenting in CHANGELOG or migration notes
- Linking to relevant upstream issues if these are workarounds
Add inline comments to explain the version constraints:
dependencies = [ "avocado-framework", + # cffi 1.17.1 is the last version compatible with Python 3.9 "cffi==1.17.1; python_version<'3.10'", "cffi; python_version>='3.10'", + # cryptography 46.0.0+ drops Python 3.9 support "cryptography<46.0.0; python_version<'3.10'", "pycparser", "ansible-core", ].github/actions/wheel/action.yml (2)
11-12: Consider using a user-local directory instead of /tmp.Installing to
/tmp/avocado_installworks but could have issues in some CI environments. Consider using a user-local directory for better isolation:- python3 -m pip install dist/*.whl -t /tmp/avocado_install - export PYTHONPATH=/tmp/avocado_install:$PYTHONPATH + python3 -m pip install dist/*.whl -t ~/.local/avocado_wheel_test + export PYTHONPATH=~/.local/avocado_wheel_test:$PYTHONPATH
13-15: Simplify the avocado invocation.The Python one-liner
python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())'is verbose and could be simplified. Since the wheel is installed, you should be able to invoke avocado directly.- python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())' run /bin/true - cd /tmp - python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())' run /bin/true + python3 -m avocado run /bin/true + # Test from a different directory to ensure imports work + (cd /tmp && python3 -m avocado run /bin/true)Note: If the wheel doesn't include console scripts, this approach verifies the module entry point works correctly.
examples/plugins/tests/magic/pyproject.toml (1)
1-25: LGTM! Consider adding package discovery configuration.The pyproject.toml structure is correct with proper entry points defined. The empty
[tool.setuptools.packages.find]section will use default discovery, which should work for a simple plugin structure.If you want to be explicit about package discovery, consider adding:
[tool.setuptools.packages.find] +include = ["avocado_magic*"]This ensures only the intended package is included and makes the configuration more explicit.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (58)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(10 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(5 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)setup.py(2 hunks)
💤 Files with no reviewable changes (8)
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
🧰 Additional context used
🪛 GitHub Actions: GH Actions
Makefile.gh
[error] 1-1: Command 'make -f Makefile.gh build-wheel check-wheel' failed. Wheel checks detected errors.
Makefile
[error] 1-1: Command 'make -f Makefile.gh build-wheel check-wheel' failed. Wheel checks detected errors.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (360)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
🔇 Additional comments (62)
.github/workflows/prerelease.yml (2)
28-28: LGTM! Modern packaging workflow adopted.The migration from
python3 setup.py develop --usertopip install -e . --useraligns with PEP 660 and modern Python packaging best practices, as directsetup.pyinvocation is deprecated.Also applies to: 49-49
51-51: LGTM! Test invocation moved to dedicated script.Moving test invocation from
setup.py testtoselftests/check.pyis correct, assetup.py testis deprecated and using a dedicated test runner provides better control and clarity.optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-49: LGTM! Plugin packaging configuration is well-structured.The pyproject.toml configuration follows modern Python packaging standards with proper build system declaration, dynamic version/readme handling, and correct entry point definitions. The structure is consistent with other plugins in the repository.
examples/plugins/README.rst (1)
11-24: LGTM! Documentation updated for modern packaging workflow.The documentation correctly reflects the migration to pip-based editable installs and includes helpful uninstall examples. The instructions are clear and align with current Python packaging best practices.
optional_plugins/resultsdb/setup.py (1)
2-6: LGTM! Setup.py simplified for transition period.The simplification to a bare
setup()call is correct, as packaging configuration is now inpyproject.toml. The comment clearly explains that the file is retained for egg building compatibility during the transition period.optional_plugins/varianter_yaml_to_mux/setup.py (1)
2-6: LGTM! Setup.py simplified for transition period.The simplification to a bare
setup()call is correct, as packaging configuration has been moved to the accompanyingpyproject.toml. The comment clearly explains the file is retained for backward compatibility during the transition period.optional_plugins/ansible/setup.py (1)
2-6: LGTM! Setup.py simplified for transition period.The simplification to a bare
setup()call is correct, with packaging configuration now inpyproject.toml. The comment appropriately explains that the file is kept for egg building compatibility during the transition.Makefile.gh (1)
66-68: Verify all plugins have pyproject.toml before removing conditionals.The removal of conditional checks for
setup.pyexistence means the build will unconditionally attempt to build packages in all plugin directories. This assumes every plugin has a validpyproject.toml. The pipeline failure indicates wheel checks detected errors, which could be caused by missing or misconfiguredpyproject.tomlfiles in some plugins.Run the following script to verify all plugins have proper pyproject.toml configuration:
Also applies to: 79-81
optional_plugins/varianter_cit/setup.py (1)
1-6: LGTM! Proper backward compatibility pattern.The bare
setup()call correctly delegates all configuration topyproject.toml, maintaining backward compatibility for tools that still invokepython setup.pycommands during the transition period.optional_plugins/varianter_cit/pyproject.toml (3)
31-35: LGTM! Entry points correctly configured.The plugin entry points are properly structured for both CLI and varianter functionality:
- CLI registration under
avocado.plugins.cli- Varianter registration under
avocado.plugins.varianter
7-7: Verify dynamic content source files exist.The configuration declares
versionandreadmeas dynamic, sourced from files at lines 44-45.Ensure that
VERSIONandREADME.rstfiles exist in theoptional_plugins/varianter_cit/directory:
13-13: Verify Python version requirement consistency.The Python requirement is set to
>=3.9. According to the PR comments, Python 3.8 has been dropped from the project.Verify this is consistent with the project's overall Python version requirements:
optional_plugins/README.rst (2)
10-24: LGTM! Documentation correctly reflects modern pip-based workflow.The updated instructions properly document:
- Using
pip install -efor development installation- Using
pip uninstallwith the full package name for removal- Providing concrete examples for common plugins
26-34: LGTM! Updated make targets align with new workflow.The documentation correctly introduces the new make targets for plugin development:
make develop-pluginsfor all pluginsmake develop-plugin PLUGIN=htmlfor specific pluginsVerify these make targets exist in the Makefile:
optional_plugins/spawner_remote/setup.py (1)
1-6: LGTM! Consistent backward compatibility pattern.This follows the same backward compatibility approach as other plugins in the PR, properly delegating configuration to
pyproject.toml.optional_plugins/varianter_pict/setup.py (1)
1-6: LGTM! Proper backward compatibility maintained.Consistent with the migration strategy across all optional plugins, this setup.py correctly delegates to
pyproject.tomlwhile maintaining backward compatibility.examples/plugins/cli-cmd/hello_priority/pyproject.toml (1)
1-14: LGTM! Standard pyproject.toml structure for a CLI plugin.The configuration follows the modern pyproject.toml format correctly:
- Build system is properly configured with setuptools and wheel
- Project metadata is clear and concise
- Entry point registration syntax is correct
- Module packaging configuration matches the entry point
However, ensure that the
hello_priority.pymodule file exists in this directory and contains aHelloWorldclass, as referenced in the entry point.examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM! Consistent structure with other CLI plugin configurations.The configuration properly mirrors the structure used in
hello_priority/pyproject.toml, maintaining consistency across example plugins.Verify that the
hello_parser.pymodule exists and contains theHelloWorldclass:examples/plugins/tests/rogue/pyproject.toml (1)
10-11: Verify script entry point module structure.The script entry point references
avocado_rogue.runner:main, but line 20 declares this as apy-modules(single module file) rather than a package.Verify whether
avocado_rogueis a single-file module or a package:If it's a package (directory with
__init__.py), the configuration should use[tool.setuptools.packages.find]instead ofpy-modules. If it's a single file namedavocado_rogue.py, then the entry point syntaxavocado_rogue.runner:mainis incorrect—it should beavocado_rogue:main.examples/plugins/test-pre-post/hello/pyproject.toml (3)
1-3: LGTM!Standard and correct build system configuration using setuptools and wheel.
16-17: LGTM!Correct configuration for packaging a single Python module.
10-14: Verify thatHelloWorldclass supports both pre and post phases.Both entry points map to the same class
hello:HelloWorld. Ensure that this class is designed to handle both pre-test and post-test execution contexts appropriately.Run the following script to examine the HelloWorld class implementation:
optional_plugins/golang/pyproject.toml (3)
28-38: LGTM!Entry points are correctly configured for script installation and plugin registration.
40-48: LGTM!Setuptools configuration correctly enables package data inclusion and uses appropriate package discovery pattern with dynamic field configuration.
1-26: LGTM!Well-structured project metadata with appropriate use of dynamic fields for version and readme. The Python version requirement (>=3.9) aligns with the project's stated drop of Python 3.8 support.
Verify that the VERSION and README.rst files exist:
.github/workflows/setup.yml (4)
73-83: LGTM!System-wide installation correctly uses
pip install .without the--userflag.
115-125: LGTM!Development installation correctly uses editable mode (
pip install -e .), and the test command properly switches to direct invocation ofselftests/check.py.
183-191: LGTM!Virtualenv installation correctly omits the
--userflag and properly installs the framework and plugins.
216-219: LGTM!Development virtualenv correctly uses editable install and runs the test suite with appropriate skip flags.
optional_plugins/mail/pyproject.toml (1)
1-44: LGTM!The pyproject.toml configuration is well-structured and follows the same pattern as other optional plugins in this migration. Entry points for initialization and job pre/post hooks are appropriately configured for a mail notification plugin.
optional_plugins/mail/setup.py (1)
1-6: LGTM! Excellent transitional approach.Simplifying setup.py to a bare
setup()call while moving configuration to pyproject.toml is the recommended migration pattern. The explanatory comment clearly communicates the transition state.Makefile (6)
9-10: LGTM!Clear documentation for the new plugin development targets.
34-61: LGTM!The expanded clean target is comprehensive and includes proper cleanup for optional plugins and example plugins. Error handling with
|| trueensures robustness, and user feedback via echo statements improves the experience.
64-67: LGTM!Proper migration to pip-based installation and uninstallation commands.
112-119: LGTM!Excellent error handling for the man page generation with fallback to
rst2man.pyifrst2manis not available, and a clear error message if neither tool is found.
83-108: LGTM with observation.The new development targets provide good flexibility for plugin development workflows. Note that
developanddevelop-coretargets are currently identical (lines 83 and 85-86), which may be intentional for compatibility or future differentiation.Verify if
developanddevelop-coreare intentionally identical or if there are plans to differentiate them:
1-129: Pipeline failure: Wheel building errors detected.The GitHub Actions pipeline reports a failure with wheel building via
make -f Makefile.gh build-wheel check-wheel. This likely relates to the pyproject.toml migration and needs investigation to ensure the new packaging configuration produces valid wheels.Investigate the wheel building failure:
optional_plugins/resultsdb/pyproject.toml (2)
33-40: LGTM!Entry points for CLI, result events, and result handling are correctly configured for the ResultsDB plugin.
42-50: LGTM!Setuptools configuration follows the standard pattern with appropriate dynamic field handling and package discovery.
optional_plugins/result_upload/pyproject.toml (1)
1-45: LGTM!The pyproject.toml configuration is well-structured and consistent with the migration pattern used across other optional plugins. All metadata, dependencies, entry points, and dynamic fields are correctly configured.
optional_plugins/result_upload/setup.py (1)
1-6: LGTM! Clean migration pattern.The transition to a bare
setup()call with explanatory comments is a clean approach for maintaining backward compatibility during the pyproject.toml migration..github/workflows/weekly.yml (2)
39-39: LGTM! Correct migration to pip-based editable install.The change from
python3 setup.py develop --usertopip install -e . --useraligns with modern Python packaging best practices and the deprecation of direct setup.py invocation.
83-83: LGTM! Consistent with the migration pattern.This change matches the update on line 39, ensuring consistent installation across all workflow jobs.
optional_plugins/html/setup.py (1)
1-6: LGTM! Consistent migration pattern.This follows the same clean migration pattern as other plugins, maintaining backward compatibility during the transition to pyproject.toml.
optional_plugins/golang/setup.py (1)
1-6: LGTM! Consistent migration pattern.This follows the same clean migration pattern used across all plugins, maintaining backward compatibility with a bare
setup()call while configuration moves to pyproject.toml.python-avocado.spec (2)
8-18: Verify the naming change is applied consistently.The macro change from
avocado-%{version}.tar.gztoavocado_framework-%{version}.tar.gzis a significant naming update. Ensure this naming convention is consistent across:
- Source tarball generation scripts
- Release automation
- Download URLs referenced in documentation
- CI/CD pipelines
Run the following script to verify consistent naming:
243-272: Verify the exclusion patterns match the actual installed packages.The added exclusions for
contrib*,scripts*, and various plugin packages ensure clean package separation. However, confirm that:
- All excluded patterns actually exist in the installation
- No legitimate core packages are accidentally excluded
- The conditional exclusions for RHEL/Fedora align with the availability of those plugins
Run the following script after a test build to verify exclusions:
optional_plugins/ansible/pyproject.toml (1)
48-49: Verify the VERSION file exists and is tracked.The dynamic version reads from a
VERSIONfile. Ensure:
- The file exists at
optional_plugins/ansible/VERSION- It's tracked in git
- It's included in source distributions
optional_plugins/robot/setup.py (1)
2-6: LGTM!The migration to a minimal
setup()call is the correct approach for transitioning to pyproject.toml-based packaging. The comments clearly explain the backward compatibility purpose during the transition period..github/workflows/ci.yml (11)
28-32: LGTM!The migration from
python3 setup.py develop --usertopip install -e . --userand frompython3 setup.py testtopython3 selftests/check.pycorrectly modernizes the CI workflow to use pip-based installation and direct test invocation.
95-99: LGTM!Consistent migration to pip-based installation and direct test script invocation.
135-135: LGTM!Consistent with the pip-based installation approach used elsewhere in the workflow.
171-171: LGTM!Consistent with the pip-based installation approach used elsewhere in the workflow.
359-383: LGTM!The job renames from
egg_task_fedora_*towheel_task_fedora_*and the dependency updates frompython3-setuptoolstopython3-pipcorrectly reflect the migration to wheel-based packaging. The use of./.github/actions/wheelaction aligns with the new packaging approach.
398-409: LGTM!The job rename from
egg_task_ubi_9towheel_task_ubi_9and the dependency update topython3-pipare consistent with the wheel-based packaging migration.
411-422: LGTM!Consistent wheel task migration for Debian 12.
437-461: LGTM!The wheel task migrations for Ubuntu 24.04 and 22.04 are consistent with the pattern used in other distribution-specific jobs.
487-497: LGTM!The migration to pip-based installation for both the main framework and the example plugin is correct and consistent.
509-519: Verify the cleanup and reinstallation sequence.Line 515 removes build artifacts (
rm -rf build/ dist/ *.egg-info) between uninstall and reinstall operations. Ensure that:
- The cleanup doesn't interfere with pip's internal state or cause issues on subsequent installs.
- All necessary artifacts are properly regenerated on the subsequent
pip install -e .at line 516.
472-476: Verify the egg path generation and usage.Line 474 generates the egg path dynamically using
ls dist/avocado_framework-*.egg. Ensure this glob pattern correctly matches the generated egg filename format, especially if the version format or naming convention changes.Run the following script to verify the egg naming pattern:
optional_plugins/html/pyproject.toml (1)
1-48: Verify the dynamic file references and dependency versions.The pyproject.toml configuration looks well-structured, but please verify:
- Dynamic file references (lines 47-48): Ensure that
VERSIONandREADME.rstfiles exist in theoptional_plugins/html/directory, as setuptools will look for them relative to the pyproject.toml location.- jinja2 dependency (line 16): Consider pinning or constraining the jinja2 version to avoid potential compatibility issues with future major releases (e.g.,
jinja2>=2.0,<4.0).Run the following script to verify the file existence:
optional_plugins/robot/pyproject.toml (1)
1-49: Verify dynamic file references, package structure, and dependency constraints.The pyproject.toml configuration is well-structured, but please verify:
- Dynamic file references (lines 48-49): Ensure that
VERSIONandREADME.rstfiles exist in theoptional_plugins/robot/directory.- robotframework version constraint (line 16): The constraint
robotframework>=4.1, <7.0excludes robotframework 7.0+. Verify that this constraint is intentional and that there are known compatibility issues with robotframework 7.0+, or consider relaxing it to allow future minor versions (e.g.,<8.0).- Package finding pattern (line 45): The pattern
avocado_robot*will include all packages starting withavocado_robot. Verify that this matches the actual package structure and doesn't inadvertently include unintended packages.Run the following scripts to verify:
| dependencies = [ | ||
| "setuptools", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restore the project’s runtime dependencies
[project].dependencies now contains only "setuptools", but the core package still imports third-party modules (for example, avocado.plugins.sysinfo imports psutil, avocado.utils.asset imports requests, and the varianter plugins rely on jsonschema). These were previously declared in install_requires; without them, pip install avocado-framework succeeds yet the package immediately raises ImportError when those modules are loaded. Please port the full dependency list from the former setup.py into this section (group purely optional items under extras if needed) so end users receive the required packages on installation.
🤖 Prompt for AI Agents
In pyproject.toml around lines 14 to 16, the project runtime dependencies were
reduced to just "setuptools", causing ImportError at runtime; restore the full
list that used to be in setup.py by populating [project].dependencies with all
required packages (e.g., psutil, requests, jsonschema and any other entries from
the former install_requires) as PEP-621 string entries so pip installs them;
move purely optional/extra features into [project.optional-dependencies] groups
(extras) and ensure build-system still declares setuptools only if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (2)
pyproject.toml (2)
5-29: Restore required runtime dependencies before release.
[project].dependenciesis empty, so a freshpip install avocado-frameworkpulls no third-party modules. The codebase still imports non-stdlib packages (e.g.psutilinavocado.plugins.sysinfo,requestsinavocado.utils.asset,jsonschemain varianter plugins). This regresses immediately withImportError. Please port the fullinstall_requireslist from the previoussetup.py(splitting optional bits into extras as needed) so users receive the necessary dependencies.
14-29: Remove the unsupported Python 3.14 classifier.PyPI rejects uploads containing
Programming Language :: Python :: 3.14, because that trove classifier has not been published yet. Drop it for now and re-add only once PyPI exposes the official classifier.
🧹 Nitpick comments (5)
optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-49: Pin PyYAML to a stable release
ReplacePyYAML>=4.2b2withPyYAML>=5.4.1(latest stable patch: 6.0.3).examples/plugins/tests/rogue/pyproject.toml (1)
7-7: Consider dynamic version management.The version is hardcoded to "1.0". For consistency with other plugins in the repository that use dynamic version loading from a VERSION file, consider updating this configuration.
Example pattern from other plugins:
[project] name = "avocado-rogue" dynamic = ["version"] description = "Avocado \"rogue\" test type" [tool.setuptools.dynamic] version = {file = "VERSION"}examples/plugins/tests/magic/pyproject.toml (1)
7-7: Consider dynamic version management.The version is hardcoded to "1.0". For consistency with other plugins in the repository that use dynamic version loading from a VERSION file, consider updating this configuration.
Example pattern from other plugins:
[project] name = "magic" dynamic = ["version"] description = "Avocado \"magic\" test type" [tool.setuptools.dynamic] version = {file = "VERSION"}examples/plugins/test-pre-post/hello/pyproject.toml (1)
7-7: Consider dynamic version management.The version is hardcoded to "1.0". For consistency with other plugins in the repository that use dynamic version loading from a VERSION file, consider updating this configuration.
Example pattern from other plugins:
[project] name = "avocado-hello-world-pre-post-test" dynamic = ["version"] description = "Avocado Hello World pre and post test plugin" [tool.setuptools.dynamic] version = {file = "VERSION"}optional_plugins/robot/pyproject.toml (1)
14-17: Remove redundant environment marker.The environment marker
python_version >= '3.9'on Line 16 is redundant because Line 13 already specifiesrequires-python = ">=3.9". When the package is installed, the Python version will always satisfy this condition.Apply this diff to simplify the dependency:
dependencies = [ "avocado-framework", - "robotframework>=4.1, <7.0; python_version >= '3.9'", + "robotframework>=4.1, <7.0", ]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (63)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(9 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(3 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(5 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)setup.py(2 hunks)
💤 Files with no reviewable changes (9)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/test-pre-post/hello/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_yaml_to_mux/README.rst
🚧 Files skipped from review as they are similar to previous changes (22)
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- .github/workflows/vmimage.yml
- selftests/pre_release/tests/check-copr-rpm-version.sh
- optional_plugins/varianter_pict/setup.py
- examples/plugins/README.rst
- optional_plugins/ansible/pyproject.toml
- examples/plugins/tests/README.rst
- .github/actions/version/action.yml
- optional_plugins/varianter_pict/pyproject.toml
- python-avocado.spec
- .github/actions/wheel/action.yml
- optional_plugins/golang/pyproject.toml
- docs/source/guides/writer/chapters/subclassing.rst
- examples/plugins/job-pre-post/sleep/pyproject.toml
- Makefile.gh
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/result_upload/setup.py
- .github/workflows/prerelease.yml
- examples/plugins/cli-cmd/hello/pyproject.toml
- .github/workflows/push_ci.yml
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (1)
Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (43)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Linux with Python 3.11
- GitHub Check: Linux with Python 3.12
- GitHub Check: Linux with Python 3.13
- GitHub Check: Linux with Python 3.9
- GitHub Check: Linux with Python 3.10
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: macOS with Python 3.11
🔇 Additional comments (31)
.github/workflows/release.yml (1)
134-136: LGTM!Using
python3 -m pipinstead ofpipdirectly is best practice, as it ensures the correct Python interpreter's pip is invoked. The conditional setuptools version constraint for Python >3.11 is retained appropriately.docs/source/guides/contributor/chapters/environment.rst (1)
55-62: LGTM! Documentation accurately reflects modern packaging practices.The update from
python setup.py developtopip install -e .aligns with the deprecation of direct setup.py invocations. The terminology updates ("editable install" and "egg info directory") are accurate and reflect current Python packaging conventions.optional_plugins/robot/setup.py (1)
1-6: LGTM! Clean migration to pyproject.toml.The minimal setup.py with a clear transitional comment is the recommended pattern for pyproject.toml migration while maintaining backward compatibility for egg builds. The comment clearly indicates that pyproject.toml is now the primary configuration source.
optional_plugins/varianter_yaml_to_mux/setup.py (1)
1-6: LGTM! Consistent migration pattern.This follows the same clean migration pattern as other optional plugins, maintaining backward compatibility while delegating to pyproject.toml.
optional_plugins/README.rst (1)
8-34: LGTM! Clear and consistent instructions.The updated installation and uninstallation instructions properly reflect the pip-based workflow. The examples for both individual plugins (html, ansible) and the Makefile targets are helpful and accurate.
optional_plugins/ansible/setup.py (1)
1-6: LGTM! Consistent migration pattern.This follows the same clean migration pattern as other optional plugins.
docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM! Documentation updated to reflect pyproject.toml workflow.The changes correctly guide developers to use pyproject.toml for plugin registration instead of setup.py, and to use
pip install -e .for development installation. This aligns with modern Python packaging standards.
111-114: LGTM! Entry points examples properly updated to TOML format.The Job Pre/Post plugin entry points example correctly demonstrates the TOML syntax for registering plugins in pyproject.toml.
170-173: LGTM! Settings plugin entry points example updated correctly.The settings plugin registration example properly shows the TOML syntax for extending configuration paths.
325-327: LGTM! Test type plugin examples consistently updated.The magic test plugin example references are updated to use pyproject.toml and pip-based installation, maintaining consistency with the rest of the documentation.
optional_plugins/varianter_cit/setup.py (1)
2-6: LGTM! Transitional approach is appropriate.The bare
setup()call with the explanatory comment correctly delegates packaging configuration to pyproject.toml while maintaining backward compatibility.examples/plugins/tests/rogue/pyproject.toml (1)
1-20: LGTM! Plugin packaging configuration is correct.The pyproject.toml configuration properly defines the build system, project metadata, script entry points, and plugin entry points for the rogue test type.
optional_plugins/golang/setup.py (1)
2-6: LGTM! Transitional approach is appropriate.The bare
setup()call with the explanatory comment correctly delegates packaging configuration to pyproject.toml while maintaining backward compatibility.examples/plugins/tests/magic/pyproject.toml (1)
1-25: LGTM! Plugin packaging configuration is correct.The pyproject.toml configuration properly defines the build system, project metadata, and multiple plugin entry points for the magic test type (init, resolver, discoverer, and runnable.runner).
examples/plugins/test-pre-post/hello/pyproject.toml (1)
1-17: LGTM! Plugin packaging configuration is correct.The pyproject.toml configuration properly defines the build system, project metadata, and test pre/post hook entry points.
optional_plugins/mail/pyproject.toml (1)
1-44: LGTM! Comprehensive plugin packaging configuration.The pyproject.toml configuration is well-structured with:
- Proper dynamic version and readme loading from VERSION and README.rst files
- Comprehensive project metadata including license, authors, and classifiers
- Correct Python version requirement (>=3.9)
- Appropriate dependency on avocado-framework
- Properly defined plugin entry points for initialization and job pre/post hooks
optional_plugins/mail/setup.py (1)
2-6: LGTM! Transitional approach is appropriate.The bare
setup()call with the explanatory comment correctly delegates packaging configuration to pyproject.toml while maintaining backward compatibility.Makefile (6)
9-10: LGTM! Clear documentation for new plugin development targets.The help text clearly explains the new
develop-pluginsanddevelop-plugintargets, making it easy for developers to understand how to install plugins.
33-61: LGTM! Comprehensive cleanup implementation.The enhanced clean target now properly handles:
- Build artifacts and caches
- Optional plugins cleanup
- Example plugins cleanup
- User-friendly progress messages
The implementation correctly uses shell loops and error suppression to handle missing directories gracefully.
64-67: LGTM! Proper migration to pip-based workflows.The install and uninstall targets correctly use
$(PYTHON) -m pipinstead of calling setup.py directly, aligning with modern Python packaging practices.
82-107: LGTM! Well-designed plugin development targets.The new development targets provide:
develop: Core framework installationdevelop-core: Explicit core-only installationdevelop-plugins: Batch installation of all optional pluginsdevelop-plugin: Selective installation with PLUGIN parameterAll correctly use pip editable installs (
-e) and include proper error handling for missing parameters.
112-119: LGTM! Robust man page generation with fallback.The conditional logic properly checks for both
rst2manandrst2man.pycommands, providing good cross-platform compatibility with clear error messaging if neither is available.
129-129: Ignore the static analysis warning about missing "all" target.The checkmake warning is a false positive—the "all" target is defined at line 1 of the Makefile. The warning about a missing "test" target may be a recommendation rather than a requirement, and its absence doesn't indicate an issue with the current changes.
optional_plugins/resultsdb/pyproject.toml (1)
1-49: LGTM! Configuration is clean and well-structured.The pyproject.toml configuration is correct and follows the standard pattern for Avocado plugins. The previous concern about the impossible
urllib3constraint has been resolved—the dependency list is now clean and minimal.optional_plugins/resultsdb/setup.py (1)
1-6: LGTM! Proper transition approach.The minimal setup.py with a bare
setup()call and clear documentation is the correct approach for maintaining backward compatibility during the migration to pyproject.toml.optional_plugins/result_upload/pyproject.toml (1)
1-45: LGTM! Clean plugin configuration.The configuration follows the standard pattern and correctly defines the result upload plugin with appropriate entry points and dependencies.
.github/workflows/weekly.yml (2)
37-47: LGTM! Properly modernized to pip-based workflows.The changes correctly migrate from deprecated
setup.py developto modernpip install -e .and invoke selftests as a module. This aligns with current Python packaging best practices.
81-89: LGTM! Consistent migration in the second job.The changes are consistent with the first job and properly modernize the workflow to use pip-based installation and module invocation.
optional_plugins/html/setup.py (1)
1-6: LGTM! Consistent transition pattern.This follows the same correct approach as other plugins in maintaining backward compatibility during the migration to pyproject.toml.
setup.py (1)
16-38: LGTM! Well-documented migration strategy.The minimal setup.py is well-structured with clear documentation explaining its purpose. Providing only
nameandversionfor egg builds while deferring all other configuration to pyproject.toml is the correct approach for this migration.optional_plugins/spawner_remote/pyproject.toml (1)
1-46: LGTM! Entry point paths are now correct.The configuration is properly structured. The previous issue with missing
.spawnermodule component in entry point paths has been resolved—both entry points now correctly referenceavocado_spawner_remote.spawnermodule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
♻️ Duplicate comments (4)
optional_plugins/golang/setup.py (1)
1-1: Fix the shebang path.The shebang should use
/usr/bin/envinstead of/bin/envfor better portability across systems.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/varianter_cit/setup.py (1)
1-1: Fix the shebang path.The shebang should use
/usr/bin/envinstead of/bin/envfor better portability across systems.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3.github/workflows/ci.yml (1)
169-169: Fix broken Windows setuptools fallback.
python -m python3 -m pip …tries to import a module namedpython3and crashes (ModuleNotFoundError), so setuptools is never installed on Windows ≥3.12. Keep the existing probe but call pip viapython -m pipinstead.- run: python -c 'import setuptools' || python -m python3 -m pip install "setuptools<80" + run: python -c 'import setuptools' || python -m pip install "setuptools<80"optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
195-201: [Duplicate] Use per-task remote output directories to avoid data corruption.This issue was previously identified: every task uses the same hardcoded path
/tmp/.avocado_task_output_dir, causing concurrent tasks to overwrite each other's results.Apply the previously suggested fix:
- output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = runtime_task.task.identifier.replace("/", "_") + output_lxc_path = os.path.join("/tmp", f".avocado-task-{safe_id}")
🧹 Nitpick comments (4)
optional_plugins/robot/pyproject.toml (1)
14-16: Consider minor style improvement in version specifier.The dependency specification is valid. However, the space after the comma in
"robotframework>=4.1, <7.0; python_version >= '3.9'"is unconventional. Consider writing it as"robotframework>=4.1,<7.0; python_version >= '3.9'"for consistency with common Python packaging style, though both forms are technically correct per PEP 440.Makefile (1)
94-101: Optionally add failure handling for plugin installs.If any plugin install fails the loop continues silently and the target exits 0. Consider adding
set -eor testing the exit status inside the loop so CI/devs notice broken plugins immediately.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
73-74: Annotate mutable class attributes withClassVar.The
slots_cachedictionary is intentionally shared across all instances but should be annotated withtyping.ClassVarto make this intent explicit and satisfy type checkers.Apply this diff:
+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + slots_cache: ClassVar[dict] = {}
208-216: Fix f-string and uselogging.exceptionfor better error context.Line 215 is missing the
fprefix, and usinglogging.exceptioninstead oflogging.errorwithin an exception handler provides automatic traceback information.Apply this diff:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}") return False
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(9 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(5 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)setup.py(2 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/tests/magic/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/tests/rogue/setup.py
✅ Files skipped from review due to trivial changes (3)
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/ansible/README.rst
🚧 Files skipped from review as they are similar to previous changes (31)
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- .github/workflows/weekly.yml
- selftests/pre_release/tests/check-copr-rpm-version.sh
- optional_plugins/spawner_remote/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/setup.py
- docs/source/guides/contributor/chapters/plugins.rst
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- Makefile.gh
- optional_plugins/resultsdb/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- optional_plugins/varianter_pict/pyproject.toml
- examples/plugins/tests/README.rst
- optional_plugins/ansible/pyproject.toml
- .github/actions/wheel/action.yml
- examples/plugins/test-pre-post/hello/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- optional_plugins/spawner_remote/setup.py
- examples/plugins/README.rst
- .github/actions/version/action.yml
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- optional_plugins/mail/pyproject.toml
- pyproject.toml
- .github/workflows/push_ci.yml
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/tests/rogue/pyproject.toml
- optional_plugins/golang/pyproject.toml
- python-avocado.spec
- optional_plugins/mail/setup.py
- docs/source/guides/contributor/chapters/environment.rst
- .github/workflows/release.yml
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (44)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Linux with Python 3.10
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: Linux with Python 3.12
- GitHub Check: Linux with Python 3.11
- GitHub Check: Linux with Python 3.13
- GitHub Check: Linux with Python 3.9
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Wheel task ubuntu:22.04
- GitHub Check: macOS with Python 3.11
🔇 Additional comments (27)
spell.ignore (1)
806-807: LGTM! Appropriate additions for the pyproject.toml migration.Adding "pyproject" and "toml" to the spell-checker ignore list is necessary and appropriate given the PR's objective to migrate packaging configuration to pyproject.toml files across the codebase. These technical terms will now appear frequently in documentation, code comments, and configuration files.
.github/workflows/vmimage.yml (1)
40-42: LGTM! Modern packaging commands adopted.The migration from
setup.py developtopython3 -m pip install -e .and explicitpython3 -m pipinvocations align with modern Python packaging best practices and the pyproject.toml-based configuration introduced in this PR..github/workflows/prerelease.yml (2)
25-28: LGTM! Workflow migrated to pip-based development.The replacement of
setup.py developwithpython3 -m pip install -e . --userand explicitpython3 -m pipinvocations align with modern Python packaging practices and the pyproject.toml migration.
48-51: LGTM! Test invocation modernized.The migration from
setup.py testtopython3 -m selftests.checkand pip-based installation aligns with the repository's shift to pyproject.toml-based packaging and modern test infrastructure.optional_plugins/golang/setup.py (1)
2-6: LGTM! Transitional setup.py delegates to pyproject.toml.The bare
setup()call correctly delegates packaging configuration topyproject.toml, and the transitional comment clearly explains the purpose of retaining this file for egg-building compatibility.setup.py (1)
16-39: LGTM! Well-designed transitional setup.py.This minimal setup.py provides excellent backward compatibility:
- Clear docstring explaining the transitional nature
- Reads VERSION for egg builds that don't fully support pyproject.toml
- Minimal implementation (name + version only) delegates other configuration to pyproject.toml
- Maintains compatibility with legacy tools while embracing modern packaging standards
The approach balances backward compatibility with the shift to PEP 517-based builds.
optional_plugins/ansible/setup.py (1)
2-6: LGTM! Transitional setup.py delegates to pyproject.toml.The bare
setup()call correctly delegates packaging configuration topyproject.toml, and the transitional comment clearly explains the purpose of retaining this file for egg-building compatibility.optional_plugins/varianter_cit/setup.py (1)
2-6: LGTM! Transitional setup.py delegates to pyproject.toml.The bare
setup()call correctly delegates packaging configuration topyproject.toml, and the transitional comment clearly explains the purpose of retaining this file for egg-building compatibility.optional_plugins/varianter_cit/pyproject.toml (1)
1-45: Approve pyproject.toml configuration
- Build system, project metadata, entry points, dynamic version/readme loading, and package discovery correctly defined
- VERSION and README.rst files confirmed present in optional_plugins/varianter_cit/ for dynamic loading
optional_plugins/resultsdb/setup.py (1)
2-6: pyproject.toml exists and is properly configured: includes required [build-system], [project], and [project.entry-points] sections.optional_plugins/varianter_pict/setup.py (1)
1-6: LGTM! Clean migration pattern.The transitional setup.py correctly delegates all configuration to pyproject.toml while maintaining backward compatibility. The explanatory comment is helpful.
docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: LGTM! Clear and accurate documentation.The updated example correctly demonstrates pyproject.toml-based packaging with proper structure including build-system, project metadata, dynamic versioning, and setuptools configuration.
88-101: LGTM! Modern installation instructions.The updated installation example correctly uses
pip install -e .(editable install) instead of the deprecatedsetup.py developapproach, aligning with modern Python packaging practices.optional_plugins/html/setup.py (1)
1-6: LGTM! Consistent migration pattern.The transitional setup.py follows the same clean pattern as other plugins in this migration.
optional_plugins/result_upload/setup.py (1)
1-6: LGTM! Consistent migration pattern.The transitional setup.py follows the established pattern for this migration.
optional_plugins/robot/setup.py (1)
1-6: LGTM! Consistent migration pattern.The transitional setup.py follows the established pattern, completing a consistent migration approach across all reviewed plugins.
optional_plugins/result_upload/pyproject.toml (1)
1-45: Approve plugin metadata and entry pointsVERSION and README.rst exist; build-system configuration, dependencies, and entry points are correctly defined.
optional_plugins/robot/pyproject.toml (1)
1-49: VERSION and README.rst present
Confirmed both files exist under optional_plugins/robot/, satisfying the dynamic entries. No further action required.optional_plugins/html/pyproject.toml (1)
1-48: VERSION and README.rst exist as expected.optional_plugins/README.rst (1)
10-34: Docs look good.Thanks for updating the plugin dev workflow to the new pip-based commands—everything lines up with the Makefile targets.
.github/workflows/setup.yml (1)
33-44: All good.Editable/user installs and per-plugin pip installs align with the new packaging workflow.
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (6)
1-14: LGTM!The imports are appropriate for remote spawner functionality. The use of
aexpectfor remote session management aligns with the library's intended purpose for test automation.
17-18: LGTM!The exception class is properly defined for spawner-specific errors.
21-46: LGTM!The configuration options are well-defined with appropriate defaults. The timeout values (1 hour for setup, 4 hours for tests) are reasonable for remote execution scenarios.
49-67: LGTM!The decorator properly manages slot reservation lifecycle using a context manager, ensuring slots are released even if errors occur.
79-90: LGTM!The async wrapper properly handles
aexpectexceptions and provides consistent error reporting.
218-233: LGTM!The requirement cache methods are correctly stubbed as no-ops, which is appropriate for a remote spawner that doesn't implement caching. The unused argument warnings from static analysis are false positives, as these parameters are required by the
Spawnerinterface.
| if len(RemoteSpawner.slots_cache) == 0: | ||
| # TODO: consider whether to provide persistence across runs via external storage | ||
| for session_slot in self.config.get("spawner.remote.slots"): | ||
| if not session_slot: | ||
| continue | ||
| with open(session_slot, "r", encoding="utf-8") as f: | ||
| session_data = json.load(f) | ||
| session = remote.remote_login(**session_data) | ||
| RemoteSpawner.slots_cache[session] = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for slot initialization.
Reading JSON configuration files and creating remote sessions can fail in multiple ways (malformed JSON, missing files, connection failures), but no error handling is present. A single bad slot configuration will crash the spawner initialization.
Apply this diff to add robust error handling:
if len(RemoteSpawner.slots_cache) == 0:
# TODO: consider whether to provide persistence across runs via external storage
for session_slot in self.config.get("spawner.remote.slots"):
if not session_slot:
continue
- with open(session_slot, "r", encoding="utf-8") as f:
- session_data = json.load(f)
- session = remote.remote_login(**session_data)
- RemoteSpawner.slots_cache[session] = False
+ try:
+ with open(session_slot, "r", encoding="utf-8") as f:
+ session_data = json.load(f)
+ session = remote.remote_login(**session_data)
+ RemoteSpawner.slots_cache[session] = False
+ except (FileNotFoundError, json.JSONDecodeError, KeyError) as e:
+ LOG.warning(f"Failed to initialize slot from {session_slot}: {e}")
+ except Exception as e:
+ LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if len(RemoteSpawner.slots_cache) == 0: | |
| # TODO: consider whether to provide persistence across runs via external storage | |
| for session_slot in self.config.get("spawner.remote.slots"): | |
| if not session_slot: | |
| continue | |
| with open(session_slot, "r", encoding="utf-8") as f: | |
| session_data = json.load(f) | |
| session = remote.remote_login(**session_data) | |
| RemoteSpawner.slots_cache[session] = False | |
| if len(RemoteSpawner.slots_cache) == 0: | |
| # TODO: consider whether to provide persistence across runs via external storage | |
| for session_slot in self.config.get("spawner.remote.slots"): | |
| if not session_slot: | |
| continue | |
| try: | |
| with open(session_slot, "r", encoding="utf-8") as f: | |
| session_data = json.load(f) | |
| session = remote.remote_login(**session_data) | |
| RemoteSpawner.slots_cache[session] = False | |
| except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: | |
| LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") | |
| except Exception as e: | |
| LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}") |
| ) | ||
| return False | ||
|
|
||
| cmd = shlex.join(entry_point_args) + " > /dev/null" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Output redirection loses all test results.
Redirecting output to /dev/null discards all test output, including results, logs, stdout, and stderr. This defeats the purpose of running tests remotely and makes debugging impossible.
Remove the output redirection or redirect to a file that can be retrieved:
- cmd = shlex.join(entry_point_args) + " > /dev/null"
+ cmd = shlex.join(entry_point_args)Or if you need to capture output remotely:
- cmd = shlex.join(entry_point_args) + " > /dev/null"
+ remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log"
+ cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cmd = shlex.join(entry_point_args) + " > /dev/null" | |
| cmd = shlex.join(entry_point_args) |
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around line
182 the command string currently appends " > /dev/null" which discards all
stdout/stderr (losing test results and logs); remove the output redirection or
replace it with safe capture: either omit " > /dev/null" so output is preserved,
or redirect to a file (e.g., a temp file path) that is collected and returned,
or pipe stdout/stderr into a capture mechanism (logging or subprocess capture)
so remote test output can be retrieved for debugging.
2795168 to
56fcda5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (6)
optional_plugins/ansible/setup.py (1)
1-1: Fix the shebang path.The shebang still uses
/bin/envinstead of/usr/bin/env, which can cause portability issues across different systems. Although this was previously flagged as addressed, the issue remains in the current code.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/varianter_cit/setup.py (1)
1-1: The shebang is still incorrect and likely unnecessary.The shebang continues to use
/bin/envinstead of the more portable/usr/bin/env. However, since this file is now a minimal shim for pyproject.toml-based packaging and is not intended to be executed directly (it's imported by build tools like pip and setuptools), the shebang may no longer be necessary and could be removed entirely.If the shebang must remain for backward compatibility, apply this diff to fix it:
-#!/bin/env python3 +#!/usr/bin/env python3Otherwise, consider removing the shebang entirely:
-#!/bin/env python3 -# This file is kept for egg building compatibility during the transition period. +# This file is kept for egg building compatibility during the transition period.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (4)
106-115: Add error handling around slot initialization.Malformed JSON or connection failures will crash the spawner.
if len(RemoteSpawner.slots_cache) == 0: # TODO: consider whether to provide persistence across runs via external storage for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
136-146: Shell-escape task identifier in pgrep.Avoid breakage/injection with special chars.
session = runtime_task.spawner_handle - status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output( + f"pgrep -r R,S -f {safe_identifier}" + )
182-185: Do not discard task output.Dropping stdout/stderr prevents debugging and may hide failures.
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)If you prefer remote capture:
+ remote_log = f"/tmp/avocado-task-{runtime_task.task.identifier.replace('/', '_')}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"
202-206: Add a timeout to the wait loop.Prevents hanging indefinitely if liveness never flips.
- async def wait_task(self, runtime_task): - while True: - if not RemoteSpawner.is_task_alive(runtime_task): - return - await asyncio.sleep(0.1) + async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() + while True: + if not RemoteSpawner.is_task_alive(runtime_task): + return + if asyncio.get_event_loop().time() - start_time > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return + await asyncio.sleep(0.1)
🧹 Nitpick comments (17)
selftests/pre_release/tests/check-copr-rpm-version.sh (2)
14-16: Source VERSION from origin/master for consistency, and hard‑fail if missing.Other metadata (date/commit) come from $ORIGIN/master; reading VERSION from the working tree can drift. Also, if VERSION is missing/empty the NVR becomes malformed and fails later without a clear message. Recommend:
- Try origin/master:VERSION first, fallback to local.
- Exit early with a clear error if still empty.
-VERSION=$(cat VERSION 2>/dev/null) +VERSION=$(git show "$ORIGIN/master:VERSION" 2>/dev/null || cat VERSION 2>/dev/null) +if [ -z "$VERSION" ]; then + echo "ERROR: VERSION not found (checked $ORIGIN/master and working tree)" >&2 + exit 1 +fi
23-26: Guard container runtime detection.If neither podman nor docker is installed, $PODMAN is empty and the script errors cryptically. Add a check with a clear message.
-PODMAN=$(which podman 2>/dev/null || which docker) +PODMAN=$(command -v podman 2>/dev/null || command -v docker 2>/dev/null) +if [ -z "$PODMAN" ]; then + echo "ERROR: Neither podman nor docker found in PATH" >&2 + exit 1 +fiexamples/plugins/tests/rogue/pyproject.toml (1)
5-9: Add requires-python to match the project’s supported versions.Given 3.8 was dropped, declare the minimum supported version (likely >=3.9).
[project] name = "avocado-rogue" version = "1.0" description = "Avocado \"rogue\" test type" +requires-python = ">=3.9"optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
29-30: Consider using HTTPS for the homepage URL.The homepage URL uses
http://instead ofhttps://. GitHub Pages typically supports HTTPS, which provides better security.Apply this diff if the site supports HTTPS:
[project.urls] -Homepage = "http://avocado-framework.github.io/" +Homepage = "https://avocado-framework.github.io/"optional_plugins/golang/pyproject.toml (6)
1-3: Setuptools minimum version: ensure features are supported[project.scripts] and [tool.setuptools.dynamic] should be supported by the declared minimum. Suggest bumping to a safer floor (e.g., 61.3+) to avoid edge cases.
If you keep 61.0, please confirm it works across your CI matrix.
12-12: License metadata: prefer SPDX or file referenceUsing license.text = "GPLv2+" is non-standard. Prefer SPDX identifier or the license file.
Apply one of:
-license = {text = "GPLv2+"} +license = {text = "GPL-2.0-or-later"}or (recommended if a license file exists in this plugin dir):
-license = {text = "GPLv2+"} +license = {file = "LICENSE"}Please confirm the actual license file name/path (LICENSE/COPYING) in this subproject.
15-16: Add a lower bound on avocado-frameworkPin a minimal compatible core version to prevent incompatible installs.
Example:
-dependencies = [ - "avocado-framework", -] +dependencies = [ + "avocado-framework>=X.Y", +]What is the minimal Avocado version required by this plugin? Let's set it explicitly.
17-26: Optional: be explicit about supported Python versionsAdd concrete Python classifiers for better PyPI metadata.
Example additions:
- Programming Language :: Python :: 3.9
- Programming Language :: Python :: 3.10
- Programming Language :: Python :: 3.11
- Programming Language :: Python :: 3.12
28-29: Use HTTPS for homepageSwitch to HTTPS.
-Homepage = "http://avocado-framework.github.io/" +Homepage = "https://avocado-framework.github.io/"
7-8: Prefer native PEP 621 readme over setuptools dynamicYou can keep dynamic version, but set readme via [project.readme] and drop the dynamic readme stanza.
[project] name = "avocado-framework-plugin-golang" -dynamic = ["version", "readme"] +dynamic = ["version"] description = "Avocado Plugin for Execution of Golang tests" @@ -[tool.setuptools.dynamic] -version = {file = "VERSION"} -readme = {file = "README.rst", content-type = "text/x-rst"} +[tool.setuptools.dynamic] +version = {file = "VERSION"}And add under [project] (near description/authors):
+readme = {file = "README.rst", content-type = "text/x-rst"}Also applies to: 46-48
.github/actions/wheel/action.yml (1)
11-13: Consider using a virtual environment or--prefixfor more robust isolation.The combination of
pip install -t /tmp/avocado_installwith manualPYTHONPATHmanipulation can be fragile. If the target directory structure conflicts with system packages or has path precedence issues, imports may fail unexpectedly.Consider using a virtual environment for cleaner isolation:
- python3 -m pip install dist/*.whl -t /tmp/avocado_install - export PYTHONPATH=/tmp/avocado_install:$PYTHONPATH - python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())' run /bin/true + python3 -m venv /tmp/avocado_venv + /tmp/avocado_venv/bin/pip install dist/*.whl + /tmp/avocado_venv/bin/avocado run /bin/trueOr use
--userinstall if system-wide isolation is not required:- python3 -m pip install dist/*.whl -t /tmp/avocado_install - export PYTHONPATH=/tmp/avocado_install:$PYTHONPATH + python3 -m pip install --user dist/*.whlMakefile.gh (1)
65-82: Consider using pushd/popd for clearer directory navigation.The pattern
cd $$PLUGIN; ... cd -;works butpushd/popdis more explicit and maintains a directory stack for complex navigation scenarios.Apply this pattern:
for PLUGIN in $(AVOCADO_OPTIONAL_PLUGINS); do\ - cd $$PLUGIN;\ + pushd $$PLUGIN;\ $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ - cd -;\ + popd;\ doneexamples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM!The pyproject.toml configuration is correct for this example plugin. The minimal metadata (no license, authors, or classifiers) is appropriate for an example, and the entry point mapping is properly structured.
Optional: Consider dynamic versioning for consistency.
While the hardcoded version
1.0is fine for examples, using dynamic versioning (like other plugins in this PR) would maintain consistency across the project.If you prefer consistency with other plugins:
[project] name = "avocado-hello-world-parser" -version = "1.0" +dynamic = ["version"] description = "Avocado Hello World CLI command with config parser" + +[tool.setuptools.dynamic] +version = {file = "VERSION"}Then create a
VERSIONfile with the version number.optional_plugins/spawner_remote/pyproject.toml (2)
14-17: Consider bumping aexpect minimum for reliability fixes.aexpect 1.8.0 includes notable bug fixes (remote_login logging loss, cleanup, output handling). Safe to require it if CI allows.
Based on learnings
dependencies = [ - "avocado-framework", - "aexpect>=1.6.2", + "avocado-framework", + "aexpect>=1.8.0", ]
29-31: Prefer HTTPS for project URL.Minor polish; also consider declaring license files for wheels/sdists.
[project.urls] -Homepage = "http://avocado-framework.github.io/" +Homepage = "https://avocado-framework.github.io/"Additionally (optional) in the setuptools tool config:
[tool.setuptools] include-package-data = true +license-files = ["LICENSE", "COPYING*"]optional_plugins/spawner_remote/setup.py (1)
1-1: Use the conventional env path in shebang.Portable shebang is /usr/bin/env.
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
72-75: Annotate mutable class attributes with ClassVar.Silences linters and documents intent.
- METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: "ClassVar" = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: "ClassVar[dict]" = {}Add at the top of the file:
from typing import ClassVar
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(16 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(5 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)setup.py(2 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/varianter_pict/README.rst
🚧 Files skipped from review as they are similar to previous changes (26)
- examples/plugins/job-pre-post/sleep/pyproject.toml
- pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- spell.ignore
- optional_plugins/result_upload/setup.py
- optional_plugins/README.rst
- .github/workflows/release.yml
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- docs/source/guides/contributor/chapters/plugins.rst
- optional_plugins/varianter_cit/pyproject.toml
- optional_plugins/ansible/pyproject.toml
- optional_plugins/robot/setup.py
- .github/workflows/push_ci.yml
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/ansible/README.rst
- optional_plugins/golang/setup.py
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/mail/pyproject.toml
- setup.py
- optional_plugins/result_upload/pyproject.toml
- docs/source/guides/writer/chapters/subclassing.rst
- .github/workflows/prerelease.yml
- .github/workflows/vmimage.yml
- optional_plugins/robot/pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (1)
Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (37)
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: Podman Egg task
- GitHub Check: Wheel task debian:12.4
- GitHub Check: Egg task debian:11.0
- GitHub Check: Fedora selftests
- GitHub Check: Wheel task fedora:40
- GitHub Check: Analyze (python)
- GitHub Check: Wheel task ubuntu:22.04
- GitHub Check: Version task debian:11.0
- GitHub Check: Version task ubuntu:24.04
- GitHub Check: Version task ubuntu:22.04
- GitHub Check: Version task debian:12.4
- GitHub Check: Windows with Python 3.11
- GitHub Check: Windows with Python 3.13
- GitHub Check: Build Package (wheel/tarball) for Python 3.9
- GitHub Check: Build Package (wheel/tarball) for Python 3.11
- GitHub Check: macOS with Python 3.11
🔇 Additional comments (36)
optional_plugins/ansible/setup.py (1)
2-6: pyproject.toml contains all necessary metadata
Name, dynamic version & readme, dependencies, scripts, and entry points are correctly specified.examples/plugins/tests/rogue/pyproject.toml (1)
13-17: Entry-point group names ‘avocado.plugins.resolver’ and ‘avocado.plugins.runnable.runner’ are correct.optional_plugins/varianter_pict/pyproject.toml (5)
1-3: LGTM! Build system configuration follows modern standards.The build system configuration correctly uses setuptools>=61.0, which has full pyproject.toml support, and specifies the standard build backend.
31-35: Entry points look correct.The plugin correctly registers both CLI and varianter interfaces. The use of the same name
varianter_pictin different namespaces is appropriate.
37-41: Package discovery configuration is appropriate.The setuptools configuration correctly enables package data inclusion and uses a glob pattern for package discovery.
43-45: Dynamic metadata files exist:optional_plugins/varianter_pict/VERSIONandREADME.rstare present.
14-16: Leave avocado-framework unconstrained
The lack of a minimum version matches all other optional plugins’ pyproject.toml entries. No change required.optional_plugins/varianter_pict/setup.py (1)
1-6: LGTM! Minimal setup.py shim is correctly implemented.The file correctly delegates all packaging configuration to
pyproject.tomlwhile maintaining backward compatibility. The comment clearly explains the transition period.optional_plugins/varianter_cit/setup.py (1)
2-6: LGTM! Clean migration to pyproject.toml.The transition approach is correct:
- The explanatory comments clearly document the purpose and transitional nature of this minimal setup.py
- The empty
setup()call is the standard pattern when migrating to pyproject.toml, allowing setuptools to automatically read configuration from pyproject.toml- Keeping this file maintains backward compatibility with older build tools that expect setup.py
optional_plugins/varianter_yaml_to_mux/setup.py (1)
1-6: LGTM! Standard pyproject.toml migration pattern.This setup.py shim correctly maintains backward compatibility during the transition to pyproject.toml. The bare
setup()call reads all configuration from pyproject.toml, and the comment clearly documents the transition.optional_plugins/varianter_yaml_to_mux/pyproject.toml (5)
1-3: LGTM! Build system correctly configured.The build system configuration is correct: setuptools>=61.0 enables dynamic metadata support, and the build backend is properly specified.
5-27: LGTM! Project metadata is well-defined.The project metadata is correctly structured. The
requires-python = ">=3.9"aligns with the project dropping Python 3.8 support, and the dependency specifications are appropriate.
41-45: LGTM! Setuptools configuration is appropriate.The setuptools configuration correctly enables package data inclusion and uses a proper wildcard pattern for package discovery.
47-49: Dynamic file references are valid
VERSION and README.rst exist in optional_plugins/varianter_yaml_to_mux as expected; dynamic configuration is correct.
32-39: Entry points verifiedAll referenced classes (YamlToMuxInit, YamlToMuxCLI, YamlToMux) are present in varianter_yaml_to_mux.py; entry-point configuration is correct.
optional_plugins/golang/pyproject.toml (3)
40-45: Package discovery looks goodinclude-package-data and packages.find include = ["avocado_golang*"] align with this plugin. No issues.
If the plugin needs non-package files (e.g., templates), add [tool.setuptools.package-data] accordingly.
31-38: Entry point group is correct ‘avocado.plugins.runnable.runner’ matches Avocado’s loader code and documentation.
46-47: IncludeVERSIONandREADME.rstinoptional_plugins/golangsdist
There’s noMANIFEST.inin that directory, so add one alongsidepyproject.toml:include VERSION README.rstThen rebuild the sdist and verify both files are present.
examples/plugins/tests/README.rst (1)
15-16: LGTM!The update to use
pip install -e .instead of the deprecatedpython setup.py develop --useraligns with modern Python packaging best practices and the PR's migration objectives.examples/plugins/README.rst (1)
10-24: LGTM!The updated instructions provide clear, modern pip-based workflows for plugin development. The explicit install and uninstall examples with concrete paths make the documentation more helpful for developers.
optional_plugins/mail/setup.py (1)
2-6: LGTM!The simplified setup.py correctly delegates all packaging configuration to
pyproject.toml, maintaining backward compatibility during the transition period as noted in the comment.python-avocado.spec (2)
243-263: LGTM!The conditional exclusions for
avocado_result_html,avocado_resultsdb, and framework plugin packages are correctly structured with appropriate RHEL/Fedora version gating.
8-8: Verify custom tarball naming on GitHub and CI workflows.
The spec usesavocado_framework-%{version}.tar.gz(underscore). GitHub’s default isavocado-framework-<version>.tar.gz(hyphen), so ensure your release pipeline (CI jobs, PyPI sdist, GitHub release assets) uploads the customavocado_framework-<version>.tar.gzartifact.optional_plugins/resultsdb/pyproject.toml (1)
1-49: LGTM!The pyproject.toml configuration for the resultsdb plugin is well-structured and complete. The dynamic version/readme loading, dependency specifications, entry points for CLI/result_events/result handlers, and package discovery are all correctly configured.
Makefile.gh (1)
65-69: No missing packaging configurations detected. Verified that every optional plugin directory contains asetup.pyorpyproject.toml.optional_plugins/resultsdb/setup.py (1)
2-6: LGTM! Clean transition shim.The minimal setup() call with clear comments about the transition period is the correct approach for maintaining backward compatibility while migrating to pyproject.toml-based configuration.
.github/actions/version/action.yml (1)
9-9: LGTM! Correctly migrated to pip-based editable install.The change from
python3 setup.py develop --usertopython3 -m pip install -e . --useraligns with the modern Python packaging workflow and the PR's migration goals.optional_plugins/html/setup.py (1)
2-6: LGTM! Clean transition shim.The minimal setup() call with clear comments about the transition period maintains backward compatibility while delegating configuration to pyproject.toml.
.github/workflows/weekly.yml (1)
37-47: LGTM! Consistent migration to modern Python workflows.The changes correctly replace setup.py-based commands with pip module invocations and Python module execution for tests, aligning with the PR's modernization goals.
.github/workflows/setup.yml (1)
32-50: LGTM! Comprehensive installation testing.The updated user installation workflow correctly uses
python3 -m pip installfor both the core framework and optional plugins, ensuring compatibility with modern Python packaging standards..github/workflows/ci.yml (2)
28-32: LGTM! CI workflow correctly updated.The static checks job properly uses
python3 -m pip install -e . --userfor editable installation andpython3 -m selftests.checkfor running tests, aligning with the pyproject.toml migration.
361-386: LGTM! Modernized packaging terminology.The renaming of "egg" tasks to "wheel" tasks (lines 361-386) correctly reflects the shift to modern Python wheel-based packaging, which is the preferred distribution format.
Makefile (1)
94-108: All plugin directories align with PLUGIN values. Directory listing confirms convention; no changes required.optional_plugins/html/pyproject.toml (1)
1-48: Entry points correct The classes HTML, HTMLInit, and HTMLResult are defined in the avocado_result_html module, matching the entry-point definitions.optional_plugins/spawner_remote/pyproject.toml (1)
32-36: Entry points look correct now.The module paths include .spawner and match the new implementation.
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
151-156: No issues with pick_runner_module_from_entry_point_kind access. It's defined as a staticmethod on Runnable and callable via the instance.
| async def terminate_task(self, runtime_task): | ||
| session = runtime_task.spawner_handle | ||
| session.sendcontrol("c") | ||
| try: | ||
| session.read_up_to_prompt() | ||
| return True | ||
| except exceptions.ExpectTimeoutError: | ||
| LOG.error("Failed to terminate task on {session.host}") | ||
| return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix logging message and include traceback on termination failure.
Current message lacks f-string; use logging.exception for context.
async def terminate_task(self, runtime_task):
session = runtime_task.spawner_handle
session.sendcontrol("c")
try:
session.read_up_to_prompt()
- return True
- except exceptions.ExpectTimeoutError:
- LOG.error("Failed to terminate task on {session.host}")
- return False
+ except exceptions.ExpectTimeoutError:
+ LOG.exception(f"Failed to terminate task on {session.host}:{session.port}")
+ return False
+ else:
+ return True📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def terminate_task(self, runtime_task): | |
| session = runtime_task.spawner_handle | |
| session.sendcontrol("c") | |
| try: | |
| session.read_up_to_prompt() | |
| return True | |
| except exceptions.ExpectTimeoutError: | |
| LOG.error("Failed to terminate task on {session.host}") | |
| return False | |
| async def terminate_task(self, runtime_task): | |
| session = runtime_task.spawner_handle | |
| session.sendcontrol("c") | |
| try: | |
| session.read_up_to_prompt() | |
| except exceptions.ExpectTimeoutError: | |
| LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") | |
| return False | |
| else: | |
| return True |
🧰 Tools
🪛 Ruff (0.13.3)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around
lines 208 to 216, the failure log uses a plain string and omits traceback;
change the LOG.error call to log the actual host and include the exception
traceback by using LOG.exception(f"Failed to terminate task on {session.host}")
(or LOG.error(..., exc_info=True)) so the host is interpolated and the
stacktrace is recorded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (9)
optional_plugins/mail/setup.py (1)
1-1: Fix the shebang for better portability.The shebang uses
/bin/envwhich is not portable across all systems. Use/usr/bin/envinstead.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/ansible/setup.py (1)
1-1: Fix the shebang for better portability.The shebang uses
/bin/envwhich is not portable across all systems. Use/usr/bin/envinstead.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (7)
38-46: Timeout options should specify key_type=int.Without
key_type=int, the settings will be stored as strings, which can break arithmetic operations or comparisons in downstream code that expects integers.Apply this diff to fix the type declarations:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-114: Add error handling for slot initialization.Reading JSON configuration files and creating remote sessions can fail in multiple ways (malformed JSON, missing files, connection failures). Without error handling, a single bad slot configuration will crash the spawner initialization.
Apply this diff to add robust error handling:
if len(RemoteSpawner.slots_cache) == 0: # TODO: consider whether to provide persistence across runs via external storage for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
143-145: Escape task identifier in shell command.The task identifier is interpolated directly into the shell command without escaping. If the identifier contains special characters (spaces, quotes, shell metacharacters), the command will break or could lead to command injection.
Apply this diff to properly escape the identifier:
@staticmethod def is_task_alive(runtime_task): if runtime_task.spawner_handle is None: return False # NOTE: since this is called at the end of each test, it is reasonable # to reuse the same session with a new command session = runtime_task.spawner_handle + safe_identifier = shlex.quote(runtime_task.task.identifier) status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" + f"pgrep -r R,S -f {safe_identifier}" ) return status == 0
182-182: Critical: Output redirection loses all test results.Redirecting output to
/dev/nulldiscards all test output, including results, logs, stdout, and stderr. This defeats the purpose of running tests remotely and makes debugging impossible.Remove the output redirection or redirect to a file that can be retrieved:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Or if you need to capture output remotely:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"
195-200: Avoid fixed /tmp path; use a sanitized, unique remote directory.The hardcoded
/tmp/.avocado_task_output_dirpath can lead to collisions when multiple tasks run concurrently, and presents TOCTOU (time-of-check-time-of-use) risks.Apply this diff to use a unique, sanitized directory per task:
def create_task_output_dir(self, runtime_task): output_dir_path = self.task_output_dir(runtime_task) - output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier) + output_lxc_path = f"/tmp/avocado-task-{safe_id}" os.makedirs(output_dir_path, exist_ok=True) runtime_task.task.setup_output_dir(output_lxc_path)
202-206: Add timeout to prevent infinite waiting.The wait loop has no timeout, so if a task hangs or
is_task_alivehas a bug, the spawner will wait indefinitely and block the job runner.Apply this diff to add a configurable timeout:
async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() while True: if not RemoteSpawner.is_task_alive(runtime_task): return + if asyncio.get_event_loop().time() - start_time > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return await asyncio.sleep(0.1)
208-216: Fix logging message and include traceback on termination failure.The error message on line 215 is missing f-string interpolation and should use
logging.exceptionto capture the full traceback.Apply this diff to fix the logging:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True - except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") - return False + except exceptions.ExpectTimeoutError: + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") + return False + else: + return True
🧹 Nitpick comments (3)
.github/workflows/ci.yml (2)
89-89: Remove redundant version flag.The
-Vflag already displays the Python version, so adding--versionis redundant.Apply this diff:
- run: python3 -V --version + run: python3 -V
131-131: Remove redundant version flag.The
-Vflag already displays the Python version, so adding--versionis redundant.Apply this diff:
- run: python3 -V --version + run: python3 -Voptional_plugins/robot/pyproject.toml (1)
16-16: Remove redundant python_version condition.The
python_version >= '3.9'condition on line 16 is redundant because line 13 already specifiesrequires-python = ">=3.9", which applies to all dependencies.Apply this diff to remove the redundant condition:
dependencies = [ "avocado-framework", - "robotframework>=4.1, <7.0; python_version >= '3.9'", + "robotframework>=4.1, <7.0", ]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (66)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(16 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)selftests/run_coverage(1 hunks)setup.py(2 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/tests/rogue/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello/setup.py
🚧 Files skipped from review as they are similar to previous changes (32)
- optional_plugins/resultsdb/setup.py
- .github/actions/version/action.yml
- examples/plugins/tests/rogue/pyproject.toml
- optional_plugins/ansible/README.rst
- .github/workflows/weekly.yml
- docs/source/guides/contributor/chapters/plugins.rst
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- spell.ignore
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- selftests/pre_release/tests/check-copr-rpm-version.sh
- optional_plugins/ansible/pyproject.toml
- optional_plugins/html/setup.py
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/tests/README.rst
- examples/plugins/tests/magic/pyproject.toml
- optional_plugins/html/pyproject.toml
- optional_plugins/golang/setup.py
- optional_plugins/spawner_remote/setup.py
- examples/plugins/test-pre-post/hello/pyproject.toml
- .github/workflows/vmimage.yml
- .github/workflows/release.yml
- optional_plugins/varianter_pict/setup.py
- .github/workflows/push_ci.yml
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- pyproject.toml
- optional_plugins/golang/pyproject.toml
- .github/actions/wheel/action.yml
- optional_plugins/varianter_pict/README.rst
- docs/source/guides/contributor/chapters/environment.rst
- .github/workflows/prerelease.yml
- optional_plugins/README.rst
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (43)
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: Linux with Python 3.13
- GitHub Check: Linux with Python 3.12
- GitHub Check: Linux with Python 3.11
- GitHub Check: Linux with Python 3.9
- GitHub Check: Linux with Python 3.10
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (18)
optional_plugins/varianter_yaml_to_mux/setup.py (1)
2-6: LGTM! Clear transitional approach.The minimal setup.py with a transitional comment clearly documents the migration path to pyproject.toml-based packaging while maintaining backward compatibility.
selftests/run_coverage (1)
30-30: LGTM! Aligns with module-based execution pattern.Changing from direct script execution to
python -m selftests.checkis consistent with Python best practices and aligns with the broader repository migration to module-based test execution.optional_plugins/varianter_yaml_to_mux/README.rst (1)
6-6: LGTM! Documentation formatting improved.Converting Sphinx-specific roles to inline code literals simplifies the documentation and makes it more portable while maintaining clarity.
Also applies to: 11-11, 14-14, 632-632, 639-639, 649-649, 786-786, 790-790, 798-800
Makefile.gh (2)
66-68: LGTM! Simplified plugin build iteration.Removing the conditional setup.py existence check aligns with the pyproject.toml migration, where all plugins now have standardized packaging configurations. The unconditional directory entry assumes all plugin directories have proper build configurations, which is reasonable for this transition.
79-81: LGTM! Consistent with wheel build changes.The egg build target follows the same pattern as the wheel build, removing conditional checks and standardizing the plugin iteration logic.
docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: LGTM! Documentation modernized for pyproject.toml.The documentation accurately reflects modern Python packaging practices, showing the complete pyproject.toml structure with dynamic versioning, build system configuration, and proper metadata declaration.
88-101: LGTM! Updated installation instructions.The installation guidance correctly shifts from
python setup.py developtopip install -e ., which is the modern, recommended approach for editable installs. The example output clearly demonstrates the expected behavior.optional_plugins/result_upload/setup.py (1)
2-6: LGTM! Consistent transitional pattern.The minimal setup.py follows the same transitional pattern as other plugins, maintaining backward compatibility while documenting the migration to pyproject.toml.
optional_plugins/mail/setup.py (1)
2-6: LGTM! Consistent transitional pattern.The minimal setup.py maintains backward compatibility while properly delegating configuration to pyproject.toml.
optional_plugins/ansible/setup.py (1)
2-6: LGTM! Consistent transitional pattern.The minimal setup.py follows the established pattern for the pyproject.toml migration, maintaining compatibility during the transition period.
Makefile (3)
64-67: LGTM: Pip-based install/uninstall modernizes the workflow.The migration from
setup.py install/developtopip installaligns with the broader pyproject.toml transition and follows current Python packaging best practices.
76-80: LGTM: Module-based invocation is correct.Using
python -m avocadoandpython -m selftests.checkensures the correct module resolution and is consistent with the pip-based editable install approach.
94-108: LGTM: Plugin development targets enhance developer experience.The new
develop-pluginsanddevelop-plugintargets provide convenient workflows for installing optional plugins in editable mode, which aligns well with the pyproject.toml-based plugin packaging.examples/plugins/README.rst (1)
10-24: LGTM: Documentation accurately reflects the pip-based workflow.The updated examples clearly demonstrate the modern
pip install -e .andpip uninstallcommands, which align with the pyproject.toml migration across the repository.optional_plugins/robot/setup.py (1)
2-6: LGTM: Minimal setup.py maintains backward compatibility.The transitional comment and minimal
setup()call appropriately maintain backward compatibility while delegating configuration to pyproject.toml.optional_plugins/result_upload/pyproject.toml (1)
1-45: LGTM: Well-structured pyproject.toml for result_upload plugin.The packaging configuration is complete and follows the same pattern as other optional plugins. Entry points are correctly defined for CLI and result plugin integration.
optional_plugins/spawner_remote/pyproject.toml (2)
32-36: LGTM: Entry points correctly reference the spawner module.The entry points now correctly point to
avocado_spawner_remote.spawner:RemoteSpawnerInitandavocado_spawner_remote.spawner:RemoteSpawner, which aligns with the new spawner.py implementation.
16-16: No change needed for aexpect dependency. aexpect>=1.6.2 already includes version 1.8.0, which introduces only bug fixes and improvements without breaking changes.
| requires-python = ">=3.9" | ||
| dependencies = [ | ||
| "avocado-framework", | ||
| "robotframework>=4.1, <7.0; python_version >= '3.9'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Verify the robotframework version constraint.
The constraint <7.0 may be outdated. Since my knowledge is from March 2025 and robotframework releases frequently, please verify whether robotframework 7.x is available and compatible.
🌐 Web query:
What is the latest stable version of robotframework as of October 2025, and is version 7.0 or higher available?
💡 Result:
As of Oct 13, 2025 the latest stable Robot Framework release is 7.3.2. [1][2]
Yes — versions 7.0 and higher are available (7.0 was released Jan 11, 2024 and the 7.x series continues through 7.3.2). [2][1]
Sources:
[1] PyPI project page for robotframework (showing v7.3.2).
[2] Robot Framework GitHub releases (showing v7.3 and related 7.x releases).
Update Robot Framework version constraint: in optional_plugins/robot/pyproject.toml, change the dependency from
"robotframework>=4.1, <7.0; python_version >= '3.9'"to
"robotframework>=4.1, <8.0; python_version >= '3.9'"to support the latest 7.x releases (current latest 7.3.2).
🤖 Prompt for AI Agents
In optional_plugins/robot/pyproject.toml around line 16, update the Robot
Framework version upper bound from <7.0 to <8.0 so the dependency line reads
that Robot Framework versions 4.1 and above up to (but not including) 8.0 are
allowed; edit the quoted dependency string accordingly and save the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
♻️ Duplicate comments (7)
examples/plugins/cli-cmd/hello_priority/pyproject.toml (1)
10-11: Duplicate entry point name causes collision.Both
examples/plugins/cli-cmd/hello/pyproject.tomland this file define the entry point keyhellounder[project.entry-points."avocado.plugins.cli.cmd"]. This collision will prevent both plugins from being installed simultaneously. Rename this entry point tohello_priorityto match the module name and avoid conflicts.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (6)
38-46: Fix timeout options to use integer type.The timeout options are registered without
key_type=int, which means they will be parsed as strings. This can cause issues when the values are used in arithmetic operations or comparisons.Apply this diff:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
182-182: Critical: Output redirection loses all test results.Redirecting output to
/dev/nulldiscards all test output, including results, logs, stdout, and stderr. This makes debugging impossible and defeats the purpose of running tests remotely.Remove the output redirection:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Or if you need to capture output remotely for later retrieval:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in task.identifier) + remote_log = f"/tmp/avocado-task-{safe_id}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"
202-206: Add timeout to prevent infinite waiting.The wait loop has no timeout, so if a task hangs or
is_task_alivehas a bug, the spawner will wait indefinitely and block the job runner.Apply this diff to add a configurable timeout:
async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() while True: if not RemoteSpawner.is_task_alive(runtime_task): return + if asyncio.get_event_loop().time() - start_time > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return await asyncio.sleep(0.1)
106-114: Add error handling for slot initialization.Reading JSON configuration files and creating remote sessions can fail in multiple ways (malformed JSON, missing files, connection failures). Without error handling, a single bad slot configuration will crash the spawner initialization.
Apply this diff:
if len(RemoteSpawner.slots_cache) == 0: # TODO: consider whether to provide persistence across runs via external storage for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
195-200: Avoid fixed /tmp path to reduce collision and security risks.Using a fixed path
/tmp/.avocado_task_output_dircan lead to collisions between concurrent tasks and TOCTOU (time-of-check-time-of-use) security vulnerabilities.Apply this diff to use a unique, sanitized path per task:
def create_task_output_dir(self, runtime_task): output_dir_path = self.task_output_dir(runtime_task) - output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier) + output_lxc_path = f"/tmp/avocado-task-{safe_id}" os.makedirs(output_dir_path, exist_ok=True) runtime_task.task.setup_output_dir(output_lxc_path)
208-216: Fix logging and improve exception handling.The error message is missing an f-string prefix and should use
logging.exceptionto include the traceback. Also, the return statement should be moved to an else block per Python conventions.Apply this diff:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") return False + else: + return True
🧹 Nitpick comments (9)
examples/plugins/tests/magic/pyproject.toml (1)
25-25: Add explicit package discovery constraints.The
[tool.setuptools.packages.find]section is empty, which means setuptools will discover all packages in the directory. This may pick up unwanted packages or fail to find the intended package.Apply this diff to explicitly include the
avocado_magicpackage:[tool.setuptools.packages.find] +include = ["avocado_magic*"]Alternatively, if
avocado_magicis in a non-standard location:[tool.setuptools.packages.find] +where = ["."] +include = ["avocado_magic*"]optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
73-74: Add ClassVar annotations for mutable class attributes.The static analysis tool correctly identifies that
METHODSandslots_cacheare mutable class attributes that should be annotated withtyping.ClassVarto clarify their scope and prevent potential issues with subclasses.Apply this diff:
+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar[list] = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar[dict] = {}.github/actions/wheel/action.yml (2)
14-16: Consider using theavocadocommand directly.The wheel installation should provide the
avocadoconsole script via entry points. Using the Python one-liner to import and callmain()directly bypasses the installed entry point, which may not fully test the wheel installation.Consider updating to use the installed command:
- python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())' run /bin/true + avocado run /bin/true cd /tmp - python3 -c 'from avocado.core.main import main; import sys; sys.exit(main())' run /bin/true + avocado run /bin/trueHowever, if the
avocadocommand is not available inPATHafter the wheel installation with-t, the current approach may be necessary. Please verify the intent.
9-9: Remove unnecessary PIP_BREAK_SYSTEM_PACKAGES override
- .github/actions/wheel/action.yml:9: drop
export PIP_BREAK_SYSTEM_PACKAGES=1—pip install --targetalready isolates installs without touching system site-packages- Keep the Python one-liner—
pip install --targetdoesn’t generate console_scripts wrappers, so invokingmain()directly is correct.Makefile (1)
83-86: Clarify the distinction betweendevelopanddevelop-core.Lines 83 and 85-86 define both
developanddevelop-coretargets with identical implementations. This duplication suggests either:
- These targets are meant to be aliases (in which case, document this)
- They will diverge in the future (in which case, document the intended distinction)
If they're meant to be aliases, consider making this explicit:
develop: $(PYTHON) -m pip install -e . $(PYTHON_DEVELOP_ARGS) develop-core: develop @# Alias for develop targetOtherwise, document in the help text (lines 6-7) what distinguishes
developfromdevelop-core..github/actions/version/action.yml (1)
9-9: Remove unnecessaryPIP_BREAK_SYSTEM_PACKAGES
Sincepip install -e . --userinstalls into the user site and cannot overwrite system packages, this override is redundant. Remove it:- export PIP_BREAK_SYSTEM_PACKAGES=1 python3 -m pip install -e . --usersetup.py (1)
24-26: Add CI validation for entry_points synchronization
- Egg builds are still in use (Makefile targets, fetch-eggs scripts, plugin spawners, eggenv), so the duplicated entry_points in setup.py is required.
- Introduce a CI check that programmatically compares entry_points in setup.py with those in pyproject.toml to prevent drift.
.github/workflows/ci.yml (2)
536-536: Inconsistent installation method.Line 536 uses
make developwhile all other jobs in this workflow usepython3 -m pip install -e . --userfor consistency with the pip-based migration. Using different installation methods across jobs may lead to subtle behavioral differences.Apply this diff to align with the rest of the workflow:
- make develop + python3 -m pip install -e . --user
517-517: Replace*.egg-infowith*.dist-infoin cleanup
Therm -rf build/ dist/ *.egg-infoglob matches nothing under pip/wheel packaging—add or replace with*.dist-infoto remove wheel metadata directories.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (67)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(16 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)contrib/scripts/avocado-safeloader-find-python-unittest(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)selftests/run_coverage(1 hunks)setup.py(2 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/cli-cmd/hello/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/varianter_pict/README.rst
🚧 Files skipped from review as they are similar to previous changes (21)
- Makefile.gh
- optional_plugins/varianter_cit/pyproject.toml
- docs/source/guides/writer/chapters/subclassing.rst
- pyproject.toml
- optional_plugins/varianter_yaml_to_mux/setup.py
- .github/workflows/release.yml
- examples/plugins/test-pre-post/hello/pyproject.toml
- .github/workflows/vmimage.yml
- examples/plugins/tests/README.rst
- optional_plugins/golang/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- optional_plugins/robot/setup.py
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/ansible/README.rst
- .github/workflows/weekly.yml
- spell.ignore
- optional_plugins/html/pyproject.toml
- .github/workflows/prerelease.yml
- optional_plugins/result_upload/setup.py
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: Linux with Python 3.12
- GitHub Check: Linux with Python 3.13
- GitHub Check: Linux with Python 3.11
- GitHub Check: Linux with Python 3.9
- GitHub Check: Linux with Python 3.10
- GitHub Check: Fedora selftests
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (41)
selftests/pre_release/tests/check-copr-rpm-version.sh (1)
14-14: LGTM! Version reading now aligns with pyproject.toml migration.The change from
python setup.py --versionto reading directly from theVERSIONfile is correct and consistent with the broader migration to pyproject.toml-based packaging.optional_plugins/varianter_pict/setup.py (1)
1-6: LGTM! Standard migration pattern to pyproject.toml.The minimal
setup()call with the transition comment is the correct approach for maintaining backward compatibility while migrating to pyproject.toml-based packaging.optional_plugins/resultsdb/setup.py (1)
1-6: LGTM! Standard migration pattern.The minimal
setup()implementation with transition comment follows the expected pattern for pyproject.toml migration.examples/plugins/README.rst (1)
8-24: LGTM! Documentation accurately reflects pip-based workflow.The updated instructions correctly document the migration from
python setup.py developtopip install -e .and include clear uninstall examples. The changes are well-structured and easy to follow.examples/plugins/cli-cmd/hello/pyproject.toml (1)
10-11: Entry point configuration is correct.The entry point name
helloappropriately matches the module name. Note thatexamples/plugins/cli-cmd/hello_priority/pyproject.tomlincorrectly uses the same entry point name, which will cause a collision.optional_plugins/html/setup.py (1)
1-6: LGTM! Standard migration pattern.The minimal
setup()implementation follows the correct pattern for transitioning to pyproject.toml-based packaging.optional_plugins/spawner_remote/pyproject.toml (2)
14-16: Verify aexpect minimum version requirement.The dependency specifies
aexpect>=1.6.2. While this is reasonable (1.8.0 is the latest version per learnings), ensure that version 1.6.2 actually provides all the features required by the remote spawner implementation.Based on learnings
32-36: LGTM! Entry points are correctly configured.The entry points now correctly reference
avocado_spawner_remote.spawner:RemoteSpawnerInitandavocado_spawner_remote.spawner:RemoteSpawner, which matches the module structure.optional_plugins/golang/setup.py (1)
2-6: LGTM! Clean transitional setup.py shim.The transitional comments clearly document the purpose, and the bare
setup()call appropriately delegates packaging configuration topyproject.toml. This approach maintains backward compatibility during the migration period.optional_plugins/mail/setup.py (1)
2-6: LGTM! Consistent with the migration pattern.The file correctly implements the transitional setup.py shim pattern, maintaining backward compatibility while delegating to
pyproject.toml.optional_plugins/spawner_remote/setup.py (1)
2-6: LGTM! Proper transitional shim.The setup.py correctly serves as a backward-compatible shim while delegating packaging to
pyproject.toml. The approach aligns with the repository-wide migration strategy.docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM! Documentation correctly updated for pyproject.toml.The documentation properly reflects the migration from
setup.pytopyproject.tomland correctly recommends usingpip install -e .for editable installs. This aligns with modern Python packaging best practices.
111-114: LGTM! Entry point syntax correctly documented.The TOML entry point syntax is accurate and follows the standard
[project.entry-points."namespace"]format. The example properly demonstrates how to register Avocado plugins inpyproject.toml.
170-173: LGTM! Settings plugin registration correctly documented.The example accurately shows how to register settings plugins using TOML entry points, maintaining consistency with the overall migration approach.
325-327: LGTM! Test type plugin documentation properly updated.The documentation correctly references the
pyproject.tomlfile and uses the recommendedpip install -e .command for development installs.optional_plugins/varianter_cit/setup.py (1)
2-6: LGTM! Consistent transitional shim.The file follows the established pattern for the pyproject.toml migration, serving as a backward-compatible shim while delegating configuration to
pyproject.toml.examples/plugins/tests/magic/pyproject.toml (1)
10-23: Package structure and entry points verified. All specified modules and classes (MagicInit,MagicResolver,MagicDiscovererinresolver.py;MagicRunnerandmain()inrunner.py) are present inexamples/plugins/tests/magic/avocado_magic.examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: Configuration valid:examples/plugins/cli-cmd/hello_option/hello_option.pyexists and definesHelloWorldas expected.optional_plugins/mail/pyproject.toml (1)
1-44: LGTM! Clean pyproject.toml configuration for the mail plugin.The packaging configuration is well-structured and consistent with the other optional plugins in this PR. The dynamic version/readme setup, entry points, and dependencies are properly defined.
python-avocado.spec (3)
8-18: LGTM! Tarball naming updated to match new packaging structure.The tarball name changes from
avocado-toavocado_framework-align with the modernized pyproject.toml-based packaging. This is consistent across both release and snapshot builds.
102-104: LGTM! Setup paths updated to match new tarball naming.The
%setupdirectives correctly reference the newavocado_framework-prefix for both release and commit-based builds.
220-220: LGTM! Selftests invocation modernized.Updated from
selftests/check.pytopython3 -m selftests.check, which is more consistent with modern Python module execution practices.examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM! Simple and appropriate configuration for an example plugin.The pyproject.toml is well-suited for the example CLI plugin. The use of
py-modulesis appropriate for a single-module plugin, and the hardcoded version is acceptable for examples.optional_plugins/ansible/pyproject.toml (1)
1-50: LGTM! Well-structured pyproject.toml with appropriate version constraints.The packaging configuration properly handles Python version-specific dependencies for
cffiandcryptography. The entry points for the ansible module runner and plugin are correctly defined.optional_plugins/ansible/setup.py (1)
1-6: LGTM! Proper transitional setup.py for backward compatibility.The minimal
setup.pywith a baresetup()call is the correct approach during the migration to pyproject.toml. The comment clearly documents that this is for egg-building compatibility.optional_plugins/resultsdb/pyproject.toml (1)
1-49: LGTM! Clean configuration with past issues resolved.The pyproject.toml is well-structured, and the impossible urllib3 constraint issue from previous review has been properly addressed. The entry points for CLI, result events, and result plugins are correctly defined.
optional_plugins/result_upload/pyproject.toml (1)
1-45: LGTM! Straightforward configuration for result upload plugin.The pyproject.toml follows the established pattern for optional plugins with proper dynamic metadata setup and correctly defined entry points for CLI and result plugins.
.github/workflows/push_ci.yml (1)
95-97: LGTM!The migration from
setup.py developtopip install -e .follows modern Python packaging best practices and aligns with PEP 517/518 standards.selftests/run_coverage (1)
30-30: LGTM!The migration from direct script invocation to module invocation (
-m selftests.check) is consistent with modern Python packaging practices and aligns with the broader migration in this PR.optional_plugins/README.rst (1)
10-34: LGTM!The documentation accurately reflects the migration to pip-based workflows and provides clear examples for both installation and removal of plugins. The updated Makefile target references are helpful.
.github/workflows/setup.yml (2)
33-125: LGTM!The workflow comprehensively covers different installation scenarios (user, system, develop) and consistently uses pip-based installation commands. The migration from
setup.pytopip installis implemented correctly across all jobs.
149-219: LGTM!The remaining installation scenarios (system-wide develop, virtualenv, develop-virtualenv) are correctly updated to use pip-based workflows, maintaining consistency with the earlier jobs.
Makefile (5)
34-61: LGTM! Enhanced clean target with clear messaging.The expanded clean target now handles build artifacts, caches, and plugin directories comprehensively with helpful progress messages.
64-67: LGTM! Migration to pip-based install/uninstall.The install and uninstall targets correctly use
pipinstead ofsetup.py, aligning with modern Python packaging practices.
80-80: LGTM! Module-based test invocation.The check target now uses
python -m selftests.check, which is consistent with the broader migration in this PR.
94-107: LGTM! New plugin development targets.The
develop-pluginsanddevelop-plugintargets provide convenient workflows for installing optional plugins in editable mode, with clear error messages and progress indicators.
112-119: LGTM! Improved man page generation with error handling.The man target now properly checks for the availability of
rst2manorrst2man.pyand provides a clear error message if neither is found..github/workflows/ci.yml (4)
28-28: LGTM on pip-based installation migration.The transition from
setup.py developtopython3 -m pip install -e . --useraligns well with modern Python packaging practices and the pyproject.toml migration objectives. The changes are consistent across most jobs (with the exception noted in Line 536).Also applies to: 95-95, 135-135, 171-171, 512-518
32-32: LGTM on test execution migration.The switch from
setup.py testinvocations topython3 -m selftests.checkis correct and follows modern Python testing practices.Also applies to: 99-99, 143-143
265-265: LGTM on python3-pip installations.Adding explicit
python3-pipinstallation steps across all distribution containers ensures pip is available for the new pip-based workflows. This is a necessary prerequisite for the migration.Also applies to: 278-278, 291-291, 304-304, 317-317, 330-330, 343-343, 356-356, 369-369, 382-382, 408-408, 421-421, 447-447, 460-460
361-463: Wheel action implementation verified. The.github/actions/wheel/action.ymlexists and correctly builds, installs, and tests the wheel package.
.github/workflows/ci.yml
Outdated
| python-version: ${{ matrix.python-version }} | ||
| - name: Display Python version | ||
| run: python -V --version | ||
| run: python3 -V --version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix invalid flag combination.
The command python3 -V --version combines two version flags incorrectly. Python's -V flag is shorthand for --version, and combining them is redundant and may cause parsing issues depending on the Python version.
Apply this diff:
- run: python3 -V --version
+ run: python3 --version📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| run: python3 -V --version | |
| run: python3 --version |
🤖 Prompt for AI Agents
In .github/workflows/ci.yml around line 89, the step uses the invalid redundant
flag combination `python3 -V --version`; replace it with a single version flag
(for example `python3 --version`) so the workflow calls Python with a single,
valid version flag.
.github/workflows/ci.yml
Outdated
| python-version: ${{ matrix.python-version }} | ||
| - name: Display Python version | ||
| run: python -V --version | ||
| run: python3 -V --version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix invalid flag combination.
Same issue as Line 89: python3 -V --version combines two version flags incorrectly.
Apply this diff:
- run: python3 -V --version
+ run: python3 --version📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| run: python3 -V --version | |
| run: python3 --version |
🤖 Prompt for AI Agents
.github/workflows/ci.yml around line 131: the workflow runs `python3 -V
--version`, which wrongly combines two version flags; replace the command with a
single valid flag such as `python3 --version` (or `python3 -V`) to print the
Python version, and ensure the similar issue on line 89 is fixed consistently.
| [project.scripts] | ||
| avocado-runner-rogue = "avocado_rogue.runner:main" | ||
|
|
||
| [project.entry-points."avocado.plugins.resolver"] | ||
| rogue = "avocado_rogue.resolver:RogueResolver" | ||
|
|
||
| [project.entry-points."avocado.plugins.runnable.runner"] | ||
| rogue = "avocado_rogue.runner:RogueRunner" | ||
|
|
||
| [tool.setuptools] | ||
| py-modules = ["avocado_rogue"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify package structure matches the configuration.
The configuration has potential ambiguity:
py-modules = ["avocado_rogue"]declares a single-file module- Entry points target submodules like
avocado_rogue.resolver:RogueResolver
This works only if avocado_rogue is a package directory (with __init__.py), not a single file. Although past reviews marked this as addressed, please confirm the actual structure.
Run the following script to verify the package structure:
🏁 Script executed:
#!/bin/bash
# Description: Verify avocado_rogue package structure
cd examples/plugins/tests/rogue || exit 1
if [ -d "avocado_rogue" ]; then
echo "✓ avocado_rogue is a package directory"
# Check for __init__.py
if [ -f "avocado_rogue/__init__.py" ]; then
echo "✓ __init__.py exists"
else
echo "✗ __init__.py missing"
fi
# Check for resolver.py and runner.py
if [ -f "avocado_rogue/resolver.py" ]; then
echo "✓ resolver.py exists"
else
echo "✗ resolver.py missing"
fi
if [ -f "avocado_rogue/runner.py" ]; then
echo "✓ runner.py exists"
else
echo "✗ runner.py missing"
fi
# Verify classes exist
rg -n "class RogueResolver" avocado_rogue/resolver.py
rg -n "class RogueRunner" avocado_rogue/runner.py
rg -n "def main" avocado_rogue/runner.py
elif [ -f "avocado_rogue.py" ]; then
echo "✗ avocado_rogue.py is a single file"
echo "Configuration declares py-modules but entry points target submodules"
echo "This mismatch will cause import errors"
else
echo "✗ avocado_rogue not found"
fiLength of output: 182
Replace py-modules with packages for avocado_rogue
Under [tool.setuptools] in examples/plugins/tests/rogue/pyproject.toml, change
py-modules = ["avocado_rogue"]to
packages = ["avocado_rogue"]🤖 Prompt for AI Agents
In examples/plugins/tests/rogue/pyproject.toml around lines 10 to 20, the
[tool.setuptools] section incorrectly uses py-modules = ["avocado_rogue"] which
should be packages = ["avocado_rogue"]; update that key to packages so
setuptools treats avocado_rogue as a package directory rather than a
single-module file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (20)
optional_plugins/varianter_yaml_to_mux/setup.py (1)
1-1: Verify the shebang fix was applied.Past review comments indicate the shebang issue (
#!/bin/env→#!/usr/bin/env) was addressed in previous commits, but the code still shows the incorrect shebang. Please confirm whether this fix was actually applied or if there has been a regression.Additionally, the file has a shebang but is not executable (Ruff EXE001). Either make the file executable with
chmod +xor remove the shebang if the file is not intended to be executed directly.optional_plugins/golang/setup.py (1)
1-1: Verify the shebang fix was applied.Past review comments indicate the shebang issue was addressed in previous commits, but the code still shows
#!/bin/env python3instead of#!/usr/bin/env python3. Please verify whether this fix was actually applied or if there has been a regression.Additionally, the file has a shebang but is not executable. Either make the file executable or remove the shebang if direct execution is not intended.
optional_plugins/resultsdb/setup.py (1)
1-1: Verify the shebang fix was applied.Past review comments indicate the shebang issue was addressed, but the code still shows
#!/bin/env python3instead of#!/usr/bin/env python3. Please confirm whether this fix was applied or if there has been a regression.Additionally, the file has a shebang but is not executable. Either make the file executable or remove the shebang.
optional_plugins/html/setup.py (1)
1-1: Verify the shebang fix was applied.Past review comments indicate the shebang issue was addressed, but the code still shows
#!/bin/env python3. Please verify the fix was applied or if there has been a regression.Additionally, the file has a shebang but is not executable. Either make the file executable or remove the shebang.
optional_plugins/mail/setup.py (1)
1-1: Restore portable shebang
/bin/envis non-portable and breaks on systems whereenvlives under/usr/bin. Please switch back to/usr/bin/env python3so the interpreter is resolved via PATH.-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/ansible/setup.py (1)
1-1: Use/usr/bin/envfor portabilityKeeping
/bin/envwill fail on most POSIX environments that only ship/usr/bin/env. Please update the shebang accordingly.-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/result_upload/setup.py (1)
1-1: Fix the shebang path
envtypically resides in/usr/bin; using/bin/envbreaks compatibility. Please switch to/usr/bin/env python3.-#!/bin/env python3 +#!/usr/bin/env python3python-avocado.spec (1)
243-250: Verify the conditional block structure is correct.The nested conditional blocks at lines 246-250 and 259-263 use
%if ! 0%{?rhel}followed immediately by another%if ! 0%{?fedora} > 35. Ensure that this nesting is intentional and that the logic correctly excludes packages only on non-RHEL systems where Fedora > 35.Additionally, the past review flagged that the
avocado_result_html*exclusion path on Line 245 is incorrect and should point to%{python3_sitelib}/optional_plugins/html/avocado_result_html*instead of%{python3_sitelib}/avocado_result_html*.Run the following script to verify the actual installation path of avocado_result_html:
#!/bin/bash # Description: Verify the installation path of avocado_result_html package # Search for avocado_result_html references in optional_plugins structure fd -t d 'avocado_result_html' optional_plugins/Also applies to: 259-263
examples/plugins/cli-cmd/hello_priority/pyproject.toml (1)
10-11: Avoid duplicate CLI entry-point names.Both
examples/plugins/cli-cmd/hello/pyproject.tomland this file define the entry pointhellounder[project.entry-points."avocado.plugins.cli.cmd"]. This creates a naming collision that could cause issues when both plugins are installed. Consider renaming this entry point tohello_priorityto match the module name and avoid conflicts.Apply this diff to fix the collision:
[project.entry-points."avocado.plugins.cli.cmd"] -hello = "hello_priority:HelloWorld" +hello_priority = "hello_priority:HelloWorld"setup.py (1)
39-176: Entry_points duplication is documented and acknowledged.The 130+ line entry_points configuration duplicates pyproject.toml as noted in your comments (lines 24-25, 38). This duplication creates maintenance burden but is necessary for egg build compatibility during the transition period.
.github/workflows/ci.yml (3)
89-89: Redundant version flags remain.The command combines both
-Vand--versionflags, which is redundant. This issue was previously flagged but still appears in the code.
131-131: Redundant version flags remain.Same issue as Line 89: the command combines both
-Vand--versionflags redundantly. This was previously flagged.
167-167: Redundant version flags in Windows workflow.The Windows workflow also has the redundant
-V --versionflags. For consistency, this should be corrected along with Lines 89 and 131.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (7)
38-46: Timeout options need explicit integer type.The
setup_timeoutandtest_timeoutoptions register with integer defaults but lackkey_type=int, which may result in string values being returned by the config system, breaking timeout arithmetic.
106-114: Missing error handling for slot initialization.Reading JSON configuration files and creating remote sessions can fail (malformed JSON, missing files, connection failures), but no error handling is present. A single bad slot configuration will crash the spawner.
136-146: Shell injection risk in task identifier.The task identifier is interpolated directly into the shell command without escaping. Special characters in the identifier (spaces, quotes, shell metacharacters) will break the command or create security risks. Past review indicated this was addressed, but the code still lacks escaping.
182-182: Critical: Output redirection discards all test results.Redirecting to
/dev/nullloses all test output, results, logs, stdout, and stderr, defeating the purpose of remote execution and making debugging impossible.
195-201: Use unique, sanitized remote directory path.The fixed
/tmp/.avocado_task_output_dirpath can cause collisions and TOCTOU security issues. Use a unique per-task directory with a sanitized identifier.
202-206: Missing timeout in wait loop.The
wait_taskloop has no timeout, risking indefinite blocking ifis_task_alivehas a bug or the task hangs.
208-216: Fix logging message and use exception logging.Line 215 lacks an f-string prefix, so
{session.host}won't interpolate. Additionally, uselogging.exceptioninstead oflogging.errorto capture the traceback for debugging.
🧹 Nitpick comments (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
70-78: Consider adding ClassVar annotations for mutable class attributes.The
METHODSandslots_cacheclass attributes are mutable and should be annotated withtyping.ClassVarfor better type checking support.+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar = {}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (67)
.github/actions/version/action.yml(1 hunks).github/actions/wheel/action.yml(1 hunks).github/workflows/ci.yml(17 hunks).github/workflows/prerelease.yml(2 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(4 hunks)Makefile.gh(2 hunks)contrib/scripts/avocado-safeloader-find-python-unittest(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/pre_release/tests/check-copr-rpm-version.sh(1 hunks)selftests/run_coverage(1 hunks)setup.py(2 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/tests/magic/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_yaml_to_mux/README.rst
🚧 Files skipped from review as they are similar to previous changes (27)
- optional_plugins/varianter_cit/pyproject.toml
- .github/workflows/release.yml
- contrib/scripts/avocado-safeloader-find-python-unittest
- optional_plugins/mail/pyproject.toml
- .github/workflows/vmimage.yml
- examples/plugins/cli-cmd/hello/pyproject.toml
- selftests/run_coverage
- optional_plugins/varianter_pict/setup.py
- optional_plugins/ansible/README.rst
- docs/source/guides/writer/chapters/subclassing.rst
- optional_plugins/README.rst
- optional_plugins/golang/pyproject.toml
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/robot/pyproject.toml
- optional_plugins/varianter_pict/pyproject.toml
- spell.ignore
- selftests/pre_release/tests/check-copr-rpm-version.sh
- optional_plugins/varianter_cit/setup.py
- optional_plugins/result_upload/pyproject.toml
- optional_plugins/ansible/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- examples/plugins/README.rst
- .github/workflows/push_ci.yml
- examples/plugins/tests/rogue/pyproject.toml
- optional_plugins/html/pyproject.toml
- .github/actions/version/action.yml
- pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (1)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (1)
Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 129-129: Missing required phony target "all"
(minphony)
[warning] 129-129: Missing required phony target "test"
(minphony)
🪛 Ruff (0.13.3)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (41)
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Linux with Python 3.13
- GitHub Check: Linux with Python 3.9
- GitHub Check: Linux with Python 3.10
- GitHub Check: Linux with Python 3.12
- GitHub Check: Linux with Python 3.11
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (33)
examples/plugins/tests/README.rst (1)
15-16: LGTM!The update from
python setup.py develop --usertopip install -e .correctly reflects modern Python packaging best practices and aligns with the migration to pyproject.toml-based configuration.Makefile.gh (2)
79-82: Ensure all plugin directories support egg building.Similar to the wheel build target, the egg build target now runs unconditionally. If a plugin directory doesn't have a valid setup.py that supports
bdist_egg, the build will fail.Consider validating that all plugin directories support the required build commands, or add error handling to skip plugins that cannot build eggs.
66-69: All optional plugin directories have valid packaging configuration Verified that each directory underoptional_pluginsincludes eithersetup.pyorpyproject.toml; no further validation needed..github/actions/wheel/action.yml (1)
12-16: Verify wheel installation and PATH handling.The workflow installs the wheel to
/tmp/avocado_installand modifies PYTHONPATH, but this approach has some concerns:
- Using
-t(target directory) instead of proper installation may miss script/entrypoint creation- No cleanup of
/tmp/avocado_installbetween runs could cause test pollution- The Python one-liner approach is unconventional compared to calling
avocadodirectlyConsider testing the installed avocado command directly (if entry points are properly installed) rather than using Python one-liners:
python3 -m pip install dist/*.whl avocado run /bin/true cd /tmp avocado run /bin/trueThis would verify that entry points are correctly installed and accessible.
python-avocado.spec (3)
8-8: LGTM!The tarball naming change from
avocado-%{version}.tar.gztoavocado_framework-%{version}.tar.gzaligns with the broader pyproject.toml-based packaging migration across the PR.Also applies to: 18-18
102-104: LGTM!The setup directory name changes from
avocado-%{version}toavocado_framework-%{version}correctly match the updated tarball naming conventions.
220-220: LGTM!The selftests invocation has been correctly updated to use
python3 -m selftests.check, consistent with the module-based invocation pattern adopted throughout the PR.optional_plugins/resultsdb/pyproject.toml (1)
1-48: LGTM!The pyproject.toml configuration for the resultsdb plugin follows the standard pattern established across other plugins in this PR. The previously flagged urllib3 constraint issue has been addressed (the impossible
urllib3<2.3.0; python_version < '3.9'constraint has been removed), and the current dependencies are appropriate for the Python 3.9+ requirement..github/workflows/prerelease.yml (2)
25-26: LGTM!The migration from direct pip invocations to
python3 -m pipand fromsetup.py developtopython3 -m pip install -e . --useraligns with modern Python packaging best practices and is consistent with the broader migration across the repository.Also applies to: 28-28
48-49: LGTM!The updates to use module-based invocations (
python3 -m pipandpython3 -m selftests.check) are consistent with the workflow standardization across the PR and follow Python best practices.Also applies to: 51-51
docs/source/guides/contributor/chapters/environment.rst (1)
55-62: LGTM!The documentation correctly updates the development installation instructions to use
pip install -e .instead of the deprecatedpython3 setup.py develop. The revised description accurately explains the editable install mechanism, including the creation of the egg info directory and the need to re-run the command only when adding new entry points.optional_plugins/spawner_remote/pyproject.toml (1)
1-45: LGTM!The pyproject.toml configuration for the spawner_remote plugin follows the established pattern. The previously flagged issue with missing
.spawnermodule component in the entry point paths has been addressed—the current entry points correctly referenceavocado_spawner_remote.spawner:RemoteSpawnerInitandavocado_spawner_remote.spawner:RemoteSpawner..github/workflows/weekly.yml (2)
37-39: LGTM!The workflow correctly adopts module-based invocations for pip and selftests, consistent with the standardization across all CI workflows in this PR.
Also applies to: 47-47
81-83: LGTM!The updates maintain consistency with the module-based invocation pattern established across the repository's CI workflows.
Also applies to: 89-89
docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM!The plugin registration documentation correctly updates to reflect pyproject.toml-based packaging and the use of
pip install -e .for editable installs.
111-114: LGTM!The entry point example has been correctly updated to the pyproject.toml TOML format, accurately reflecting the new packaging standard.
170-173: LGTM!The settings plugin registration example correctly demonstrates the pyproject.toml entry point format.
325-327: LGTM!The test type plugin activation instructions correctly reference pyproject.toml and use
pip install -e .for installation.optional_plugins/spawner_remote/setup.py (1)
1-6: LGTM! Clean migration to pyproject.toml.The minimal setup.py shim correctly maintains backward compatibility for egg builds while moving configuration to pyproject.toml. The transitional comment clearly explains the purpose.
examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: LGTM! Well-structured pyproject.toml configuration.The build system, project metadata, and entry-point configuration follow standard conventions and are properly aligned with Avocado's plugin architecture.
Makefile (4)
9-10: LGTM! Clear documentation for new plugin development targets.The help text for the new
develop-pluginsanddevelop-plugintargets is clear and informative.
33-61: LGTM! Comprehensive cleanup improvements.The enhanced
cleantarget with explicit loops for plugins and examples, along with improved error handling, makes the build process more robust and maintainable.
63-108: LGTM! Successful migration to pip-based workflows.The migration from
setup.pytopython -m pipcommands is correct and aligns with modern Python packaging practices. The new plugin development targets provide a convenient workflow for installing optional plugins.
109-119: LGTM! Robust manpage generation with proper fallbacks.The updated manpage generation logic with fallback between
rst2manandrst2man.py, along with clear error handling, ensures better compatibility across different environments..github/workflows/setup.yml (2)
33-125: LGTM! Consistent migration across installation workflows.The migration from
setup.pytopython3 -m pipcommands is consistently applied across user, system-wide, and developer installation workflows. The changes also correctly update test execution to usemake manandpython3 -m selftests.check.
149-219: LGTM! Complete workflow migration.The remaining workflow jobs (system-wide developer and virtualenv installations) correctly adopt the pip-based installation pattern, maintaining consistency across all CI workflows.
setup.py (1)
16-36: LGTM! Clear documentation of backward compatibility approach.The header comments clearly explain the purpose of this minimal setup.py file and acknowledge the entry_points duplication for egg build support. The version reading logic is straightforward.
.github/workflows/ci.yml (3)
28-32: LGTM! Static checks workflow updated correctly.The migration to
python3 -m pipandpython3 -m selftests.checkis correct and consistent with the overall packaging modernization.
169-169: LGTM! Setuptools installation fixed correctly.The setuptools fallback command has been corrected to use
python -m pip installinstead of the erroneouspython -m python3 -m pippattern.
265-536: LGTM! Comprehensive CI workflow modernization.The CI workflow updates consistently adopt pip-based installation patterns across all platform-specific jobs (Fedora, UBI, Debian, Ubuntu). The explicit installation of
python3-pipensures the required tooling is available.examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM! Standard plugin packaging configuration.The pyproject.toml follows the same well-structured pattern as other plugin examples, with proper build system, metadata, and entry-point configuration.
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
79-90: LGTM! Robust async command execution.The
run_remote_cmd_asyncmethod properly handles shell timeouts and process termination errors, providing clear error messages.
218-233: LGTM! Stub methods for future implementation.These stub methods provide the required interface for the Spawner base class. The unused
runtime_taskarguments are intentional placeholders for future implementation.
.github/actions/wheel/action.yml
Outdated
| - name: Test running avocado from wheels | ||
| shell: sh | ||
| run: | | ||
| export PIP_BREAK_SYSTEM_PACKAGES=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using PIP_BREAK_SYSTEM_PACKAGES in CI workflows.
Setting PIP_BREAK_SYSTEM_PACKAGES=1 bypasses pip's externally-managed-environment protection, which can lead to system package conflicts and unstable CI environments. This flag is intended only for containerized environments where breaking system packages is acceptable.
Consider these alternatives:
- Use a virtual environment for isolation
- Use
--userflag with pip install - If running in a container, document why this flag is necessary
Apply this diff to use a virtual environment instead:
- export PIP_BREAK_SYSTEM_PACKAGES=1
- python3 -m pip install build wheel setuptools
+ python3 -m venv /tmp/avocado_venv
+ . /tmp/avocado_venv/bin/activate
+ pip install build wheel setuptoolsCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In .github/actions/wheel/action.yml around line 9 the workflow exports
PIP_BREAK_SYSTEM_PACKAGES=1 which bypasses pip's protection; remove that export
and instead create and activate a virtual environment in the action before
running pip (python -m venv <env> then source <env>/bin/activate or use the
setup-python action to create venv-like isolation), install packages into that
venv (or use pip install --user as an alternative), and add a comment explaining
why a venv is used; if this action truly runs in a container and you must keep
the flag, document the rationale rather than exporting it unconditionally.
|
The change will also include some enhance but also introduce some regression that make CI no green, I will do some debug until all CI green again, then split to multiple commits. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (10)
setup.py (1)
167-296: Acknowledged: Entry points duplication is a known trade-off.The 130-line entry_points dictionary duplicates configuration from pyproject.toml for egg build compatibility, as noted in lines 24-25. This is a known maintenance burden.
Consider adding a CI validation step that compares entry_points between setup.py and pyproject.toml to catch drift.
pyproject.toml (2)
14-16: Critical: Restore runtime dependencies.The
[project].dependencieslist contains only"setuptools", but the core package imports third-party modules (e.g.,avocado.plugins.sysinfoimportspsutil,avocado.utils.assetimportsrequests, varianter plugins rely onjsonschema). Without these dependencies,pip install avocado-frameworkwill succeed but fail at runtime withImportError.Please restore the full dependency list from the former
setup.pyinto this section.
30-30: Remove unsupported Python 3.14 classifier.The classifier
"Programming Language :: Python :: 3.14"is not yet published by PyPI. Including it will cause upload rejections with "Invalid classifier" errors. Remove this line and re-add only after PyPI officially supports it.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (7)
38-46: Register timeouts as integers (prevents type bugs).Without key_type=int, values become strings, breaking arithmetic/timeouts downstream. See avocado.core.settings.register_option.
Apply:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) ... help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )Based on learnings (relevant_code_snippets: avocado/core/settings.py).
106-115: Add error handling when initializing slots (robustness).Malformed/missing files or login failures crash initialization.
Apply:
- with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + continue + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}") + continue + else: + RemoteSpawner.slots_cache[session] = False
143-146: Escape identifier in shell command to avoid breakage/injection.Quote the pattern passed to pgrep.
- status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {safe_identifier}")
182-185: Do not discard remote output.Redirecting to /dev/null loses test logs/results; breaks debugging.
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Optionally, redirect to a file and collect it later.
195-201: Avoid fixed /tmp path; use a unique, sanitized per-task dir.Prevents collisions and improves isolation.
- output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier) + output_lxc_path = f"/tmp/avocado-task-{safe_id}"If needed, create it before running the task:
# In spawn_task, before executing the command: await RemoteSpawner.run_remote_cmd_async(session, f"mkdir -p {shlex.quote(runtime_task.task.runnable.output_dir)}", 30)
202-206: Add a wait timeout to avoid infinite loops.Prevents hangs when tasks never terminate or liveness checks fail.
- async def wait_task(self, runtime_task): - while True: - if not RemoteSpawner.is_task_alive(runtime_task): - return - await asyncio.sleep(0.1) + async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start = asyncio.get_running_loop().time() + while True: + if not RemoteSpawner.is_task_alive(runtime_task): + return + if asyncio.get_running_loop().time() - start > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return + await asyncio.sleep(0.1)
208-216: Fix logging and include traceback on termination failure.Current message lacks f-string and loses context.
- try: - session.read_up_to_prompt() - return True - except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") - return False + try: + session.read_up_to_prompt() + except exceptions.ExpectTimeoutError: + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") + return False + else: + return True
🧹 Nitpick comments (13)
optional_plugins/robot/avocado_robot/robot.py (1)
41-42: Consider more explicit type checking.The
hasattr()check is functional but may mask errors iftest_case.namedoesn't exist or isn't a string. Consider usingisinstance()orgetattr()with a default value for more robust handling.Apply this diff for a more explicit approach:
- # Handle both string (old API) and TestCase object (new API) - test_name = test_case.name if hasattr(test_case, 'name') else test_case + # Handle both string (old API) and TestCase object (new API) + test_name = getattr(test_case, 'name', test_case)Alternatively, if the type is known, use
isinstance()checks:# Handle both string (old API) and TestCase object (new API) if isinstance(test_case, str): test_name = test_case else: test_name = test_case.name.github/workflows/ci.yml (4)
27-30: Migrate from setup.py develop to pip editable install.For consistency with the rest of the PR and modern packaging, switch to pip editable:
- - name: Installing Avocado in develop mode - run: python3 setup.py develop --user + - name: Installing Avocado in develop mode + run: python3 -m pip install --user -e .
94-98: Same here: use pip editable install.Replace setup.py develop with pip -e:
- - name: Installing Avocado in develop mode - run: python3 setup.py develop --user + - name: Installing Avocado in develop mode + run: python3 -m pip install --user -e .
132-136: macOS: avoid setup.py, prefer pip editable.Also align interpreter usage to python3:
- - name: Install avocado - run: | - python3 -m pip install -r requirements-dev.txt - python setup.py develop --user + - name: Install avocado + run: | + python3 -m pip install -r requirements-dev.txt + python3 -m pip install --user -e .
96-99: Avoid PATH issues by invoking avocado as a module.User installs may not add ~/.local/bin to PATH. Use module invocation:
- - name: Avocado version - run: avocado --version + - name: Avocado version + run: python3 -m avocado --versionMakefile (3)
124-124: Add missing PHONY targets (all, test).Satisfy checkmake and clarify intent:
-.PHONY: pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables man +.PHONY: all test pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables man + +# Optional: alias test to check to satisfy tools expecting a 'test' target +test: checkStatic analysis flagged these (minphony). Based on hints.
82-84: Consider using pip editable for develop.Align with pyproject/pip flow:
-develop: - $(PYTHON) setup.py develop $(PYTHON_DEVELOP_ARGS) +develop: + $(PYTHON) -m pip install -e . $(PYTHON_DEVELOP_ARGS)
108-114: Use automatic variables in manpage rule.More idiomatic and future-proof:
-%.1: %.rst - @if command -v rst2man >/dev/null 2>&1; then \ - rst2man man/avocado.rst man/avocado.1; \ +%.1: %.rst + @if command -v rst2man >/dev/null 2>&1; then \ + rst2man $< $@; \.github/workflows/setup.yml (3)
112-114: Invoke pip via Python for reliability.Avoid pip3/which-pip issues:
- - name: Install dependencies - run: pip3 install -r requirements-dev.txt + - name: Install dependencies + run: python3 -m pip install -r requirements-dev.txt
148-151: Same here: use python -m pip.- - name: Install dependencies - run: pip3 install -r requirements-dev.txt + - name: Install dependencies + run: python3 -m pip install -r requirements-dev.txt
176-179: Install python3-venv instead of virtualenv when using venv.You're using
python3 -m venv, so installpython3-venv:- sudo apt-get install -y python3-virtualenv + sudo apt-get install -y python3-venvoptional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
72-75: Annotate mutable class attributes as ClassVar to avoid shared-state lint issues.Silences Ruff RUF012 and clarifies intent.
+from typing import ClassVar ... - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar[list] = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar[dict] = {}
81-85: Use asyncio.get_running_loop() in async context.get_event_loop() is deprecated in 3.10+ when called in coroutines.
- loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop()
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (63)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)setup.py(3 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/tests/rogue/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_pict/README.rst
- optional_plugins/ansible/README.rst
🚧 Files skipped from review as they are similar to previous changes (22)
- examples/plugins/tests/rogue/pyproject.toml
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- selftests/run_coverage
- examples/plugins/tests/magic/pyproject.toml
- optional_plugins/robot/pyproject.toml
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/mail/setup.py
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
- optional_plugins/resultsdb/setup.py
- examples/plugins/test-pre-post/hello/pyproject.toml
- examples/plugins/cli-cmd/hello/pyproject.toml
- .github/workflows/vmimage.yml
- optional_plugins/resultsdb/pyproject.toml
- Makefile.gh
- examples/plugins/tests/README.rst
- .github/workflows/push_ci.yml
- optional_plugins/spawner_remote/pyproject.toml
- optional_plugins/html/pyproject.toml
- optional_plugins/README.rst
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (41)
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (32)
optional_plugins/robot/avocado_robot/robot.py (2)
43-45: LGTM!The change from storing raw
test_caseto the normalizedtest_nameimproves consistency and ensures the dictionary always contains string test names regardless of the Robot Framework API version.
41-45: Verify the relationship to pyproject.toml migration.This API compatibility change appears unrelated to the PR's stated objective of migrating from setup.py to pyproject.toml. Please confirm whether this change is:
- A side effect of updating Robot Framework or other dependencies
- An independent fix that happened to be included in this PR
- Related to the migration in a way not immediately obvious from the PR description
If this is a separate concern, consider extracting it to a dedicated PR or documenting the connection in the PR description.
optional_plugins/varianter_pict/setup.py (1)
2-6: LGTM! Clean migration approach.The transition strategy is well-documented. Keeping setup.py as a compatibility shim while moving primary configuration to pyproject.toml aligns with modern Python packaging standards (PEP 517/621).
optional_plugins/varianter_yaml_to_mux/setup.py (1)
2-6: Consistent migration pattern.This follows the same clean transition approach as other plugins, maintaining backward compatibility while centralizing configuration in pyproject.toml.
examples/plugins/README.rst (1)
10-24: Clear and accurate workflow documentation.The updated examples correctly demonstrate the modern pip-based development workflow, replacing deprecated
python setup.pycommands with their pip equivalents.optional_plugins/robot/setup.py (1)
2-6: Consistent with the migration pattern.The transition approach matches other plugins, properly delegating configuration to pyproject.toml.
optional_plugins/html/setup.py (1)
2-6: Correct transition implementation.The migration follows the established pattern across plugins, maintaining compatibility while modernizing the packaging configuration.
docs/source/guides/writer/chapters/subclassing.rst (1)
20-101: Comprehensive and accurate modernization guide.The updated documentation provides a complete example of modern Python packaging using pyproject.toml. The example demonstrates:
- Proper build-system configuration with setuptools>=61.0
- Dynamic version sourcing from VERSION file
- Correct dependency declaration
- Modern installation workflow with pip
optional_plugins/varianter_cit/setup.py (1)
2-6: Standard migration implementation.Correctly implements the transition pattern with proper documentation of the backward compatibility shim.
optional_plugins/varianter_cit/pyproject.toml (1)
1-44: Configuration verified: entry points and dynamic files present
All entry points reference existing classes and the VERSION/README files are present.examples/plugins/job-pre-post/sleep/pyproject.toml (1)
1-17: LGTM!The pyproject.toml configuration for the sleep plugin is correctly structured with appropriate build system requirements, project metadata, and entry points for the job pre/post hooks.
optional_plugins/mail/pyproject.toml (1)
1-43: LGTM!The pyproject.toml configuration for the mail notification plugin is correctly structured with appropriate dependencies on the core framework, proper entry points, and dynamic version/readme handling.
optional_plugins/ansible/pyproject.toml (1)
1-47: LGTM!The pyproject.toml configuration for the Ansible plugin is well-structured with:
- Appropriate dependencies (avocado-framework, cffi, pycparser, ansible-core)
- Console script for the ansible module runner
- Proper entry point for the runnable runner plugin
- Package discovery pattern for avocado_ansible modules
optional_plugins/ansible/setup.py (1)
2-6: LGTM!The setup.py has been correctly reduced to a minimal compatibility shim. The transitional comment clearly explains the purpose, and the bare
setup()call delegates to pyproject.toml configuration, which is the modern approach.setup.py (1)
16-26: LGTM!The docstring clearly explains the purpose of keeping setup.py for backward compatibility and egg builds. The note about entry_points duplication is explicit and sets expectations for maintainers.
python-avocado.spec (4)
8-8: LGTM!The tarball name change from
avocado-%{version}.tar.gztoavocado_framework-%{version}.tar.gzaligns with the pyproject.toml-based packaging structure.
102-104: LGTM!The %setup directory name changes from
avocado-%{version}toavocado_framework-%{version}correctly match the updated tarball naming convention.
220-220: LGTM!The change to module-based invocation (
%{python3} -m selftests.check) is the modern Python best practice and aligns with the pyproject.toml migration.
243-245: Exclusions are correct: Verified thatcontrib*,scripts*, andavocado_result_html*match actual directories (contrib/,scripts/,optional_plugins/html/avocado_result_html/); no changes needed.examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM!The pyproject.toml configuration for the hello_parser CLI plugin is correctly structured with appropriate build system requirements, project metadata, and entry point mapping to the CLI command group.
pyproject.toml (1)
168-232: Optional plugin package names are consistent. Verified that each entry in the rootpyproject.tomlmatches its respective plugin’spyproject.toml.docs/source/guides/contributor/chapters/plugins.rst (2)
97-101: Documentation correctly updated for pyproject.toml migration.The changes properly reflect the migration from setup.py to pyproject.toml-based configuration, including the updated installation command using
pip install -e .for development mode.
111-114: Entry-point format correctly updated to TOML syntax.The entry-point example properly demonstrates the TOML-based format using
[project.entry-points."avocado.plugins.job.prepost"]instead of the old setuptools dictionary format.optional_plugins/result_upload/pyproject.toml (1)
1-44: Well-structured pyproject.toml configuration.The pyproject.toml file is properly configured with:
- Build system declaration using setuptools>=61.0
- Complete project metadata including name, description, authors, and license
- Correct Python version requirement (>=3.9)
- Proper entry-point registration for both CLI and result plugins
- Dynamic version and readme loading from VERSION and README.rst files
optional_plugins/result_upload/setup.py (1)
2-6: Backward compatibility approach is correct.The bare
setup()call with a clear comment explaining the transition period is the recommended approach for maintaining backward compatibility while migrating to pyproject.toml-based configuration.optional_plugins/golang/setup.py (1)
2-6: Consistent backward compatibility approach.The setup.py follows the same pattern as other migrated plugins, with a bare
setup()call and clear transitional comment. This ensures consistent backward compatibility across the project..github/workflows/prerelease.yml (1)
48-49: Installation commands correctly updated.The migration to
python3 -m pipfor both dependency installation and editable install aligns with the new pyproject.toml-based workflow and follows Python best practices..github/actions/version/action.yml (1)
9-11: Verify the necessity of--break-system-packagesflag.The
--break-system-packagesflag bypasses pip's protection against installing packages that conflict with system packages. While this may be necessary in containerized or specific CI environments, ensure this is intentional and required.If this workflow runs in a controlled CI environment where system package conflicts are not a concern, the flag is acceptable. Otherwise, consider using a virtual environment or removing this flag.
.github/workflows/weekly.yml (2)
39-47: Workflow commands correctly migrated to module-based invocations.The changes properly migrate from
setup.py developtopip install --user -e .and from script-based execution topython3 -m selftests.check, aligning with modern Python packaging practices and the pyproject.toml migration.
83-89: Consistent module-based invocations in without-plugins job.The without-plugins job correctly uses the same module-based approach, with appropriate plugin disabling via
--disable-plugin-checksfor testing without optional dependencies.optional_plugins/spawner_remote/setup.py (1)
2-6: Consistent migration pattern maintained.The spawner_remote plugin follows the same backward compatibility pattern as other migrated plugins, ensuring consistency across the project during the transition period.
optional_plugins/golang/pyproject.toml (1)
5-25: LGTM for plugin packaging.Metadata, entry points, and dynamic fields look correct. No issues found.
| python3 -m pip install --user -e . | ||
| - name: Avocado pre-release job | ||
| run: python3 setup.py test --select=pre-release,vmimage | ||
| run: python3 -m selftets.check --select=pre-release,vmimage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical typo in module name.
The command contains a typo: selftets.check should be selftests.check. This will cause the workflow to fail with a module not found error.
Apply this diff:
- run: python3 -m selftets.check --select=pre-release,vmimage
+ run: python3 -m selftests.check --select=pre-release,vmimage📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| run: python3 -m selftets.check --select=pre-release,vmimage | |
| run: python3 -m selftests.check --select=pre-release,vmimage |
🤖 Prompt for AI Agents
In .github/workflows/prerelease.yml at line 51, the workflow command misspells
the Python module as "selftets.check"; update it to "selftests.check" so the run
step reads the correct module name, ensuring the workflow invokes python3 -m
selftests.check --select=pre-release,vmimage.
| @with_slot_reservation | ||
| async def spawn_task(self, runtime_task): | ||
| self.create_task_output_dir(runtime_task) | ||
| task = runtime_task.task | ||
| full_module_name = ( | ||
| runtime_task.task.runnable.pick_runner_module_from_entry_point_kind( | ||
| runtime_task.task.runnable.kind | ||
| ) | ||
| ) | ||
| if full_module_name is None: | ||
| msg = f"Could not determine Python module name for runnable with kind {runtime_task.task.runnable.kind}" | ||
| raise RemoteSpawnerException(msg) | ||
| # using the "python" symlink will result in the container default python version | ||
| entry_point_args = ["python3", "-m", full_module_name, "task-run"] | ||
| entry_point_args.extend(task.get_command_args()) | ||
|
|
||
| session = runtime_task.spawner_handle | ||
| LOG.info(f"Hostname: {session.host} Port: {session.port}") | ||
|
|
||
| setup_hook = self.config.get("spawner.remote.setup_hook") | ||
| # Customize and deploy test data to the container | ||
| if setup_hook: | ||
| setup_timeout = self.config.get("spawner.remote.setup_timeout") | ||
| status, output = await RemoteSpawner.run_remote_cmd_async( | ||
| session, setup_hook, setup_timeout | ||
| ) | ||
| LOG.debug(f"Customization command exited with code {status}") | ||
| if status != 0: | ||
| LOG.error( | ||
| f"Error exit code {status} on {session.host}:{session.port} " | ||
| f"from setup hook with output:\n{output}" | ||
| ) | ||
| return False | ||
|
|
||
| cmd = shlex.join(entry_point_args) + " > /dev/null" | ||
| timeout = self.config.get("spawner.remote.test_timeout") | ||
| status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) | ||
| LOG.debug(f"Command exited with code {status}") | ||
| if status != 0: | ||
| LOG.error( | ||
| f"Error exit code {status} on {session.host}:{session.port} " | ||
| f"with output:\n{output}" | ||
| ) | ||
| return False | ||
|
|
||
| return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spawn_task blocks until completion; breaks spawner semantics and concurrency.
run_remote_cmd_async waits for the command to finish, so spawn_task is synchronous. This defeats wait_task/is_task_alive and prevents parallelism.
Recommendation:
- Launch the remote task in background (e.g.,
nohup ... >/tmp/log 2>&1 & echo $!), store the PID/handle in runtime_task.spawner_handle, and return True immediately. - Update is_task_alive to check the stored PID, and wait_task to poll until the process exits.
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around
lines 148-193, spawn_task currently waits for the remote command to finish
because run_remote_cmd_async is used for the entry-point execution; change it to
launch the remote process in the background and return immediately: build a
background-safe command (e.g., wrap the entry_point_args with nohup ...
>/tmp/<taskid>.log 2>&1 & echo $!), run that via run_remote_cmd_async, capture
the echoed PID from the command output, store that PID (and any remote
host/port/session info) on runtime_task.spawner_handle (or add a small .pid
field), and return True without waiting for process completion; keep the
setup_hook execution synchronous if needed but keep the task launch
non-blocking; then update is_task_alive to check the stored PID on the remote
host (e.g., kill -0 or ps check) and update wait_task to poll the PID until it
exits, returning exit status/output as appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (11)
optional_plugins/robot/pyproject.toml (1)
16-16: Update Robot Framework version constraint.The dependency constraint
"robotframework"has no upper bound, but a previous review suggested adding<8.0to support the latest 7.x releases while preventing breaking changes from 8.x.pyproject.toml (2)
14-16: Critical: Missing runtime dependencies.The
[project].dependenciessection only contains"setuptools", but the core package imports third-party modules likepsutil,requests, andjsonschema. Without these dependencies, users will encounterImportErrorat runtime after installation.
30-30: Major: Remove unsupported Python 3.14 classifier.PyPI does not yet support the
"Programming Language :: Python :: 3.14"classifier, which will cause package upload failures.optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
38-46: Major: Timeout options needkey_type=int.Without
key_type=int, the configuration values will be strings, breaking arithmetic and timeout logic downstream.
106-114: Critical: Add error handling for slot initialization.Slot initialization can fail due to malformed JSON, missing files, or connection failures. Without error handling, a single bad slot will crash the spawner.
136-146: Major: Escape task identifier in shell command.The task identifier is interpolated directly into the shell command without escaping, creating command injection risk and breakage with special characters.
148-193: Major: spawn_task blocks until completion, breaking spawner semantics.Using
run_remote_cmd_asyncto execute the task makesspawn_tasksynchronous, defeating the purpose ofwait_taskand preventing concurrency.
182-182: Critical: Output redirection loses all test results.Redirecting output to
/dev/nulldiscards all test output, logs, and results, making debugging impossible.
195-201: Major: Use sanitized, unique remote directory path.The fixed
/tmp/.avocado_task_output_dirpath creates collision and TOCTOU risks.
202-206: Major: Add timeout to prevent infinite waiting.The wait loop has no timeout, potentially blocking the job runner indefinitely.
208-216: Minor: Fix logging and add traceback on termination failure.The error log lacks f-string interpolation and should use
logging.exceptionfor context.
🧹 Nitpick comments (2)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
70-74: Annotate mutable class attributes withClassVar.Static analysis correctly identifies that
slots_cacheshould be annotated withtyping.ClassVarto clarify it's shared across instances.Apply this diff:
+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + slots_cache: ClassVar[dict] = {}Makefile (1)
124-124: Static analysis note: optional PHONY targets.The static analysis tool suggests adding "all" and "test" to the PHONY declarations. While these are common conventions in Makefiles, they're not strictly required for this project. The current PHONY declaration covers all the actual targets that need it.
Based on static analysis hints
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(0 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(0 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(0 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(0 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(0 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(0 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(0 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(0 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (9)
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello/setup.py
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
- examples/plugins/tests/rogue/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/spawner_remote/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (23)
- examples/plugins/tests/rogue/pyproject.toml
- examples/plugins/cli-cmd/hello/pyproject.toml
- .github/workflows/push_ci.yml
- .github/workflows/weekly.yml
- optional_plugins/result_upload/pyproject.toml
- optional_plugins/ansible/pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/README.rst
- examples/plugins/tests/README.rst
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/html/setup.py
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- selftests/run_coverage
- optional_plugins/varianter_cit/setup.py
- optional_plugins/mail/pyproject.toml
- .github/workflows/prerelease.yml
- optional_plugins/resultsdb/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- examples/plugins/README.rst
- python-avocado.spec
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Fedora develop install/uninstall task
- GitHub Check: Build Package (wheel/tarball) for Python 3.11
- GitHub Check: Windows with Python 3.13
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Analyze (python)
- GitHub Check: Static checks
🔇 Additional comments (42)
spell.ignore (1)
806-807: LGTM!Adding "pyproject" and "toml" to the spell checker ignore list is appropriate given the introduction of pyproject.toml files throughout the repository.
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: LGTM!The API compatibility handling correctly supports both the legacy string-based test_case and the new TestCase object with a name attribute. The hasattr check is appropriate for detecting the API version at runtime.
optional_plugins/golang/setup.py (1)
2-6: LGTM!The minimal setup.py stub with explanatory comment correctly maintains backward compatibility for egg building while delegating primary configuration to pyproject.toml. This pattern is consistent with the broader migration strategy.
optional_plugins/varianter_yaml_to_mux/setup.py (1)
2-6: LGTM!The setup.py stub follows the established migration pattern, maintaining egg-build compatibility while pyproject.toml handles the primary configuration.
optional_plugins/resultsdb/setup.py (1)
2-6: LGTM!Consistent with the migration pattern across other plugins - minimal setup.py for compatibility with pyproject.toml handling primary configuration.
optional_plugins/varianter_pict/setup.py (1)
2-6: LGTM!Final setup.py stub follows the consistent migration pattern. The uniform approach across all plugins simplifies the transition to pyproject.toml-based packaging.
optional_plugins/ansible/README.rst (1)
16-18: Installation package name is correct. The nameavocado-framework-plugin-ansiblein README matchespyproject.toml.Makefile.gh (1)
65-69: All optional plugins include pyproject.tomlAll current optional plugins have a pyproject.toml, so the unconditional build loop in Makefile.gh is safe.
optional_plugins/mail/setup.py (1)
2-6: LGTM! Minimal setup.py for backward compatibility.The file correctly retains a minimal
setup()call for backward compatibility during the transition to pyproject.toml-based configuration. The comment clearly explains the purpose.examples/plugins/job-pre-post/sleep/pyproject.toml (1)
1-17: LGTM! Clean plugin packaging configuration.The pyproject.toml correctly defines the build system, project metadata, entry points for both init and job prepost plugins, and module configuration. This aligns well with the migration strategy.
pyproject.toml (1)
1-250: Comprehensive pyproject.toml structure looks good.The overall structure is well-organized with proper build system configuration, extensive plugin entry points, optional dependencies grouping, and dynamic version/readme sourcing. Once the dependency and classifier issues are resolved, this will be a solid foundation for the migration.
examples/plugins/test-pre-post/hello/pyproject.toml (1)
1-17: LGTM! Test plugin configuration is correct.The pyproject.toml properly configures entry points for both test pre and post hooks, referencing the
HelloWorldclass from thehellomodule..github/workflows/setup.yml (3)
33-43: LGTM! Installation commands properly migrated to pip.The workflow correctly replaces
setup.pycommands withpython3 -m pip installfor both the main package and plugins. This aligns with modern Python packaging best practices.
115-126: LGTM! Developer workflow commands updated correctly.The developer installation flow properly uses:
python3 -m pip install --user -e .for editable installationmake manfor manpage generationpython3 -m selftests.checkfor running testspython3 -m pip uninstallfor cleanupAll changes are consistent with the pyproject.toml migration.
181-194: LGTM! Virtualenv workflow properly updated.The virtualenv installation correctly uses
python3 -m venvand pip-based commands within the activated environment.optional_plugins/golang/pyproject.toml (1)
1-47: LGTM! Golang plugin packaging is well-structured.The pyproject.toml correctly defines:
- Build system and dependencies (including avocado-framework)
- Script entry point for the golang runner
- Plugin entry points for resolver and runnable runner
- Dynamic version/readme sourcing
- Package discovery configuration
optional_plugins/robot/pyproject.toml (1)
1-48: LGTM! Robot plugin packaging structure is solid.The pyproject.toml properly defines all necessary components for the robot framework plugin, including build system, dependencies, scripts, and entry points.
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
218-233: Stub implementations are acceptable for now.The placeholder implementations for requirement cache methods (
check_task_requirements,is_requirement_in_cache,save_requirement_in_cache,update_requirement_cache) are acceptable stubs. The unused argument warnings from static analysis can be safely ignored for these abstract method implementations.optional_plugins/html/pyproject.toml (1)
1-47: LGTM!The pyproject.toml configuration for the HTML plugin follows modern Python packaging best practices. The build system, dependencies, entry points, and dynamic metadata configuration are all properly structured.
.github/workflows/vmimage.yml (1)
42-42: LGTM!The migration from
setup.py develop --usertopython -m pip install --user -e .is correct and aligns with the PR's modernization goals..github/actions/version/action.yml (1)
9-12: LGTM!The migration to pip-based installation with
PIP_BREAK_SYSTEM_PACKAGESfor CI environments is appropriate, and the directavocado --versioninvocation is correct after pip install.docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM!The documentation correctly updates references from
setup.pytopyproject.tomland provides accurate installation instructions usingpip install -e ..
111-114: LGTM!The TOML-based entry point examples are correct and demonstrate the modern plugin registration approach.
170-173: LGTM!The settings plugin registration example properly shows the pyproject.toml-based configuration.
325-327: LGTM!The test type plugin registration documentation correctly reflects the migration to pyproject.toml and pip-based installation.
optional_plugins/README.rst (2)
10-24: LGTM!The installation and uninstallation instructions are correctly updated to use pip-based commands, with clear examples for specific plugins.
30-34: LGTM!The make target updates (
develop-pluginsanddevelop-plugin) are documented correctly and align with the Makefile changes.Makefile (6)
9-10: LGTM!The help text for the new plugin development targets is clear and informative.
33-61: LGTM!The expanded clean target provides comprehensive cleanup of build artifacts, cache files, and plugin directories. The iteration over optional and example plugins ensures thorough cleanup.
64-67: LGTM!The migration to
python -m pipfor install and uninstall operations follows best practices for modern Python packaging.
80-80: LGTM!The change to
python -m selftests.checkaligns with the project-wide migration to module-based invocations.
91-104: LGTM!The new
develop-pluginsanddevelop-plugintargets provide a clean interface for plugin development. The PLUGIN variable check with usage guidance is a good UX touch.
109-114: LGTM!The enhanced man page generation with explicit error handling for missing
rst2manis a good improvement over silent failures.setup.py (1)
16-26: LGTM!The docstring clearly explains the purpose of keeping setup.py for backward compatibility and the necessity of duplicating entry_points for egg builds. This addresses the concern raised in previous reviews.
.github/workflows/ci.yml (8)
32-32: LGTM!The migration to
python3 -m selftests.checkis consistent with the project-wide modernization.
89-89: LGTM!Using
python -VV(double verbose) is a valid improvement over the previous invalid combination of-V --versionmentioned in past reviews.
93-93: LGTM!The migration to
python3 -m pip installfor dependencies follows best practices.
99-99: LGTM!Using
python3 -m selftests.check --skip=static-checksis the correct module-based invocation.
131-131: LGTM!The
-VVflag provides more verbose version information and is a valid flag.
143-143: LGTM!The module-based test invocation is correct and consistent.
167-171: LGTM!The
-VVflag and pip-based installation are both correct. This addresses the previous review comments about invalid flag combinations and broken setuptools fallback.
265-356: LGTM!The Python dependency installation commands are consistently updated across all container-based version tasks, properly installing python3-pip, python3-venv, and necessary certificates.
b3a3d96 to
918a1d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (13)
optional_plugins/robot/setup.py (1)
1-1: Inconsistency: Past review claims shebang was fixed, but code still incorrect.The past review comment indicates this shebang issue was "✅ Addressed in commit dce17a9", but the code still shows
#!/bin/env python3instead of the portable#!/usr/bin/env python3.Run the following script to verify if the shebang fix was actually applied:
#!/bin/bash # Check if commit dce17a9 exists and what changes it made to this file git log --oneline --all | grep -i dce17a9 git show dce17a9:optional_plugins/robot/setup.py | head -1optional_plugins/varianter_cit/setup.py (1)
1-1: Inconsistency: Past review claims shebang was fixed, but code still incorrect.The past review comment indicates this shebang issue was "✅ Addressed in commits 662fc8c to af71902", but the code still shows
#!/bin/env python3instead of#!/usr/bin/env python3.Run the following script to verify the commit history:
#!/bin/bash # Check if the fix commits exist and verify the current state git log --oneline --all | grep -E '662fc8c|af71902' git show af71902:optional_plugins/varianter_cit/setup.py | head -1optional_plugins/mail/setup.py (1)
1-1: Inconsistency: Past review claims shebang was fixed, but code still incorrect.The past review comment indicates this shebang issue was "✅ Addressed in commits 662fc8c to af71902", but the code still shows
#!/bin/env python3instead of#!/usr/bin/env python3.This is the same issue flagged in other optional_plugins setup.py files. Consider verifying all affected files at once:
#!/bin/bash # Find all setup.py files with incorrect shebang rg -n '^#!/bin/env' --type=py --glob='**/setup.py'optional_plugins/ansible/setup.py (1)
1-1: Inconsistency: Past review claims shebang was fixed, but code still incorrect.The past review comment indicates this shebang issue was "✅ Addressed in commits c31acca to 1352bf5", but the code still shows
#!/bin/env python3instead of#!/usr/bin/env python3.This appears to be a systematic issue across multiple optional_plugins. Verify the commit history and current state:
#!/bin/bash # Check commit history for ansible plugin git log --oneline --all | grep -E 'c31acca|1352bf5' # Verify current state matches what's expected git show 1352bf5:optional_plugins/ansible/setup.py | head -1optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (6)
38-46: Register timeout options as integers.The
setup_timeoutandtest_timeoutoptions are registered withoutkey_type=int, so they will be treated as strings by default. This can cause type errors when the values are used in arithmetic operations or comparisons.Apply this diff to fix both timeout registrations:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-114: Add error handling for slot initialization.Loading slot configuration files can fail in multiple ways (file not found, malformed JSON, connection errors), but there's no error handling. A single bad slot configuration will crash the spawner.
Apply this diff to add robust error handling:
for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
182-182: Critical: Output redirection loses all test results.Redirecting stdout to
/dev/nulldiscards all test output, including results, logs, and error messages. This makes debugging impossible and defeats the purpose of running tests remotely.Remove the output redirection:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)
195-201: Avoid hardcoded /tmp path; use unique remote directory per task.The hardcoded path
/tmp/.avocado_task_output_dircreates collision risks when multiple tasks run concurrently. It's also flagged by static analysis as a security concern.Apply this diff to use a unique, sanitized path per task:
def create_task_output_dir(self, runtime_task): output_dir_path = self.task_output_dir(runtime_task) - output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier) + output_lxc_path = f"/tmp/avocado-task-{safe_id}" os.makedirs(output_dir_path, exist_ok=True) runtime_task.task.setup_output_dir(output_lxc_path)
202-206: Add timeout to prevent infinite waiting.The
wait_taskloop has no timeout, so ifis_task_alivenever returns False (due to a bug or hung task), the spawner will wait indefinitely and block the job runner.Apply this diff to add a configurable timeout:
async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() while True: if not RemoteSpawner.is_task_alive(runtime_task): return + if asyncio.get_event_loop().time() - start_time > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return await asyncio.sleep(0.1)
208-216: Fix logging and include exception traceback.Line 215 is missing the f-string prefix, so the host variable won't be interpolated. Additionally, use
LOG.exceptioninstead ofLOG.errorto capture the full traceback.Apply this diff:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") return False + else: + return Truepyproject.toml (2)
14-16: Restore the project's runtime dependencies.The
dependencieslist contains onlysetuptools, but the Avocado framework requires additional packages at runtime (e.g.,psutilfor system info,requestsfor asset fetching,jsonschemafor validation). Without these dependencies,pip install avocado-frameworkwill succeed but the package will raiseImportErrorwhen imported.Based on learnings, setuptools should only be in
build-system.requires, not in runtime dependencies. Please restore the full dependency list from the formersetup.py(which likely included packages likepsutil,requests,jsonschema, etc.) and move them to[project].dependencies.For optional features, use
[project.optional-dependencies]groups, which are already defined in this file starting at Line 168.
30-30: Remove unsupported Python 3.14 classifier.The trove classifier
"Programming Language :: Python :: 3.14"is not yet published by PyPI. Including it will cause package uploads to PyPI to be rejected with "Invalid classifier" errors.Apply this diff to remove the unsupported classifier:
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]Re-add the classifier only after PyPI officially publishes it.
optional_plugins/varianter_yaml_to_mux/setup.py (1)
1-1: Fix shebang for better portability.The shebang uses
/bin/envwhich is not portable across all systems. Use/usr/bin/envinstead.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3Note: Since this file is now just a compatibility shim during the transition period (as stated in the comment on Line 2), this is a minor issue. However, it's still worth fixing for consistency.
🧹 Nitpick comments (1)
optional_plugins/varianter_pict/setup.py (1)
1-1: Consider fixing shebang for portability.The shebang uses
/bin/envwhich may not be portable across all systems. Consider using/usr/bin/envinstead (though this is a minor portability concern).Apply this diff for better portability:
-#!/bin/env python3 +#!/usr/bin/env python3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (1)
- optional_plugins/result_upload/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (31)
- spell.ignore
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/varianter_pict/README.rst
- optional_plugins/resultsdb/setup.py
- examples/plugins/tests/magic/pyproject.toml
- examples/plugins/tests/rogue/pyproject.toml
- Makefile.gh
- .github/workflows/weekly.yml
- optional_plugins/ansible/README.rst
- optional_plugins/spawner_remote/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- optional_plugins/html/pyproject.toml
- optional_plugins/varianter_pict/pyproject.toml
- examples/plugins/README.rst
- optional_plugins/mail/pyproject.toml
- examples/plugins/test-pre-post/hello/setup.py
- .github/workflows/vmimage.yml
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- .github/workflows/setup.yml
- examples/plugins/tests/README.rst
- .github/workflows/prerelease.yml
- optional_plugins/robot/pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
- .github/workflows/push_ci.yml
- examples/plugins/cli-cmd/hello/setup.py
- optional_plugins/ansible/pyproject.toml
- optional_plugins/spawner_remote/setup.py
- .github/actions/version/action.yml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (49)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Fedora selftests
- GitHub Check: Windows with Python 3.12
- GitHub Check: Windows with Python 3.11
- GitHub Check: Windows with Python 3.10
- GitHub Check: Version task fedora:41
- GitHub Check: Version task ubuntu:24.04
- GitHub Check: Build Package (wheel/tarball) for Python 3.12
- GitHub Check: Build Package (wheel/tarball) for Python 3.13
- GitHub Check: macOS with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (30)
selftests/run_coverage (1)
30-30: LGTM: Module-based test execution.The change from direct script execution to module invocation (
-m selftests.check) aligns with modern Python best practices and the PR's migration goals.examples/plugins/tests/magic/setup.py (1)
1-6: LGTM: Clean migration to pyproject.toml.The minimal setup.py shim correctly delegates all configuration to pyproject.toml while maintaining backward compatibility. The implementation follows best practices with a proper shebang and clear comments.
optional_plugins/golang/setup.py (1)
2-6: LGTM: Minimal setup.py shim for compatibility.The bare setup() call correctly delegates configuration to pyproject.toml while maintaining backward compatibility.
Note: The shebang issue on line 1 was already flagged in a previous review and marked as addressed.
examples/plugins/cli-cmd/hello_option/setup.py (1)
1-6: LGTM: Proper setup.py shim for pyproject.toml migration.The minimal setup.py implementation correctly delegates all packaging configuration to pyproject.toml while maintaining backward compatibility. Shebang and comments are appropriate.
optional_plugins/varianter_pict/setup.py (1)
2-6: LGTM: Clean delegation to pyproject.toml.The minimal setup.py shim properly delegates all configuration to pyproject.toml while maintaining backward compatibility.
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-6: LGTM: Correct migration pattern.The minimal setup.py implementation properly delegates to pyproject.toml with appropriate shebang and documentation comments.
optional_plugins/html/setup.py (1)
2-6: LGTM: Minimal setup.py for pyproject.toml migration.The bare setup() call correctly delegates all packaging configuration to pyproject.toml while maintaining backward compatibility during the transition period.
Note: The shebang issue on line 1 was already flagged in a previous review and marked as addressed.
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: Compatibility fallback correct: thehasattr(test_case, "name")check cleanly handles legacy string names and newTestCaseobjects; no further conditional attribute access is needed.examples/plugins/cli-cmd/hello_parser/setup.py (1)
1-6: LGTM! Clean transition shim.The file correctly implements a minimal setup.py shim for backward compatibility during the pyproject.toml migration. The shebang is portable, and the comment clearly explains the transition strategy.
docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: LGTM! Documentation correctly reflects modern packaging.The pyproject.toml example demonstrates proper configuration with:
- Standard build-system declaration
- Dynamic version sourcing
- Correct dependency specification
88-101: LGTM! Install output accurately reflects pip behavior.The example output correctly shows the modern pip install workflow using pyproject.toml-based builds.
examples/plugins/tests/rogue/setup.py (1)
1-6: LGTM! Proper transition shim implementation.The file correctly implements a minimal setup.py shim with a portable shebang and clear transition documentation.
docs/source/guides/contributor/chapters/plugins.rst (3)
97-101: LGTM! Documentation correctly updated for pyproject.toml.The instructions now properly direct users to configure plugins in pyproject.toml instead of setup.py, and the install command correctly uses
pip install -e .for development mode.
111-114: LGTM! Entry points syntax correctly updated.The example correctly shows the TOML entry points syntax using
[project.entry-points."avocado.plugins.job.prepost"]format.
170-173: LGTM! Settings plugin registration example is accurate.The pyproject.toml entry point syntax for settings plugins is correct.
optional_plugins/result_upload/setup.py (1)
2-6: LGTM! Clean transition to pyproject.toml-based configuration.The minimal setup() approach correctly maintains backward compatibility for egg builds while delegating primary configuration to pyproject.toml. The explanatory comments clearly document the transition strategy.
examples/plugins/job-pre-post/sleep/pyproject.toml (1)
1-17: LGTM! Standard plugin packaging configuration.The pyproject.toml follows the established pattern for Avocado plugins with appropriate build system requirements, entry point declarations, and module packaging configuration.
examples/plugins/job-pre-post/sleep/setup.py (1)
1-6: LGTM! Proper transition approach with correct shebang.The minimal setup() maintains egg build compatibility while the correct
#!/usr/bin/env python3shebang ensures portability.examples/plugins/test-pre-post/hello/pyproject.toml (1)
1-17: LGTM! Consistent plugin configuration.The pyproject.toml properly configures the hello plugin with entry points for both pre and post test hooks. The reuse of the same class for both hooks is appropriate for plugins that handle both phases.
Makefile (5)
9-10: Good addition of plugin development targets.The new
develop-pluginsanddevelop-plugintargets provide convenient workflows for plugin development, consistent with the migration to pip-based installations.
64-67: Improved robustness with module-based pip invocations.Using
python -m pipinstead of callingpipdirectly ensures the correct Python environment's pip is used, avoiding potential version mismatches in multi-Python environments.
99-104: Well-guarded plugin installation with clear error messaging.The explicit check for the PLUGIN variable with a helpful usage message follows best practices for Makefile targets that require parameters.
109-114: Improved error handling for man page generation.The explicit check for
rst2manavailability with a clear error message prevents silent failures during documentation builds.
80-80: Ensure selftests.check is invocable as a moduleVerify that:
selftests/__init__.pyexists soselftests.checkis a package module.check.pyincludes anif __name__ == "__main__":guard for-mexecution.- the
avocado-frameworkdependency is installed (e.g. added to test requirements/CI) soimport selftests.checksucceeds.optional_plugins/README.rst (1)
10-34: LGTM! Clear documentation aligned with new pip-based workflow.The updated instructions provide explicit examples for installing and removing plugins using pip, and correctly reference the new Makefile targets. The documentation now matches the implementation changes throughout the PR.
setup.py (1)
16-26: LGTM! Clear documentation of transition strategy.The docstring effectively explains the backward compatibility purpose and explicitly notes the entry_points duplication for egg builds. This technical debt is appropriately documented.
optional_plugins/golang/pyproject.toml (1)
1-47: Approve Golang plugin pyproject.tomlVerified that
VERSIONandREADME.rstexist; configuration for dynamic version/readme loading, dependencies, entry points, and Python >=3.9 requirement is correct.optional_plugins/resultsdb/pyproject.toml (1)
1-48: LGTM!The pyproject.toml configuration for the resultsdb plugin is well-structured, with proper build-system declaration, project metadata, dependencies, and entry points. The impossible urllib3 constraint mentioned in previous reviews has been correctly removed.
optional_plugins/varianter_yaml_to_mux/README.rst (1)
1-818: LGTM!The formatting changes appropriately replace Sphinx roles with inline code literals for better readability. These are purely documentation improvements with no functional impact.
python-avocado.spec (1)
243-245: No changes required for avocado_result_html exclusion
The plugin’s package directory matches the exclusion pattern%{python3_sitelib}/avocado_result_html*.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (14)
optional_plugins/golang/setup.py (1)
2-6: Samesetup()regression as noted in result_uploadThis file has the identical bare
setup()change and will fail in the same way; please address it together with the fix in optional_plugins/result_upload/setup.py.optional_plugins/mail/setup.py (1)
2-6: Same broken compatibility stubThe bare
setup()here has the same failure mode as described for optional_plugins/result_upload/setup.py; please apply the same resolution.optional_plugins/ansible/setup.py (1)
2-6: Same issue as in result_uploadThis shim will also crash on
python setup.py …; please fix alongside the earlier comment.optional_plugins/varianter_cit/setup.py (1)
2-6: Same legacy-path regressionRepeats the bare
setup()change that breaks the legacy workflow; please address alongside the fix for optional_plugins/result_upload/setup.py.setup.py (1)
207-350: Keep entry_points in sync with pyproject.toml (avoid drift).This duplicates pyproject.toml and is a maintenance risk. Ensure synchronization or generate these programmatically.
Run to compare groups and entries:
#!/bin/bash # Compare entry point groups echo "setup.py groups:" rg -nP '^\s*"([^"]+)"\s*:\s*\[' -n setup.py | sed -n 's/.*"\([^"]*\)".*/\1/p' | sort -u echo -e "\npyproject.toml groups:" rg -nP '^\[project\.entry-points\."([^"]+)"\]' -n pyproject.toml | sed -n 's/.*"\([^"]*\)".*/\1/p' | sort -u # Compare console_scripts entries (names only) echo -e "\nconsole_scripts in setup.py:" sed -n '/"console_scripts": \[/,/\],/p' setup.py | rg -nP '^\s*"([^"]+)\s*=' | sed -n 's/.*"\([^"]*\).*/\1/p' | sort echo -e "\nconsole_scripts in pyproject.toml:" sed -n '/^\[project\.scripts\]/,/^\[/p' pyproject.toml | rg -nP '^\s*([a-zA-Z0-9._-]+)\s*=' -n | sed -n 's/^\s*\([a-zA-Z0-9._-]\+\).*/\1/p' | sortoptional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (7)
208-216: Fix logging and include traceback on termination failure.Use f-string and exception logging; return True in else block.
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") - return False + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") + return False + else: + return True
38-46: Register timeouts as integers (not strings).Add key_type=int so values from config are parsed as ints.
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) ... help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-115: Harden slot initialization (I/O, JSON, login errors).Wrap file read/JSON/login with error handling to avoid crashing on a bad slot file.
- with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
136-146: Escape task identifier in shell command.Prevent breakage/injection by quoting the identifier.
session = runtime_task.spawner_handle - status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {safe_identifier}")
182-193: Don’t discard output; spawn should be non-blocking.
- Dropping all stdout/stderr to /dev/null loses results/logs.
- run_remote_cmd_async waits for completion; spawn_task becomes synchronous.
Option A (preserve output, still blocking; minimal fix):
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Option B (proper async spawn; recommended):
- cmd = shlex.join(entry_point_args) + " > /dev/null" - timeout = self.config.get("spawner.remote.test_timeout") - status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) + remote_log = f"/tmp/avocado-task-{runtime_task.task.identifier.replace('/', '_')}.log" + bg_cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1 & echo $!" + status, output = await RemoteSpawner.run_remote_cmd_async(session, bg_cmd, 30) + if status == 0: + try: + runtime_task.spawner_pid = int(output.strip().splitlines()[-1]) + except Exception: + LOG.error(f"Failed to parse remote PID from output: {output!r}") + return False + else: + LOG.error(f"Failed to spawn task on {session.host}:{session.port}:\n{output}") + return False - LOG.debug(f"Command exited with code {status}") - if status != 0: - LOG.error( - f"Error exit code {status} on {session.host}:{session.port} " - f"with output:\n{output}" - ) - return FalseThen update is_task_alive()/wait_task to check PID (e.g., kill -0) and stop polling when it exits.
195-201: Avoid fixed /tmp path; use a unique, safe per-task dir.Fixed path risks collisions and leakage.
- output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier) + output_lxc_path = f"/tmp/avocado-task-{safe_id}"Optionally ensure the remote dir exists before run.
202-206: Add a wait timeout to avoid infinite loops.Break the poll if task never finishes.
- async def wait_task(self, runtime_task): - while True: - if not RemoteSpawner.is_task_alive(runtime_task): - return - await asyncio.sleep(0.1) + async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start = asyncio.get_event_loop().time() + while True: + if not RemoteSpawner.is_task_alive(runtime_task): + return + if asyncio.get_event_loop().time() - start > timeout: + LOG.error(f"Task {runtime_task.task.identifier} exceeded wait timeout of {timeout}s") + return + await asyncio.sleep(0.1)pyproject.toml (2)
14-16: Restore required runtime dependencies
Onlysetuptoolsis declared, but the core package still imports third-party modules such aspsutil(see avocado/plugins/sysinfo.py),requests(see avocado/utils/asset.py) andjsonschema(see avocado/plugins/variants.py). Without listing them here,pip install avocado-frameworksucceeds but the first use of those modules raisesImportError. Please port the fullinstall_requireslist from the former setup.py (group optional pieces under extras if needed) so users receive the necessary dependencies on install.
29-30: Remove unsupported Python 3.14 classifier
PyPI rejects uploads that reference classifiers it does not recognize, andProgramming Language :: Python :: 3.14is not published yet. Drop it to keep releases uploadable.
🧹 Nitpick comments (4)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
73-75: Annotate mutable class attributes with ClassVar.Silences tooling and clarifies intent.
-from avocado.core.spawners.common import SpawnerMixin, SpawnMethod +from avocado.core.spawners.common import SpawnerMixin, SpawnMethod +from typing import ClassVar, Dict, Any @@ - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar[list] = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar[Dict[Any, bool]] = {}
92-135: Guard slot reservation against races.Concurrent async tasks can pick the same free slot. Consider protecting slots_cache with an asyncio.Lock or reserving atomically.
Would you like a patch that adds an asyncio.Lock and wraps selection inside it?
examples/plugins/tests/magic/pyproject.toml (1)
5-13: Make package discovery explicit and declare Python version.
- Constrain discovery to avocado_magic* and declare minimum Python version (3.9+).
Apply:
[project] name = "magic" version = "1.0" description = "Avocado \"magic\" test type" +requires-python = ">=3.9" @@ -[tool.setuptools.packages.find] +[tool.setuptools.packages.find] +include = ["avocado_magic*"]optional_plugins/varianter_pict/pyproject.toml (1)
5-17: Add explicit Python version classifiers.
optional_plugins/varianter_pict/VERSIONandREADME.rstare present.
Underclassifiers, replace the existing Python entry with:classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Natural Language :: English", "Operating System :: POSIX", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", - "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (3)
- spell.ignore
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_yaml_to_mux/README.rst
🚧 Files skipped from review as they are similar to previous changes (25)
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- .github/workflows/weekly.yml
- optional_plugins/ansible/pyproject.toml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
- optional_plugins/golang/pyproject.toml
- selftests/run_coverage
- optional_plugins/spawner_remote/setup.py
- examples/plugins/job-pre-post/sleep/pyproject.toml
- docs/source/guides/contributor/chapters/environment.rst
- docs/source/guides/contributor/chapters/plugins.rst
- examples/plugins/tests/README.rst
- examples/plugins/tests/rogue/pyproject.toml
- examples/plugins/README.rst
- .github/workflows/push_ci.yml
- optional_plugins/README.rst
- examples/plugins/cli-cmd/hello_option/setup.py
- optional_plugins/result_upload/pyproject.toml
- .github/workflows/ci.yml
- .github/workflows/prerelease.yml
- optional_plugins/ansible/README.rst
- optional_plugins/varianter_yaml_to_mux/setup.py
- optional_plugins/mail/pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (35)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Fedora selftests
- GitHub Check: Version task ubuntu:22.04
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: macOS with Python 3.11
- GitHub Check: Windows with Python 3.10
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (22)
.github/actions/version/action.yml (2)
9-9: Consider documenting the PIP_BREAK_SYSTEM_PACKAGES override.Setting
PIP_BREAK_SYSTEM_PACKAGES=1bypasses PEP 668's externally-managed-environment protections. While this may be necessary in containerized CI environments, it can mask dependency conflicts or system-package interference.Consider adding a comment explaining why this override is required, or verify whether the CI container is sufficiently isolated to make this safe.
10-11: LGTM!The migration from
setup.py developtopip install -e .follows modern Python packaging best practices..github/workflows/vmimage.yml (1)
42-42: LGTM!The migration to
pip install -e .modernizes the workflow and aligns with the project-wide transition away from directsetup.pyinvocations.examples/plugins/cli-cmd/hello/setup.py (1)
1-6: LGTM!The minimal shim approach with a clear compatibility comment is an appropriate transition strategy during the migration to
pyproject.toml-based packaging.optional_plugins/varianter_pict/setup.py (1)
1-6: LGTM!Consistent with the project-wide migration strategy: minimal setup.py shim for backward compatibility with configuration sourced from
pyproject.toml.optional_plugins/spawner_remote/pyproject.toml (1)
1-45: LGTM! Entry points corrected per previous review.The pyproject.toml configuration is complete, and the entry point paths now correctly reference the
.spawnermodule as resolved in the previous review. The dependency onaexpect>=1.6.2is appropriate given that the latest version is 1.8.0.Based on learnings about aexpect, version 1.6.2 is a reasonable minimum given the library's stable API and the availability of newer versions (up to 1.8.0).
examples/plugins/tests/rogue/setup.py (1)
1-6: LGTM!Consistent minimal shim pattern for backward compatibility during the migration to
pyproject.toml-based packaging.optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-48: Approve pyproject.toml configuration Verified that the requiredVERSIONandREADME.rstfiles exist.Makefile.gh (1)
65-69: Unconditional build safe: all plugins have pyproject.toml
Verified that each directory inAVOCADO_OPTIONAL_PLUGINScontains apyproject.toml, so removing thesetup.pycheck is safe.examples/plugins/tests/magic/setup.py (1)
1-6: LGTM: minimal back-compat shim.Delegates config to pyproject.toml as intended.
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-6: LGTM: minimal back-compat shim.setup() defers to pyproject.toml as intended.
python-avocado.spec (3)
8-9: LGTM: tarball macro and %setup -n updates.Names now match avocado_framework-*. No further issues spotted.
Also applies to: 100-105
220-220: LGTM: switch to module-based selftests invocation.%{python3} -m selftests.check aligns with upstream changes.
243-245: Exclusion paths are correct. The patterns%exclude %{python3_sitelib}/contrib*and%exclude %{python3_sitelib}/scripts*only apply to top-level packages and will not excludeavocado/contriboravocado/scripts. No changes needed.optional_plugins/robot/avocado_robot/robot.py (1)
41-44: LGTM! Backward-compatible API handling.The conditional logic correctly handles both the old string-based API and the new TestCase object API by checking for the presence of the
nameattribute. This maintains backward compatibility while supporting newer versions of the Robot Framework API.optional_plugins/html/setup.py (1)
1-6: LGTM! Standard pyproject.toml migration.The file correctly transitions to a minimal setup.py shim, with all packaging configuration now handled by pyproject.toml. This aligns with modern Python packaging practices (PEP 517/518/621).
examples/plugins/cli-cmd/hello/pyproject.toml (1)
1-14: LGTM! Well-structured example plugin packaging.The pyproject.toml configuration is clean and follows modern packaging standards:
- Proper build-system declaration with setuptools>=61.0
- Clear project metadata for the example plugin
- Correct entry point registration for the CLI command
- Appropriate py-modules declaration for single-module packaging
optional_plugins/resultsdb/setup.py (1)
1-6: LGTM! Standard pyproject.toml migration.The file correctly transitions to a minimal setup.py shim following modern Python packaging practices. All packaging configuration is now handled by pyproject.toml, consistent with the project-wide migration.
examples/plugins/test-pre-post/hello/setup.py (1)
1-6: LGTM! Clean pyproject.toml migration.The file correctly migrates to a minimal setup.py shim with proper portable shebang (
/usr/bin/env). The transition to pyproject.toml-based configuration is well-executed and consistent with the project-wide modernization.docs/source/guides/writer/chapters/subclassing.rst (1)
20-101: LGTM! Comprehensive documentation update.The documentation successfully modernizes the subclassing example:
- Clear migration from setup.py to pyproject.toml
- Correct PEP 621-compliant project structure
- Proper build-system configuration with setuptools>=61.0
- Well-structured project metadata with dynamic version loading
- Updated installation commands and realistic output examples
- Maintains clear pedagogical flow for developers creating Avocado sub-frameworks
optional_plugins/robot/setup.py (1)
1-6: LGTM! Consistent pyproject.toml migration.The file correctly transitions to a minimal setup.py shim, matching the pattern applied across other optional plugins. All packaging configuration is now centralized in pyproject.toml, aligning with modern Python packaging standards.
examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: LGTM! Well-structured example plugin packaging.The pyproject.toml configuration is clean and follows modern packaging standards:
- Proper build-system declaration with setuptools>=61.0
- Clear project metadata for the CLI option example
- Correct entry point registration for the hello_option command
- Appropriate py-modules declaration for single-module packaging
The configuration is consistent with the companion hello plugin example, which is good for educational purposes.
| [tool.setuptools.packages.find] | ||
| exclude = ["selftests*", "docs*", "examples*", "contrib*", "scripts*", "optional_plugins*"] | ||
|
|
||
| [tool.setuptools.dynamic] | ||
| version = {file = "VERSION"} | ||
| readme = {file = "README.rst", content-type = "text/x-rst"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not exclude packages required by console scripts
[project.scripts] registers avocado-external-runner = "scripts.external_runner:main", but [tool.setuptools.packages.find] excludes scripts*, so that module never ships in the wheel/sdist and the console script fails at runtime. Remove scripts* from the exclusion list (or package the module another way) to keep the entry point importable.
🤖 Prompt for AI Agents
In pyproject.toml around lines 238 to 243, the packages.find exclude list
currently contains "scripts*", which prevents the scripts.external_runner module
(required by the avocato-external-runner console script entry point) from being
packaged; remove "scripts*" from the exclude array so the scripts package is
included in sdist/wheel, or alternatively move/register the external_runner
module inside a packaged module and update the entry point to that import path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
python-avocado.spec (1)
243-250: Exclusion patterns need verification.The additions of
contrib*andscripts*exclusions (lines 243-244) and the conditional exclusion blocks (lines 246-250) were flagged in a previous review. The concern aboutavocado_result_html*path correctness remains unresolved.Verify that these exclusion patterns match the actual installed package structure after the pyproject.toml migration:
#!/bin/bash # Verify exclusion patterns exist in the expected locations # Check for contrib and scripts in installed layout fd -t d '^(contrib|scripts)$' --max-depth 3 # Check actual location of avocado_result_html after installation # (may be in optional_plugins/html/ subdirectory) fd -t d 'avocado_result_html' --max-depth 4optional_plugins/robot/pyproject.toml (1)
14-16: Verify robotframework version constraint.Line 16 declares
"robotframework"as a dependency without version constraints. A previous review flagged that the constraint<7.0was too restrictive given that robotframework 7.3.2 is available. However, the current code shows no version constraint at all.Confirm whether an upper version bound is needed for robotframework compatibility:
Is Robot Framework 7.x compatible with Python 3.9+, and should the avocado-framework-plugin-robot declare a version constraint?
🧹 Nitpick comments (8)
selftests/utils.py (1)
27-32: Approve the migration; consider narrowing exception handling.The migration from
pkg_resources.require()todistribution()is correct and aligns with modern Python packaging standards. However, the exception handling is overly broad.Consider catching the specific exception instead of all exceptions:
try: distribution(module_name) return True - except Exception: - # Catch all exceptions (PackageNotFoundError, etc.) + except PackageNotFoundError: return FalseIf you need to handle the exception without importing it explicitly, you can catch it as:
+from importlib.metadata import distribution, PackageNotFoundErrorThis makes the intent clearer and follows the principle of catching specific exceptions rather than using blind exception handling, as flagged by the static analysis tool.
Based on learnings
examples/plugins/cli-cmd/hello/setup.py (1)
6-10: Consider removing hardcoded metadata to eliminate duplication.The metadata (name, version, description) is duplicated between this file and pyproject.toml, creating a maintenance burden and risk of inconsistencies. The cleanest transition pattern is to use a bare
setup()call (as seen inexamples/plugins/tests/rogue/setup.py), allowing pyproject.toml to be the single source of truth for all packaging metadata.Apply this diff to follow the cleanest pattern:
-setup( - name='avocado-hello-world-option', - version='1.0', - description='Avocado Hello World CLI command with config option', -) +setup()examples/plugins/cli-cmd/hello_parser/setup.py (1)
6-10: Consider removing hardcoded metadata to eliminate duplication.The metadata is duplicated between this file and pyproject.toml. Following the pattern in
examples/plugins/tests/rogue/setup.pywith a baresetup()call would eliminate this duplication and make pyproject.toml the single source of truth.Apply this diff:
-setup( - name='avocado-hello-world-parser', - version='1.0', - description='Avocado Hello World CLI command with config parser', -) +setup()optional_plugins/varianter_pict/setup.py (1)
11-15: Consider removing hardcoded metadata to eliminate duplication.While the version is correctly read from the VERSION file, the name and description remain hardcoded, creating duplication with pyproject.toml. For consistency with the cleanest transition pattern (as in
examples/plugins/tests/rogue/setup.py), consider using a baresetup()call.Apply this diff to eliminate duplication:
-setup( - name='avocado-framework-plugin-varianter-pict', - version=VERSION, - description='Varianter with combinatorial capabilities by PICT', -) +setup()This change would also allow you to remove the VERSION file reading logic (lines 7-9) as pyproject.toml can handle dynamic version sourcing.
optional_plugins/ansible/setup.py (1)
11-15: Consider removing hardcoded metadata to eliminate duplication.The name and description are duplicated between this file and pyproject.toml. Following the pattern in
examples/plugins/tests/rogue/setup.pywith a baresetup()call would eliminate this duplication and simplify the transition.Apply this diff:
-setup( - name='avocado-framework-plugin-ansible', - version=VERSION, - description='Adds to Avocado the ability to use ansible modules as dependencies for tests', -) +setup()This would also allow removing the VERSION file reading logic (lines 4-9).
optional_plugins/html/setup.py (1)
11-15: Consider removing hardcoded metadata to eliminate duplication.The name and description are duplicated between this file and pyproject.toml. Using a bare
setup()call (as demonstrated inexamples/plugins/tests/rogue/setup.py) would eliminate this duplication and align with the cleanest transition pattern.Apply this diff:
-setup( - name='avocado-framework-plugin-result-html', - version=VERSION, - description='Avocado HTML Report for Jobs', -) +setup()This would also allow removing the VERSION file reading logic (lines 4-9).
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
73-74: Annotate mutable class attributes withClassVar.The
METHODSandslots_cacheclass attributes are mutable and should be annotated withtyping.ClassVarfor clarity and to satisfy static analysis tools.Apply this diff:
+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar[list] = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar[dict] = {}
219-233: Stub methods have unused parameters; consider documenting.The stub implementations for requirement management methods (
check_task_requirements,is_requirement_in_cache,save_requirement_in_cache,update_requirement_cache) have unusedruntime_taskandresultparameters. If these are intentionally not implemented, add docstrings explaining that these methods are stubs.Example for one method:
@staticmethod async def check_task_requirements(runtime_task): - """Check the runtime task requirements needed to be able to run""" + """Check the runtime task requirements needed to be able to run. + + This is a stub implementation. Remote spawner does not currently + validate requirements. + """ return True
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)selftests/utils.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (1)
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (22)
- optional_plugins/ansible/README.rst
- .github/workflows/weekly.yml
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/mail/pyproject.toml
- examples/plugins/README.rst
- .github/workflows/prerelease.yml
- optional_plugins/varianter_pict/README.rst
- examples/plugins/tests/rogue/pyproject.toml
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
- optional_plugins/golang/pyproject.toml
- examples/plugins/tests/README.rst
- docs/source/guides/contributor/chapters/environment.rst
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello/pyproject.toml
- optional_plugins/result_upload/pyproject.toml
- .github/workflows/vmimage.yml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- docs/source/guides/writer/chapters/subclassing.rst
- pyproject.toml
- .github/workflows/push_ci.yml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
selftests/utils.py
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (42)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Fedora selftests
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: macOS with Python 3.11
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (44)
spell.ignore (1)
806-807: LGTM! Necessary additions for pyproject.toml migration.These ignore entries are appropriate and necessary given the project-wide migration to pyproject.toml configuration files. They will prevent false positives during spell checks.
selftests/utils.py (1)
6-6: LGTM! Good modernization.Migrating from
pkg_resourcestoimportlib.metadatais the correct approach for modern Python projects, especially when moving away from setup.py-centric tooling.Based on learnings
selftests/run_coverage (1)
30-30: LGTM: Module-based test invocation.The change from direct script execution to module-based invocation (
-m selftests.check) aligns with Python best practices and the broader migration pattern across the repository. Coverage tracking will function correctly with this approach.examples/plugins/test-pre-post/hello/setup.py (1)
1-6: LGTM: Standard pyproject.toml migration pattern.The minimal setup.py shim preserves backward compatibility for legacy tools while moving configuration to pyproject.toml. The explanatory comment clearly documents the transition purpose.
examples/plugins/tests/magic/setup.py (1)
1-6: LGTM: Consistent migration pattern.Matches the established pattern for migrating to pyproject.toml-based configuration while maintaining backward compatibility.
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-6: LGTM: Consistent migration pattern.Follows the established pattern for pyproject.toml migration with backward-compatible shim.
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: LGTM: Proper API compatibility handling.The code correctly handles both the old Robot Framework API (where
test_caseis a string) and the new API (wheretest_caseis aTestCaseobject). Thehasattrcheck with fallback ensures backward compatibility while supporting newer versions..github/actions/version/action.yml (1)
9-11: Verify necessity of PIP_BREAK_SYSTEM_PACKAGES.This flag bypasses pip’s protection against modifying system-managed installations and isn’t used elsewhere. Confirm the CI runner is fully isolated and that this override is strictly required; if not, remove it or configure pip to install in user space without this flag.
optional_plugins/spawner_remote/pyproject.toml (1)
1-45: LGTM! Configuration follows modern packaging standards.The pyproject.toml configuration is well-structured with appropriate build system requirements, project metadata, and entry points. The dependency on
aexpect>=1.6.2is reasonable given that the latest version is 1.8.0, and the dynamic version/readme sourcing pattern aligns with the repository's standardized approach.examples/plugins/tests/rogue/setup.py (1)
1-6: LGTM! This is the cleanest transition pattern.This file demonstrates the recommended approach for the setup.py transition: a bare
setup()call that delegates all configuration to pyproject.toml, eliminating duplication and making pyproject.toml the single source of truth.docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM! Documentation accurately reflects the migration.The documentation has been properly updated to reference
pyproject.tomlinstead ofsetup.pyfor plugin registration, and the installation command correctly usespip install -e .for development mode installation.
111-114: LGTM! Entry-point syntax updated to TOML format.The entry-point declaration examples now correctly use the TOML syntax with
[project.entry-points."<namespace>"]format, aligning with the modern pyproject.toml-based packaging approach.
170-173: LGTM! Settings plugin registration example updated.The settings plugin registration example now uses TOML format with proper
[project.entry-points."avocado.plugins.settings"]syntax, consistent with the migration to pyproject.toml-based configuration.
325-327: LGTM! Test type plugin example updated.The test type plugin activation example has been correctly updated to reference pyproject.toml and use
pip install -e .for installation, maintaining consistency with the documentation updates throughout the file.examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: LGTM! Example plugin packaging configuration is correct.The pyproject.toml follows the correct pattern for an Avocado CLI plugin example:
- Build system properly configured with setuptools>=61.0
- Project metadata is minimal but complete for an example plugin
- Entry point correctly registered under
avocado.plugins.cli.cmd- Single-module packaging is appropriate for this simple example
optional_plugins/varianter_cit/setup.py (1)
2-15: LGTM! Minimal setup.py shim follows correct transition pattern.The reduced setup.py correctly serves as a compatibility shim during the migration:
- Clear transition comment indicates pyproject.toml is primary
- VERSION file reading uses proper encoding
- Minimal setup() with only essential fields (name, version, description)
- Full metadata now lives in pyproject.toml per the PR's migration strategy
This pattern aligns with the project-wide shift to pyproject.toml-based packaging while maintaining backward compatibility.
examples/plugins/job-pre-post/sleep/pyproject.toml (1)
1-17: LGTM! Job pre/post plugin packaging is correctly configured.The pyproject.toml properly defines the sleep plugin:
- Standard build system with setuptools>=61.0
- Both required entry points registered:
avocado.plugins.initfor SleepInit andavocado.plugins.job.prepostfor Sleep- Single-module packaging appropriate for this example plugin
- Follows consistent pattern with other example plugin configurations in the PR
optional_plugins/mail/setup.py (1)
2-15: LGTM! Mail plugin setup.py correctly minimized for transition.The setup.py follows the correct migration pattern:
- Transition comment clearly indicates pyproject.toml is the primary configuration
- VERSION file reading with proper encoding
- Minimal setup() call with essential fields only
- Full packaging metadata (dependencies, entry points for notification plugins) now defined in pyproject.toml
Consistent with the project-wide pyproject.toml migration strategy.
python-avocado.spec (3)
8-18: LGTM! Tarball naming updated for pyproject.toml migration.The tarball name changes from
avocado-%{version}toavocado_framework-%{version}(lines 8, 18) correctly align with the standardized package naming convention established by the pyproject.toml migration.
102-104: LGTM! %setup invocations match updated tarball naming.The
%setup -q -ndirectives correctly updated to useavocado_framework-%{version}andavocado_framework-%{commit}, matching the new tarball naming convention.
220-220: LGTM! Module-based test invocation is correct.The change from
%{python3} selftests/check.pyto%{python3} -m selftests.checkfollows best practices for modern Python packaging and aligns with the pyproject.toml migration strategy.optional_plugins/result_upload/setup.py (1)
2-15: Setup.py shim is correctly configured.The minimal setup.py provides the necessary fields (name, version, description) to avoid
ValueError: Missing project name. The transition comment clearly indicates that pyproject.toml is the primary configuration source.The past review comment about a missing project name appears to be based on an earlier version of this file. The current code correctly includes all essential fields in the setup() call.
optional_plugins/ansible/pyproject.toml (1)
1-47: LGTM! Ansible plugin packaging is comprehensive and correct.The pyproject.toml provides complete packaging configuration:
- Standard build system with setuptools>=61.0
- Dynamic version/readme loading from VERSION and README.rst files
- All necessary dependencies declared (avocado-framework, cffi, pycparser, ansible-core)
- Console script and plugin entry point correctly registered
- Comprehensive metadata including classifiers, license, and Python version requirement (>=3.9)
- Package discovery properly configured for avocado_ansible* modules
Follows the consistent pattern established across optional plugins in this PR.
optional_plugins/robot/pyproject.toml (1)
1-48: LGTM! Robot plugin packaging is well-configured.The pyproject.toml provides comprehensive packaging configuration:
- Standard build system with setuptools>=61.0
- Dynamic version/readme loading from VERSION and README.rst
- Required dependencies declared (avocado-framework, robotframework)
- Console script for the robot runner
- Both required entry points registered: runner and resolver plugins
- Package discovery properly configured for avocado_robot* modules
- Comprehensive metadata with appropriate classifiers
Follows the consistent pattern across optional plugins in this PR.
optional_plugins/robot/setup.py (1)
2-15: LGTM! Transitional setup.py is correctly minimal.The file correctly serves as a compatibility shim during the migration period, with primary packaging configuration delegated to pyproject.toml. The version reading is straightforward and appropriate.
optional_plugins/html/pyproject.toml (1)
1-48: LGTM! PyProject configuration is well-structured.The pyproject.toml follows best practices with:
- Modern build system (setuptools ≥61.0)
- Dynamic version/readme sourcing
- Proper entry points for all plugin interfaces
- Appropriate Python version requirement (≥3.9)
optional_plugins/varianter_yaml_to_mux/README.rst (1)
6-806: LGTM! Documentation formatting improvements.The changes consistently apply inline code formatting using backticks for module/class references, improving readability and adherence to reStructuredText best practices.
optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-48: LGTM! PyProject configuration is correct.The configuration properly:
- Defines build system and metadata
- Specifies PyYAML dependency with minimum version
- Maps entry points for init, cli, and varianter interfaces
- Uses dynamic version/readme sourcing
- Configures package discovery appropriately
optional_plugins/resultsdb/setup.py (1)
2-15: LGTM! Transitional setup.py is appropriately minimal.The file serves as a backward-compatibility shim during migration, correctly delegating packaging configuration to pyproject.toml while maintaining simple version reading.
optional_plugins/varianter_yaml_to_mux/setup.py (1)
2-15: LGTM! Transitional setup.py follows the correct pattern.The file appropriately serves as a compatibility shim, with primary configuration moved to pyproject.toml. The implementation is consistent with other optional plugins in this PR.
optional_plugins/README.rst (1)
10-34: LGTM! Documentation correctly reflects the new workflow.The updated instructions accurately document the pip-based development workflow and the new Makefile targets, providing clear examples for installing, uninstalling, and enabling plugins. The changes align well with the project-wide migration to pyproject.toml.
optional_plugins/golang/setup.py (1)
2-15: LGTM! Clean minimal setup for backward compatibility.The minimal setup.py approach is correct for the transition period. The file properly:
- Documents its transitional purpose
- Reads VERSION with correct utf-8 encoding
- Provides only essential metadata for egg builds
This aligns well with the pyproject.toml-based configuration in optional_plugins/golang/pyproject.toml.
.github/workflows/setup.yml (2)
33-50: LGTM! Consistent pip-based installation workflow.The user installation workflow correctly migrates from setup.py to pip-based commands:
- Editable install with
python3 -m pip install --user -e .- Plugin installations with explicit paths
- Proper use of --user flag for user-level installs
This aligns with the broader migration pattern seen across all workflow jobs.
121-125: LGTM! Test execution migrated to module-based invocation.The changes correctly:
- Use
make manfor manpage generation- Execute tests via
python3 -m selftests.check- Uninstall via
python3 -m pip uninstallThis modern approach is consistent with the pyproject.toml migration.
optional_plugins/spawner_remote/setup.py (1)
2-15: LGTM! Consistent minimal setup pattern.This file follows the same clean minimal setup pattern as other optional plugins, correctly providing backward compatibility for egg builds while delegating primary configuration to pyproject.toml.
Makefile (3)
91-104: LGTM! Useful plugin development targets.The new
develop-pluginsanddevelop-plugintargets provide convenient workflows for plugin development:
develop-pluginsinstalls all optional plugins in one commanddevelop-pluginwith PLUGIN parameter allows selective installation- Both use pip-based editable installs consistent with the migration
The error guard for missing PLUGIN variable is good practice.
34-61: LGTM! Comprehensive cleanup.The enhanced clean target is thorough and well-structured:
- Clears build artifacts, docs, caches
- Iterates through optional_plugins and example plugins
- Includes verbose progress messages
- Handles errors gracefully with
|| trueThis provides a much better cleanup experience for developers.
124-124: Note: Static analysis false positives.The checkmake warnings about missing "all" and "test" in PHONY are false positives:
- The "all" target at line 1 is informational (displays help) and doesn't need PHONY
- The "test" target is not used; "check" is the standard test target for this project
No action needed.
setup.py (2)
16-26: LGTM! Clear documentation of transitional approach.The module docstring effectively communicates:
- Purpose of retaining setup.py (backward compatibility)
- Migration to pyproject.toml
- Egg build support rationale
- Acknowledgment of entry_points duplication
This transparency helps maintainers understand the transitional state.
207-350: Track removal of egg‐build support and verify external_runner entry point
- Keep the explicit entry_points in setup.py for now; plan a follow-up task to remove egg-build support and this file once the migration is stable.
- Instead of a direct import in the source tree (which fails without an installed distribution), install in editable mode (
pip install -e .) and confirm that theavocado-external-runnerconsole script successfully loadsscripts.external_runner:main..github/workflows/ci.yml (3)
32-32: LGTM! Test execution migrated correctly.Static checks now use
python3 -m selftests.check --select=static-checks, which is consistent with the module-based execution pattern adopted throughout the PR.
89-99: LGTM! Correct Python version display and test execution.The workflow properly:
- Uses
python -VVfor verbose version output (correct flag usage)- Installs dependencies via
python3 -m pip- Executes tests via
python3 -m selftests.check --skip=static-checksThis resolves the past review concerns about flag usage.
167-171: LGTM! Windows workflow uses correct pip invocation.The Windows workflow correctly uses
python -m pip install --user -e ., which resolves the past review issue about the erroneouspython -m python3 -m pipinvocation.optional_plugins/resultsdb/pyproject.toml (1)
1-48: LGTM! Clean pyproject.toml configuration.The resultsdb plugin packaging configuration is well-structured:
- Modern build system with setuptools>=61.0
- Dynamic version/readme sourcing from VERSION/README.rst
- Clean dependency declarations (the impossible urllib3 constraint from past reviews has been correctly removed)
- Proper entry points for all plugin interfaces (cli, result_events, result)
- Appropriate Python version requirement (>=3.9)
This configuration follows the standard pattern established across other optional plugins in this migration.
| cd $$PLUGIN;\ | ||
| $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ | ||
| cd -;\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify build behavior for incomplete plugin migrations.
The removal of the setup.py existence check means the build will be attempted for all plugin directories unconditionally. This could fail if any plugins haven't been migrated to pyproject.toml yet.
Additionally, note the inconsistency: the build-egg target (lines 78-83) still has the conditional check for setup.py, while build-wheel does not.
🏁 Script executed:
#!/bin/bash
# Verify all optional plugins have pyproject.toml files
echo "Checking for pyproject.toml in all optional plugins:"
for plugin in optional_plugins/*/; do
if [ ! -f "${plugin}pyproject.toml" ]; then
echo "Missing: ${plugin}pyproject.toml"
fi
done
# Check if any plugins still have substantial setup.py files (not just shims)
echo -e "\nChecking for non-shim setup.py files:"
fd setup.py optional_plugins/ --exec sh -c 'lines=$(wc -l < "$1"); if [ $lines -gt 10 ]; then echo "$1 has $lines lines"; fi' sh {}Length of output: 641
Add a guard for pyproject.toml in the build-wheel target. Unconditionally running python -m build in optional_plugins/* will fail since none include pyproject.toml; mirror the conditional logic in build-egg.
🤖 Prompt for AI Agents
In Makefile.gh around lines 66 to 68, the build-wheel step runs `python -m
build` unconditionally which fails for optional_plugins that lack
pyproject.toml; add the same file-existence guard used in the build-egg target
so the wheel build only runs when pyproject.toml exists (wrap the cd/$(PYTHON)
-m build/ cd - sequence in a conditional like `if [ -f pyproject.toml ]; then
... fi` or the Makefile-equivalent test).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
python-avocado.spec (1)
8-18: Revert the tarball/dir rename to keep RPM build functional.GitHub still publishes archives as
avocado-<tag>.tar.gzunpacking toavocado-<tag>/. Updating%{gittar}and%setup -ntoavocado_framework-…makesSource0404 and breaks%prep. Restore the previousavocado-%{version}/avocado-%{commit}naming so the spec can fetch and unpack the sources again.Also applies to: 102-106
♻️ Duplicate comments (14)
examples/plugins/cli-cmd/hello_option/setup.py (1)
6-10: Metadata duplication between setup.py and pyproject.toml.As previously noted, this file retains metadata in the
setup()call while the comment states that configuration is in pyproject.toml. This creates duplication risk and maintenance burden.Convert to a minimal shim consistent with other plugins:
setup( - name="avocado-hello-world-option", - version="1.0", - description="Avocado Hello World CLI command with config option", + # All configuration is in pyproject.toml )optional_plugins/varianter_yaml_to_mux/setup.py (1)
1-1: Fix the shebang path (duplicate concern).The shebang still uses
/bin/envinstead of/usr/bin/env. While past review comments indicate this was addressed in earlier commits, the issue persists in the current state of the file.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/varianter_cit/setup.py (1)
1-1: Fix the shebang path (duplicate concern).The shebang still uses
/bin/envinstead of/usr/bin/env. While past review comments indicate this was addressed in earlier commits (662fc8c to af71902), the issue persists in the current state of the file.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/result_upload/setup.py (1)
1-1: Shebang still uses non-portable path.The shebang
#!/bin/envis not portable across all systems. While this was previously flagged and marked as addressed, the code still shows the incorrect path. Use#!/usr/bin/envinstead.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
38-46: Parse timeout options as integers.
settings.register_option()returns strings from config files unless you declarekey_type=int. Without it, overrides arrive as str and bleed into timeout arithmetic/run calls. Addkey_type=intto both timeout registrations.
106-115: Harden slot loading with error handling.Opening arbitrary JSON files and logging in without guards will crash the spawner on a single bad slot (missing file, malformed JSON, login failure). Wrap the load/login in try/except and log/skip failures so one bad slot doesn’t bring the whole spawner down.
143-145: Escape the task identifier before shelling out.Task identifiers can carry spaces or shell metacharacters. Injecting them unquoted into
pgreprisks breakage or command injection on the remote host. Quote the identifier (e.g.safe_id = shlex.quote(...)) before composing the command.
182-185: Preserve remote test output instead of dropping it.Appending
> /dev/nulldiscards all stdout/stderr from the remote run, eliminating diagnostics and results. Remove the redirection or redirect into a retrievable log file so failures remain debuggable.
182-193: Don’t block spawn_task until the remote run finishes.
run_remote_cmd_async()waits for completion, sospawn_task()only returns after the task exits. That defeats the spawner contract (wait_taskcan never observe a running process and concurrency collapses). Launch the command in background, capture its PID/handle, store it onruntime_task, and letwait_task/is_task_alivepoll it.
195-201: Use a unique, sanitized remote output directory.Hard-coding
/tmp/.avocado_task_output_dirmeans every task shares the same path, inviting collisions and TOCTOU races. Derive a per-task directory (sanitize the identifier, ensure creation on the remote) so runs stay isolated.
202-206: Add a timeout to the wait loop.If
is_task_alive()never flips to False (hang, bug, lost session),wait_task()loops forever. Honor the configuredtest_timeout(or another cap) to avoid jobs stalling indefinitely.
208-216: Fix termination logging and include traceback.The current
LOG.error("...{session.host}")logs the literal braces and omits the exception context. UseLOG.exception(f"Failed to terminate task on {session.host}:{session.port}")(orLOG.error(..., exc_info=True)) so the message interpolates correctly and captures the stack trace.optional_plugins/robot/setup.py (1)
1-1: The shebang portability issue remains unresolved.Despite being marked as addressed in commit dce17a9, the shebang still uses the non-portable
#!/bin/env python3path. This should be#!/usr/bin/env python3for proper PATH-based interpreter resolution across different systems.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/mail/setup.py (1)
1-1: The shebang portability issue remains unresolved.Despite past review comments indicating this was addressed (commits 662fc8c to af71902), the shebang still uses the non-portable
#!/bin/env python3path. Use#!/usr/bin/env python3for proper cross-platform compatibility.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3
🧹 Nitpick comments (6)
.github/actions/version/action.yml (2)
10-10: Consider removing the pip upgrade step.Upgrading pip on every workflow run adds overhead and potential instability. Modern Python installations typically include a recent pip version that's sufficient for editable installs.
If pip upgrade is necessary for specific features, add a comment explaining why. Otherwise, consider removing this line to improve workflow performance.
9-9: Limit and document PIP_BREAK_SYSTEM_PACKAGES usage or isolate with venv
- Scope the override to the pip command only, e.g.:
PIP_BREAK_SYSTEM_PACKAGES=1 pip install --upgrade pip- Add a comment in
action.ymlexplaining why PEP 668 protections are disabled- Alternatively, create a
python -m venv env(as in other workflows) to avoid modifying the system Pythonoptional_plugins/spawner_remote/pyproject.toml (1)
14-17: Consider updating the minimum aexpect version requirement.The current requirement
aexpect>=1.6.2is quite permissive. According to available information, aexpect 1.8.0 was released in July 2025 with potential API and behavior improvements.Consider whether:
- The plugin truly supports aexpect 1.6.2, or if newer features are used that require a higher minimum
- It would be beneficial to require a more recent version for security and stability improvements
Verify the minimum version by reviewing the spawner implementation for any aexpect features used:
#!/bin/bash # Description: Check aexpect usage in the spawner implementation # Find aexpect usage patterns in the spawner module rg -n "aexpect\." optional_plugins/spawner_remote/avocado_spawner_remote/ -A 2 -B 1optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
16-16: Update PyYAML dependency to a stable release.
ChangePyYAML>=4.2b2toPyYAML>=6.0.3(latest stable) or at minimumPyYAML>=5.4to include critical CVE fixes.examples/plugins/tests/magic/pyproject.toml (1)
6-6: Generic package name may cause conflicts.The package name
"magic"is very generic and could conflict with other packages in the ecosystem. Consider a more specific name like"avocado-test-magic"or"avocado-plugin-magic"to avoid namespace collisions.Apply this diff:
-name = "magic" +name = "avocado-test-magic"optional_plugins/ansible/pyproject.toml (1)
14-18: Consider removing redundant pycparser dependency.The
pycparserpackage is already a dependency ofcffi, so explicitly listing it may be redundant. However, explicit dependencies can improve clarity and prevent issues if cffi's dependencies change.If you prefer explicit dependencies for stability, the current setup is fine. Otherwise, consider this optional simplification:
dependencies = [ "avocado-framework", "cffi", - "pycparser", "ansible-core", ]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(1 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)selftests/utils.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (2)
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/varianter_pict/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (25)
- spell.ignore
- Makefile.gh
- optional_plugins/ansible/README.rst
- examples/plugins/tests/rogue/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/mail/pyproject.toml
- optional_plugins/spawner_remote/setup.py
- examples/plugins/job-pre-post/sleep/pyproject.toml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- examples/plugins/cli-cmd/hello/pyproject.toml
- pyproject.toml
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/tests/README.rst
- .github/workflows/prerelease.yml
- examples/plugins/cli-cmd/hello_parser/setup.py
- .github/workflows/push_ci.yml
- examples/plugins/tests/magic/setup.py
- optional_plugins/golang/setup.py
- examples/plugins/tests/rogue/setup.py
- docs/source/guides/writer/chapters/subclassing.rst
- optional_plugins/varianter_pict/README.rst
- optional_plugins/README.rst
- .github/workflows/vmimage.yml
- optional_plugins/html/setup.py
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (4)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
selftests/utils.py
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (42)
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Fedora develop install/uninstall task
- GitHub Check: macOS with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (35)
docs/source/guides/contributor/chapters/environment.rst (1)
55-62: LGTM! Documentation accurately reflects modern packaging practices.The migration from
setup.py developtopip install -e .and the terminology update from "egg link" to "editable install" align with current Python packaging standards (PEP 660). The explanation about the egg-info directory and when re-runs are needed is clear and helpful.examples/plugins/README.rst (1)
8-24: LGTM! Clear and helpful plugin development workflow.The updated documentation with explicit examples (including directory navigation and uninstall commands) makes the plugin development workflow much clearer for contributors. The migration from implicit setup.py commands to explicit pip-based commands aligns with modern Python packaging practices.
optional_plugins/spawner_remote/pyproject.toml (1)
1-45: LGTM! Well-structured pyproject.toml configuration.The pyproject.toml file follows modern Python packaging standards with:
- Proper build-system configuration
- Comprehensive project metadata
- Correct entry point registration (after previous fix)
- Standard dynamic version/readme loading pattern
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-6: LGTM! Clean transition to pyproject.toml.This setup.py file follows the recommended minimal shim pattern, delegating all configuration to pyproject.toml while maintaining backward compatibility.
docs/source/guides/contributor/chapters/plugins.rst (2)
111-114: LGTM! TOML entry-points syntax is correct.The documentation properly demonstrates the pyproject.toml entry-points syntax for plugin registration.
97-101: Example path and content verified
The referencedexamples/plugins/cli-cmd/hello/pyproject.tomlexists and contains the correct entry-point configuration.examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: LGTM! Well-structured pyproject.toml configuration.The configuration correctly uses
py-modulesfor a single-module plugin and properly registers the entry point for the CLI command.examples/plugins/job-pre-post/sleep/setup.py (1)
1-10: LGTM! Minimal setup.py for backward compatibility.The minimal setup stub with clear transition comments aligns with the PR's migration strategy. The essential metadata (name, version, description) enables legacy workflows while directing users to pyproject.toml.
optional_plugins/golang/pyproject.toml (1)
1-47: LGTM! Well-structured pyproject.toml.The golang plugin's pyproject.toml is properly configured with:
- Appropriate build system and Python version requirements (>=3.9).
- Dynamic version/readme sourcing.
- Correct entry point registrations.
- Proper package discovery configuration.
The migration from setup.py to pyproject.toml is complete and correct.
optional_plugins/result_upload/setup.py (1)
2-15: LGTM! Minimal setup.py with proper version loading.The setup stub correctly:
- Includes clear transition comments.
- Loads version from the VERSION file.
- Provides essential metadata for backward compatibility.
The previous concern about missing metadata causing crashes has been addressed with the minimal name/version/description setup.
optional_plugins/result_upload/pyproject.toml (1)
1-44: LGTM! Complete pyproject.toml configuration.The result_upload plugin's pyproject.toml is properly structured with:
- Standard build system requirements.
- Appropriate metadata and dynamic field sourcing.
- Correct entry point registrations for both CLI and result plugins.
- Proper package discovery configuration.
The migration is complete and correct.
optional_plugins/ansible/pyproject.toml (1)
1-47: LGTM! Well-configured ansible plugin.The ansible plugin's pyproject.toml is properly structured with:
- Standard build system and Python version requirements.
- Comprehensive metadata and dynamic field sourcing.
- Correct entry point registrations.
- Proper package discovery configuration.
The dependencies are appropriate for the ansible integration functionality.
examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM! Clean example plugin configuration.The hello_parser plugin's pyproject.toml is appropriately minimal for an example:
- Standard build system.
- Clear, specific package name.
- Correct entry point registration.
- Proper module configuration using py-modules.
The simplified structure (no dynamic fields) is suitable for an example plugin.
optional_plugins/resultsdb/pyproject.toml (1)
1-48: LGTM! Complete resultsdb plugin configuration.The resultsdb plugin's pyproject.toml is properly configured with:
- Standard build system and Python version requirements.
- Appropriate metadata with dynamic field sourcing.
- Correct entry point registrations for CLI, result events, and result plugins.
- Proper package discovery configuration.
- Clean dependency list (the previous urllib3 constraint issue has been resolved).
The migration is complete and correct.
.github/workflows/weekly.yml (2)
39-47: LGTM! Workflow modernization is consistent.The changes correctly migrate from
setup.py develop --usertopython3 -m pip install --user -e .and from direct script invocation topython3 -m selftests.check. These align with the PR's broader standardization of pip-based workflows.
83-89: LGTM! Plugin-disabled test invocation updated correctly.The module-based selftests invocation with
--disable-plugin-checksflag is properly migrated and maintains the same functionality as before.optional_plugins/robot/setup.py (1)
2-15: LGTM! Minimal setup.py shim is appropriate.The transitional shim correctly reads VERSION from the file and delegates all packaging metadata to pyproject.toml. This is the recommended pattern during the migration period.
optional_plugins/mail/setup.py (1)
2-15: LGTM! Minimal setup.py shim is appropriate.The transitional shim correctly delegates packaging metadata to pyproject.toml while maintaining egg-build compatibility through a minimal setup() call.
.github/workflows/setup.yml (3)
33-43: LGTM! User installation workflow correctly updated.The migration from setup.py-based installation to pip-based installation (
python3 -m pip install --user -e .and direct plugin installations via pip) is correct and aligns with modern Python packaging best practices.
121-125: LGTM! Test execution modernized correctly.The switch to
make manfor manpage generation andpython3 -m selftests.checkfor test execution is consistent with the broader workflow modernization and eliminates direct setup.py invocations.
181-194: LGTM! Virtualenv workflow uses pip consistently.The virtualenv installation steps correctly use
python3 -m venvandpython3 -m pip installfor both Avocado and plugins, following modern packaging conventions.Makefile (5)
9-10: LGTM! New plugin development targets documented.The new
develop-pluginsanddevelop-plugintargets are well-documented and provide clear guidance for plugin development workflows, complementing the migration to pip-based installation.
34-61: LGTM! Enhanced clean target with better user feedback.The improved clean target provides clear progress messages and comprehensively cleans both optional plugins and example plugins. The defensive error handling (
|| true) ensures the clean process completes even if some files are missing.
64-80: LGTM! Core targets updated to use pip and module-based commands.The migration of
install,uninstall, andchecktargets to usepython -m pipandpython -m selftests.checkis correct and eliminates direct setup.py invocations.
91-105: LGTM! Plugin development targets are well-implemented.The new
develop-pluginstarget iterates through all optional plugins, anddevelop-pluginprovides targeted installation with clear usage guidance. The error message for missing PLUGIN variable is helpful.
109-114: LGTM! Man page generation with proper error handling.The updated man page target includes proper error handling with
command -vto check for rst2man availability before attempting generation, providing a clear error message if the tool is missing.setup.py (3)
16-26: LGTM! Clear documentation of transitional setup.py purpose.The docstring effectively communicates that this file is maintained for backward compatibility and egg builds during the migration period, with explicit acknowledgment of entry_points duplication. This transparent communication helps future maintainers understand the temporary nature of this arrangement.
38-41: LGTM! Simplified VERSION reading.The streamlined VERSION reading using a context manager is clean and appropriate for the transitional setup.py shim.
207-350: LGTM with maintenance caveat.The entry_points dictionary duplication for egg builds is acknowledged in the comments (lines 24-25). While this creates maintenance burden, it's a necessary transitional measure. The comprehensive entry_points configuration covers all plugin types and appears complete.
Consider adding a CI check to validate entry_points synchronization between setup.py and pyproject.toml to prevent future drift, as suggested in past review comments.
.github/workflows/ci.yml (5)
32-32: LGTM! Static checks updated to use module invocation.The change to
python3 -m selftests.check --select=static-checkscorrectly replaces the deprecated setup.py test invocation and aligns with the broader migration strategy.
89-99: LGTM! Check-linux job correctly modernized.The workflow updates use
python -VV(correct double-verbose flag), pip-based dependency installation, and module-based test execution. These changes align with modern Python packaging practices.
131-143: LGTM! macOS workflow updated consistently.The macOS job follows the same modernization patterns as Linux jobs, ensuring cross-platform consistency in installation and test execution methods.
167-171: LGTM! Windows workflow updated correctly.The Windows job uses
python -VVandpython -m pip install --user -e ., maintaining consistency with the Linux/macOS workflows. The setuptools fallback at line 169 is correctly implemented aspython -m pip install.
265-356: LGTM! Version tasks consistently updated across distributions.All distribution-specific version tasks (Fedora, UBI, Debian, Ubuntu) consistently use
python3 python3-pip(or appropriate variant) andpython3-venvfor Python dependency installation, with ca-certificates included where needed. This standardization improves workflow reliability.optional_plugins/robot/pyproject.toml (1)
1-48: LGTM! Well-structured pyproject.toml configuration.The packaging configuration correctly defines:
- Build system with setuptools and wheel
- Project metadata with dynamic version/readme from files
- Dependencies and Python version requirements
- CLI scripts and plugin entry points
- Package discovery rules
This modernizes the Robot plugin packaging and aligns with PEP 517/518 standards.
| }, | ||
| ) | ||
| setup( | ||
| name="avocado-hello-world-option", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the package name matches the directory.
The package name avocado-hello-world-option suggests this belongs in the hello_option directory, not the hello directory. Based on the PR changes, there should be a separate hello_option plugin with its own pyproject.toml.
Run this script to verify the directory structure and identify if this is a mismatch:
🏁 Script executed:
#!/bin/bash
# Verify the directory structure and package names for hello plugins
echo "=== Checking hello plugin directories ==="
fd -t d "hello" examples/plugins/cli-cmd/
echo ""
echo "=== Checking pyproject.toml files ==="
fd "pyproject.toml" examples/plugins/cli-cmd/ --exec cat {} \; --exec echo "---" \;
echo ""
echo "=== Checking setup.py files ==="
fd "setup.py" examples/plugins/cli-cmd/ --exec echo "File: {}" \; --exec grep -A2 "name=" {} \;Length of output: 2490
Fix metadata in hello/setup.py: in examples/plugins/cli-cmd/hello/setup.py, change name to "avocado-hello-world", description to "Avocado Hello World CLI command", and entry-points to hello = "hello:HelloWorld" to align with its pyproject.toml.
🤖 Prompt for AI Agents
In examples/plugins/cli-cmd/hello/setup.py around line 7, update the package
metadata to match pyproject.toml: change name from "avocado-hello-world-option"
to "avocado-hello-world", update the description to "Avocado Hello World CLI
command", and adjust the entry-points mapping so the console/script entry is
hello = "hello:HelloWorld"; ensure the updated strings are used in the setup()
call.
| [project.entry-points."avocado.plugins.runnable.runner"] | ||
| magic = "avocado_magic.runner:MagicRunner" | ||
|
|
||
| [tool.setuptools.packages.find] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Complete the package discovery configuration.
The [tool.setuptools.packages.find] section is empty. Since the entry points reference avocado_magic module, you should specify which packages to include.
Apply this diff:
[tool.setuptools.packages.find]
+include = ["avocado_magic*"]🤖 Prompt for AI Agents
In examples/plugins/tests/magic/pyproject.toml around line 25, the
[tool.setuptools.packages.find] section is empty; update it to explicitly
include the avocado_magic package (and any subpackages) by setting include =
["avocado_magic*"] and, if your project uses a src layout, also set where =
["src"]; this ensures setuptools discovers the referenced avocado_magic module
for packaging and entry points.
| [build-system] | ||
| requires = ["setuptools>=61.0", "wheel"] | ||
| build-backend = "setuptools.build_meta" | ||
|
|
||
| [project] | ||
| name = "avocado-framework-plugin-robot" | ||
| dynamic = ["version", "readme"] | ||
| description = "Avocado Plugin for Execution of Robot Framework tests" | ||
| authors = [ | ||
| {name = "Avocado Developers", email = "avocado-devel@redhat.com"}, | ||
| ] | ||
| license = {text = "GPL-2.0-or-later"} | ||
| requires-python = ">=3.9" | ||
| dependencies = [ | ||
| "avocado-framework", | ||
| "robotframework" | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Consider adding version constraints for robotframework dependency.
The robotframework dependency at line 16 lacks version constraints. While this allows maximum flexibility, it can lead to compatibility issues if robotframework releases breaking changes. Past review comments mentioned updating a <7.0 constraint, but the current configuration has no constraints at all.
Consider adding appropriate version bounds:
dependencies = [
"avocado-framework",
- "robotframework"
+ "robotframework>=4.1,<8.0"
]Search the web to verify the current stable robotframework version and compatibility requirements:
🌐 Web query:
What is the latest stable version of Robot Framework as of October 2025, and what are the recommended version constraints for Python 3.9+ compatibility?
💡 Result:
-
Latest stable Robot Framework (as of Oct 14, 2025): 7.3.2 (final release published July 4, 2025). [1][2]
-
Python compatibility / recommended constraints:
- Robot Framework itself requires Python 3.8 or newer (official docs). If you specifically want Python 3.9+ for better ecosystem support, pin your environment to Python >=3.9 — many common RF libraries (e.g., Browser) and tools declare Python 3.9+ support. Example constraints you can use:
- robotframework==7.3.2
- python_requires=">=3.9"
References: Robot Framework user guide (requires Python 3.8+), Browser library and other ecosystem projects (recommend Python 3.9+). [3][4]
- Robot Framework itself requires Python 3.8 or newer (official docs). If you specifically want Python 3.9+ for better ecosystem support, pin your environment to Python >=3.9 — many common RF libraries (e.g., Browser) and tools declare Python 3.9+ support. Example constraints you can use:
Sources
- Robot Framework releases (7.3 release candidates / release history). [GitHub releases]. [2]
- Release listing showing v7.3.2 (July 4, 2025). [gitclear / release metadata]. [1]
- Robot Framework User Guide — Python installation / requirements (requires Python 3.8+). [3]
- Example ecosystem library (Browser) — declares Python 3.9+ support. [4]
Add version constraints for robotframework dependency
Constrain robotframework to the current stable 7.x release to avoid unintentional upgrades to 8.x:
dependencies = [
"avocado-framework",
- "robotframework"
+ "robotframework>=7.3.2,<8.0"
]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [build-system] | |
| requires = ["setuptools>=61.0", "wheel"] | |
| build-backend = "setuptools.build_meta" | |
| [project] | |
| name = "avocado-framework-plugin-robot" | |
| dynamic = ["version", "readme"] | |
| description = "Avocado Plugin for Execution of Robot Framework tests" | |
| authors = [ | |
| {name = "Avocado Developers", email = "avocado-devel@redhat.com"}, | |
| ] | |
| license = {text = "GPL-2.0-or-later"} | |
| requires-python = ">=3.9" | |
| dependencies = [ | |
| "avocado-framework", | |
| "robotframework" | |
| ] | |
| [build-system] | |
| requires = ["setuptools>=61.0", "wheel"] | |
| build-backend = "setuptools.build_meta" | |
| [project] | |
| name = "avocado-framework-plugin-robot" | |
| dynamic = ["version", "readme"] | |
| description = "Avocado Plugin for Execution of Robot Framework tests" | |
| authors = [ | |
| {name = "Avocado Developers", email = "avocado-devel@redhat.com"}, | |
| ] | |
| license = {text = "GPL-2.0-or-later"} | |
| requires-python = ">=3.9" | |
| dependencies = [ | |
| "avocado-framework", | |
| "robotframework>=7.3.2,<8.0" | |
| ] |
🤖 Prompt for AI Agents
In optional_plugins/robot/pyproject.toml around lines 1 to 17, the
robotframework dependency is unpinned which allows accidental upgrades to 8.x;
update the dependencies entry to constrain robotframework to the 7.x stable
series (for example use a version specifier like >=7.0,<8.0) by replacing the
plain "robotframework" entry with the bounded version range so the package stays
on 7.x while allowing patch/minor updates.
| try: | ||
| pkg_resources.require(module_name) | ||
| distribution(module_name) | ||
| return True | ||
| except pkg_resources.DistributionNotFound: | ||
| except Exception: | ||
| # Catch all exceptions (PackageNotFoundError, etc.) | ||
| return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use specific exception type instead of bare Exception.
Catching Exception is too broad and may hide unexpected errors (e.g., AttributeError, TypeError) that should propagate. The importlib.metadata.distribution() function raises PackageNotFoundError when a distribution isn't found.
Apply this diff to handle the specific exception:
+from importlib.metadata import PackageNotFoundError, distribution
-from importlib.metadata import distribution
def python_module_available(module_name):
"""
Checks if a given Python module is available
:param module_name: the name of the module
:type module_name: str
:returns: if the Python module is available in the system
:rtype: bool
"""
try:
distribution(module_name)
return True
- except Exception:
- # Catch all exceptions (PackageNotFoundError, etc.)
+ except PackageNotFoundError:
return False📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try: | |
| pkg_resources.require(module_name) | |
| distribution(module_name) | |
| return True | |
| except pkg_resources.DistributionNotFound: | |
| except Exception: | |
| # Catch all exceptions (PackageNotFoundError, etc.) | |
| return False | |
| from importlib.metadata import PackageNotFoundError, distribution | |
| def python_module_available(module_name): | |
| """ | |
| Checks if a given Python module is available | |
| :param module_name: the name of the module | |
| :type module_name: str | |
| :returns: if the Python module is available in the system | |
| :rtype: bool | |
| """ | |
| try: | |
| distribution(module_name) | |
| return True | |
| - except Exception: | |
| except PackageNotFoundError: | |
| return False |
🧰 Tools
🪛 Ruff (0.14.0)
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
In selftests/utils.py around lines 27 to 32, the try/except currently catches a
bare Exception; change it to catch importlib.metadata.PackageNotFoundError
specifically so only the "distribution not found" case is handled. Update
imports if needed (e.g., from importlib.metadata import PackageNotFoundError or
reference as importlib.metadata.PackageNotFoundError) and replace "except
Exception:" with "except PackageNotFoundError:" so other unexpected errors still
propagate.
| entry_points={ | ||
| "console_scripts": [ | ||
| "avocado = avocado.core.main:main", | ||
| "avocado-runner-noop = avocado.plugins.runners.noop:main", | ||
| "avocado-runner-dry-run = avocado.plugins.runners.dry_run:main", | ||
| "avocado-runner-exec-test = avocado.plugins.runners.exec_test:main", | ||
| "avocado-runner-python-unittest = avocado.plugins.runners.python_unittest:main", | ||
| "avocado-runner-avocado-instrumented = avocado.plugins.runners.avocado_instrumented:main", | ||
| "avocado-runner-tap = avocado.plugins.runners.tap:main", | ||
| "avocado-runner-asset = avocado.plugins.runners.asset:main", | ||
| "avocado-runner-package = avocado.plugins.runners.package:main", | ||
| "avocado-runner-pip = avocado.plugins.runners.pip:main", | ||
| "avocado-runner-vmimage = avocado.plugins.runners.vmimage:main", | ||
| "avocado-runner-podman-image = avocado.plugins.runners.podman_image:main", | ||
| "avocado-runner-sysinfo = avocado.plugins.runners.sysinfo:main", | ||
| "avocado-software-manager = avocado.utils.software_manager.main:main", | ||
| "avocado-external-runner = scripts.external_runner:main", | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify scripts.external_runner is properly packaged.
Line 231 references scripts.external_runner:main as a console script entry point. Past review comments flagged concerns about whether the scripts module is properly packaged (scripts/ needs __init__.py or explicit inclusion in packages).
Run this script to verify the scripts module is properly packaged:
🏁 Script executed:
#!/bin/bash
# Description: Verify scripts module packaging configuration
# Check if scripts/__init__.py exists
if [ -f "scripts/__init__.py" ]; then
echo "✓ scripts/__init__.py exists"
else
echo "✗ scripts/__init__.py is missing"
fi
# Check if scripts is included in find_packages or explicitly listed
rg -A5 'packages\s*=.*find_packages' setup.py | rg -q 'scripts' && echo "✓ scripts included in packages" || echo "✗ scripts not found in packages config"
# Check if external_runner.py exists
if [ -f "scripts/external_runner.py" ]; then
echo "✓ scripts/external_runner.py exists"
else
echo "✗ scripts/external_runner.py is missing"
fi
# Check if external_runner has a main function
if [ -f "scripts/external_runner.py" ]; then
rg -q 'def main\(' scripts/external_runner.py && echo "✓ main() function found" || echo "✗ main() function not found"
fiLength of output: 123
Add __init__.py to the scripts/ directory
Without it, scripts.external_runner:main won’t be packaged and the console script will break.
🤖 Prompt for AI Agents
In setup.py around lines 215-232 the console entry "avocado-external-runner =
scripts.external_runner:main" references scripts as a package but the scripts/
directory lacks an __init__.py, so the module won't be packaged; add an
__init__.py (can be empty) to the scripts/ directory and ensure the package is
included in the distribution (e.g., include 'scripts' in the packages list or
use find_packages / update MANIFEST.in if you rely on package discovery), then
rebuild the package so the console script import works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
♻️ Duplicate comments (9)
selftests/utils.py (1)
30-32: Address the previously flagged exception handling issue.The broad
except Exception:catch remains unaddressed from the previous review. As noted earlier and confirmed by static analysis, catchingPackageNotFoundErrorspecifically is necessary to avoid masking unexpected errors.Apply the previously suggested fix:
+from importlib.metadata import PackageNotFoundError, distribution -from importlib.metadata import distribution def python_module_available(module_name): """ Checks if a given Python module is available :param module_name: the name of the module :type module_name: str :returns: if the Python module is available in the system :rtype: bool """ try: distribution(module_name) return True - except Exception: - # Catch all exceptions (PackageNotFoundError, etc.) + except PackageNotFoundError: return Falseoptional_plugins/ansible/setup.py (1)
33-37: Consider removing duplicate metadata fields.The past review comment remains valid: the
descriptionfield duplicates what's in pyproject.toml. For consistency with other minimal setup.py files in this PR (e.g.,examples/plugins/tests/rogue/setup.pywhich only passesnameandversion), consider removing the description parameter.However, if the description is intentionally kept for specific backward-compatibility needs, the current implementation is acceptable.
pyproject.toml (3)
14-16: Restore the project's runtime dependencies.
[project].dependenciesnow contains only"setuptools", but the core package still imports third-party modules (for example,avocado.plugins.sysinfoimportspsutil,avocado.utils.assetimportsrequests, and the varianter plugins rely onjsonschema). These were previously declared ininstall_requires; without them,pip install avocado-frameworksucceeds yet the package immediately raisesImportErrorwhen those modules are loaded. Please port the full dependency list from the formersetup.pyinto this section (group purely optional items under extras if needed) so end users receive the required packages on installation.
30-30: Drop unsupported future Python classifier.The trove classifier
"Programming Language :: Python :: 3.14"is not published by PyPI yet. Keeping it here will cause uploads to PyPI to be rejected with "Invalid classifier". Please remove it (and re-add only after PyPI exposes the official classifier).Apply this diff:
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]
238-239: Do not exclude packages required by console scripts.
[project.scripts]registersavocado-external-runner = "scripts.external_runner:main"at line 54, but[tool.setuptools.packages.find]excludesscripts*at line 239, so that module never ships in the wheel/sdist and the console script fails at runtime. Removescripts*from the exclusion list (or package the module another way) to keep the entry point importable.Apply this diff to remove
scripts*from the exclusion list:[tool.setuptools.packages.find] -exclude = ["selftests*", "docs*", "examples*", "contrib*", "scripts*", "optional_plugins*"] +exclude = ["selftests*", "docs*", "examples*", "contrib*", "optional_plugins*"]examples/plugins/cli-cmd/hello_priority/pyproject.toml (1)
10-11: Entry point name conflict persists.Despite the previous review comment being marked as addressed, the entry point is still named
hello, which conflicts withexamples/plugins/cli-cmd/hello/pyproject.toml. If both plugins are installed, only onehellocommand will be registered, causing unpredictable behavior.Rename the entry point to
hello_priorityto match the module name:Apply this diff:
[project.entry-points."avocado.plugins.cli.cmd"] -hello = "hello_priority:HelloWorld" +hello_priority = "hello_priority:HelloWorld"optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (3)
143-145: Escape task identifier before runningpgrep.The identifier is interpolated raw into the shell command, so spaces or shell metacharacters break the command and allow injection. Quote it with
shlex.quote(...)before passing tocmd_status_output.- status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {identifier}")
38-46: Register timeouts as integers.Options
setup_timeoutandtest_timeoutare registered withoutkey_type=int, so user-provided values arrive as strings. Those strings are later passed to timeout-sensitive calls, causing runtime type errors. Register them withkey_type=int.- settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 - ) + settings.register_option( + section=section, + key="setup_timeout", + help_msg=help_msg, + default=3600, + key_type=int, + ) ... - settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 - ) + settings.register_option( + section=section, + key="test_timeout", + help_msg=help_msg, + default=14400, + key_type=int, + )
108-115: Harden slot initialization failures.If any slot file is missing or contains bad JSON, this will raise and brick the entire spawner initialization. Wrap the open/parse/login sequence in try/except so a single bad slot is logged and skipped instead of crashing the job.
- with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + except (FileNotFoundError, json.JSONDecodeError, KeyError) as exc: + LOG.warning("Skipping slot %s: %s", session_slot, exc) + continue + except Exception as exc: + LOG.error("Failed to initialize slot %s: %s", session_slot, exc) + continue + RemoteSpawner.slots_cache[session] = False
🧹 Nitpick comments (11)
optional_plugins/varianter_yaml_to_mux/setup.py (1)
33-37: Consider removing duplicate description field.Similar to
optional_plugins/ansible/setup.py, thedescriptionparameter duplicates metadata in pyproject.toml. For consistency with truly minimal setup.py files (likeexamples/plugins/tests/rogue/setup.py), consider keeping onlynameandversion. This is optional if backward compatibility requires the description field.optional_plugins/varianter_pict/setup.py (1)
1-1: Consider removing the shebang line.Since this file is now a backward-compatibility wrapper meant to be invoked as
python setup.pyrather than executed directly, the shebang is unnecessary. Removing it would eliminate the static analysis warning and better reflect the file's purpose.Apply this diff to remove the shebang:
-#!/usr/bin/env python3 -# This program is free software; you can redistribute it and/or modify +# This program is free software; you can redistribute it and/or modifyoptional_plugins/resultsdb/setup.py (1)
1-1: Consider removing the shebang line.The shebang is unnecessary for a file invoked as
python setup.py. Removing it would resolve the static analysis warning and better reflect the backward-compatibility wrapper purpose.Apply this diff:
-#!/usr/bin/env python3 -# This program is free software; you can redistribute it and/or modify +# This program is free software; you can redistribute it and/or modifyoptional_plugins/mail/setup.py (1)
1-1: Consider removing the shebang line.Since this backward-compatibility wrapper is invoked as
python setup.pyrather than executed directly, the shebang is unnecessary and causes a static analysis warning.Apply this diff:
-#!/usr/bin/env python3 -# This program is free software; you can redistribute it and/or modify +# This program is free software; you can redistribute it and/or modifyoptional_plugins/varianter_cit/setup.py (1)
1-1: Consider removing the shebang line.The shebang is not needed for a file invoked as
python setup.py. Removing it would eliminate the static analysis warning.Apply this diff:
-#!/usr/bin/env python3 -# This program is free software; you can redistribute it and/or modify +# This program is free software; you can redistribute it and/or modifyoptional_plugins/html/setup.py (1)
1-1: Consider removing the shebang line.For a backward-compatibility wrapper invoked as
python setup.py, the shebang is unnecessary and triggers a static analysis warning.Apply this diff:
-#!/usr/bin/env python3 -# This program is free software; you can redistribute it and/or modify +# This program is free software; you can redistribute it and/or modifyoptional_plugins/golang/setup.py (1)
1-1: Shebang without executable bit (EXE001).setup.py isn’t intended to be executed directly. Remove the shebang or make the file executable. Prefer removal:
-#!/usr/bin/env python3Makefile (1)
124-124: Satisfy checkmake: add PHONY and a test alias.Declare all and test as phony and provide a test target aliasing check.
@@ -.PHONY: pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables man +.PHONY: all test pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables man + +test: checkAlso applies to: 78-81
setup.py (1)
207-215: Optional: avoid entry_points drift by loading from pyproject.toml.To keep egg-only metadata aligned without duplicating, load entry points programmatically (same approach as suggested for plugins). I can draft a patch if you want to adopt it here too.
optional_plugins/result_upload/setup.py (1)
1-1: Shebang without executable bit (EXE001).Remove shebang to silence the linter on a non-executable packaging module:
-#!/usr/bin/env python3examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
5-8: Consider addingrequires-pythonconstraint.Example plugins should demonstrate complete configuration. Add
requires-python = ">=3.9"to match the main project's Python version requirement and provide a complete example.Apply this diff:
[project] name = "avocado-hello-world-parser" version = "1.0" description = "Avocado Hello World CLI command with config parser" +requires-python = ">=3.9"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(2 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(2 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(2 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(2 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(2 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(2 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(2 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(2 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(2 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(2 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/run_coverage(1 hunks)selftests/utils.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (3)
- optional_plugins/varianter_pict/README.rst
- optional_plugins/ansible/README.rst
- optional_plugins/varianter_yaml_to_mux/README.rst
🚧 Files skipped from review as they are similar to previous changes (25)
- .github/workflows/vmimage.yml
- optional_plugins/README.rst
- examples/plugins/job-pre-post/sleep/setup.py
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/resultsdb/pyproject.toml
- spell.ignore
- docs/source/guides/writer/chapters/subclassing.rst
- optional_plugins/mail/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- optional_plugins/robot/pyproject.toml
- .github/workflows/prerelease.yml
- docs/source/guides/contributor/chapters/plugins.rst
- docs/source/guides/contributor/chapters/environment.rst
- .github/workflows/push_ci.yml
- optional_plugins/ansible/pyproject.toml
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/tests/magic/setup.py
- examples/plugins/tests/rogue/pyproject.toml
- .github/workflows/weekly.yml
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- Makefile.gh
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/tests/README.rst
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/ansible/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/varianter_yaml_to_mux/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/resultsdb/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/spawner_remote/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
optional_plugins/mail/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/result_upload/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
selftests/utils.py
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
optional_plugins/golang/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/html/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/robot/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/varianter_cit/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/varianter_pict/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (41)
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: macOS with Python 3.11
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (26)
selftests/utils.py (1)
6-6: LGTM! Modern import for package checking.The migration from
pkg_resourcestoimportlib.metadatais the correct approach for modern Python package checking.selftests/run_coverage (1)
30-30: LGTM! Module-based invocation aligns with modern Python practices.The change from script path to module invocation (
-m selftests.check) is consistent with the project-wide migration and improves maintainability.examples/plugins/test-pre-post/hello/setup.py (1)
16-30: LGTM! Clean migration with clear documentation.The minimal setup.py approach with an explanatory docstring is appropriate. The name and version fields provide sufficient backward compatibility while pyproject.toml handles the full configuration.
examples/plugins/README.rst (1)
10-24: LGTM! Documentation reflects modern packaging practices.The updated workflow using
pip install -e .andpip uninstallaligns with current Python packaging standards and improves clarity with concrete examples.optional_plugins/varianter_cit/pyproject.toml (1)
1-44: LGTM! Well-structured pyproject.toml configuration.The packaging configuration follows modern standards with appropriate dynamic field sourcing, proper entry point declarations, and clear metadata. The setuptools>=61.0 requirement supports all declared features.
optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-48: LGTM! Complete pyproject.toml configuration with proper plugin integration.The configuration properly defines all necessary entry points (init, cli, varianter) for the YAML-to-MUX plugin and includes appropriate dependencies with reasonable version constraints.
examples/plugins/tests/rogue/setup.py (1)
16-30: LGTM! Exemplary minimal setup.py implementation.This file demonstrates the cleanest migration pattern with only
nameandversionin the setup() call, fully delegating configuration to pyproject.toml as documented in the docstring. This serves as a good reference for other setup.py migrations in the codebase.optional_plugins/varianter_pict/setup.py (1)
16-37: LGTM! Clean backward-compatibility wrapper.The minimal setup() approach with basic metadata (name, version, description) provides appropriate backward compatibility while the full configuration lives in pyproject.toml. The VERSION file reading is safe with proper encoding.
optional_plugins/resultsdb/setup.py (1)
16-37: LGTM! Backward-compatibility approach is appropriate.While a past comment suggested removing all metadata from setup(), keeping the minimal name/version/description here is standard practice for backward compatibility with legacy tools. The full rich metadata (dependencies, entry-points, etc.) properly lives in pyproject.toml.
examples/plugins/job-pre-post/sleep/pyproject.toml (1)
1-17: LGTM! Modern packaging configuration.The pyproject.toml follows current best practices:
- Build-system uses setuptools>=61.0 (supports pyproject.toml)
- Entry points properly declare plugin hooks for Avocado's init and job.prepost lifecycle
- py-modules is the correct approach for single-file module packaging
optional_plugins/mail/setup.py (1)
16-37: LGTM! Clean backward-compatibility implementation.The minimal setup() provides appropriate backward compatibility with legacy tooling while configuration properly lives in pyproject.toml.
optional_plugins/varianter_cit/setup.py (1)
16-37: LGTM! Appropriate backward-compatibility wrapper.The minimal metadata approach correctly balances backward compatibility with the modern pyproject.toml-based configuration.
optional_plugins/html/setup.py (1)
16-37: LGTM! Clean backward-compatibility implementation.The minimal setup() with basic metadata provides appropriate legacy tool support while full configuration resides in pyproject.toml.
examples/plugins/test-pre-post/hello/pyproject.toml (1)
1-17: LGTM! Standard plugin configuration.The pyproject.toml correctly configures the hello plugin:
- Modern build-system with setuptools>=61.0
- Proper entry-points for Avocado's test.pre and test.post hooks
- py-modules is appropriate for the single-file hello module
optional_plugins/golang/pyproject.toml (1)
1-47: LGTM! Comprehensive and well-structured configuration.This pyproject.toml exemplifies modern Python packaging best practices:
- Proper build-system setup with setuptools>=61.0
- Dynamic version/readme resolution from files (standard pattern)
- Complete metadata: authors, license, classifiers, URLs
- Correct dependency declaration (avocado-framework)
- Multiple plugin integration points via entry-points (resolver, runnable.runner)
- Script entry point for avocado-runner-golang command
- Package discovery configured appropriately with include pattern
- Python version constraint (>=3.9) aligns with project requirements
Based on learnings about setuptools 80.x series, this configuration avoids deprecated pkg_resources patterns and uses modern setuptools features appropriately.
Makefile (1)
79-81: Good move to module-based test runner.Using “-m selftests.check” is the right direction for modern packaging.
python-avocado.spec (2)
220-221: LGTM on module-based selftests invocation.This aligns with the rest of the migration.
8-19: Tarball name/dir mismatch does not break RPM builds Both avocado- and avocado_framework- named archives download successfully (HTTP 200), and%setup -n avocado_framework-%{ref}correctly renames the internalavocado-%{ref}directory.Likely an incorrect or invalid review comment.
optional_plugins/result_upload/pyproject.toml (3)
1-4: LGTM! Standard build system configuration.The build system configuration follows modern Python packaging best practices with setuptools≥61.0 and the standard
setuptools.build_metabackend.
42-44: VERSION and README.rst exist:optional_plugins/result_upload/VERSIONandREADME.rstare present, so the dynamic metadata configuration is valid.
14-16: Dependencies are complete. The plugin only imports modules fromavocado.*, so no additional third-party dependencies are required.optional_plugins/html/pyproject.toml (1)
43-44: Emptypackages.findconfiguration looks intentional.The empty
[tool.setuptools.packages.find]section will use default behavior (find all packages). Combined withinclude-package-data = true, this should correctly packageavocado_result_htmland its subpackages. This appears intentional and correct..github/actions/version/action.yml (1)
9-9: Review the need forPIP_BREAK_SYSTEM_PACKAGES=1.Setting
PIP_BREAK_SYSTEM_PACKAGES=1bypasses pip's protection against modifying system-managed Python installations (PEP 668). While this may be necessary in some CI containers, consider whether:
- The CI environment truly requires this override
- Using a virtual environment (
python3 -m venv) would be safer- This setting could mask packaging issues that users will encounter
If the CI environment is containerized and disposable, this is acceptable. Otherwise, prefer using virtual environments.
Based on learnings
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: LGTM! Good defensive API compatibility handling.The code correctly handles both the legacy string-based API and the newer TestCase object API by checking for the
nameattribute before accessing it. This ensures backward compatibility while supporting the newer API.optional_plugins/spawner_remote/pyproject.toml (1)
31-35: LGTM! Entry points are correctly configured.The entry point module paths correctly reference
avocado_spawner_remote.spawner:RemoteSpawnerInitandavocado_spawner_remote.spawner:RemoteSpawner. This aligns with the package structure and was properly addressed from previous review feedback..github/workflows/setup.yml (1)
36-43: Fix pip--userflag order (commands fail).
pip install ./path --useris parsed as an invalid requirement (--user), so every plugin install step here will fail. Put--userbefore the path, e.g.python3 -m pip install --user ./optional_plugins/golang.- python3 -m pip install ./optional_plugins/golang --user + python3 -m pip install --user ./optional_plugins/golang - python3 -m pip install ./optional_plugins/html --user + python3 -m pip install --user ./optional_plugins/html - python3 -m pip install ./optional_plugins/result_upload --user + python3 -m pip install --user ./optional_plugins/result_upload - python3 -m pip install ./optional_plugins/resultsdb --user + python3 -m pip install --user ./optional_plugins/resultsdb - python3 -m pip install ./optional_plugins/robot --user + python3 -m pip install --user ./optional_plugins/robot - python3 -m pip install ./optional_plugins/varianter_cit --user + python3 -m pip install --user ./optional_plugins/varianter_cit - python3 -m pip install ./optional_plugins/varianter_pict --user + python3 -m pip install --user ./optional_plugins/varianter_pict - python3 -m pip install ./optional_plugins/varianter_yaml_to_mux --user + python3 -m pip install --user ./optional_plugins/varianter_yaml_to_muxLikely an incorrect or invalid review comment.
| setup_timeout = self.config.get("spawner.remote.setup_timeout") | ||
| status, output = await RemoteSpawner.run_remote_cmd_async( | ||
| session, setup_hook, setup_timeout | ||
| ) | ||
| LOG.debug(f"Customization command exited with code {status}") | ||
| if status != 0: | ||
| LOG.error( | ||
| f"Error exit code {status} on {session.host}:{session.port} " | ||
| f"from setup hook with output:\n{output}" | ||
| ) | ||
| return False | ||
|
|
||
| cmd = shlex.join(entry_point_args) + " > /dev/null" | ||
| timeout = self.config.get("spawner.remote.test_timeout") | ||
| status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) | ||
| LOG.debug(f"Command exited with code {status}") | ||
| if status != 0: | ||
| LOG.error( | ||
| f"Error exit code {status} on {session.host}:{session.port} " | ||
| f"with output:\n{output}" | ||
| ) | ||
| return False | ||
|
|
||
| return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spawn_task waits for completion (no async concurrency).
run_remote_cmd_async blocks until the command ends, so spawn_task does not return until the task finishes. That defeats wait_task/is_task_alive and prevents the spawner from running tasks concurrently. Launch the remote process in the background (e.g. nohup ... & echo $!), store the PID/session, and return immediately so wait/terminate can manage it.
| cmd = shlex.join(entry_point_args) + " > /dev/null" | ||
| timeout = self.config.get("spawner.remote.test_timeout") | ||
| status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) | ||
| LOG.debug(f"Command exited with code {status}") | ||
| if status != 0: | ||
| LOG.error( | ||
| f"Error exit code {status} on {session.host}:{session.port} " | ||
| f"with output:\n{output}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep remote stdout/stderr; don’t send to /dev/null.
Redirecting to /dev/null discards all task output, making debugging impossible. Drop the redirection or capture to a per-task log file you can retrieve later.
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around
lines 182 to 189, the command string appends " > /dev/null" which discards
stdout (and leaves stderr un-captured), preventing any output from being
available for diagnostics; remove that redirection and instead preserve
stdout/stderr by building the entry_point_args command without " > /dev/null" so
RemoteSpawner.run_remote_cmd_async can capture both streams (or, if disked logs
are preferred, redirect both stdout and stderr to a per-task file like
/tmp/spawner_{session.id}.log and return that path), ensuring the remote call
captures and returns output for logging on failure.
| def create_task_output_dir(self, runtime_task): | ||
| output_dir_path = self.task_output_dir(runtime_task) | ||
| output_lxc_path = "/tmp/.avocado_task_output_dir" | ||
|
|
||
| os.makedirs(output_dir_path, exist_ok=True) | ||
| runtime_task.task.setup_output_dir(output_lxc_path) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use unique, sanitized remote output dirs.
Every task writes to /tmp/.avocado_task_output_dir, so concurrent runs collide and races corrupt logs. Generate a per-task directory (e.g. based on the identifier) and ensure it exists remotely before use.
🧰 Tools
🪛 Ruff (0.14.0)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around
lines 195-201, the code always uses the fixed path
"/tmp/.avocado_task_output_dir" which causes collisions for concurrent tasks;
change this to a unique, sanitized per-task path (for example
"/tmp/.avocado_task_output_dir_<sanitized_task_id>") by deriving the id from
runtime_task (e.g. runtime_task.id or another stable identifier), sanitize it
(remove/replace path separators, whitespace, very long names and unsafe chars),
build the full path with os.path.join, create the directory locally with
os.makedirs(..., exist_ok=True) and then pass that unique path into
runtime_task.task.setup_output_dir(...) so the directory exists before use;
ensure length/charset limits and fallback to a UUID if the identifier cannot be
safely sanitized.
| async def wait_task(self, runtime_task): | ||
| while True: | ||
| if not RemoteSpawner.is_task_alive(runtime_task): | ||
| return | ||
| await asyncio.sleep(0.1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add timeout when waiting for tasks.
wait_task loops forever if is_task_alive never flips (hangs or detection bug). Honor spawner.remote.test_timeout (or a dedicated wait timeout) to break out instead of blocking indefinitely.
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py around
lines 202 to 206, wait_task currently loops forever if
RemoteSpawner.is_task_alive never becomes False; update it to honor a timeout
(use spawner.remote.test_timeout or add a dedicated wait timeout) by tracking
start time (or using asyncio.wait_for) and breaking out when elapsed exceeds the
configured timeout, returning or raising a TimeoutError (consistent with
surrounding API), and ensure any awaited sleep/cancellation is handled cleanly;
read the timeout from configuration with a sensible default and log or surface
the timeout event for callers.
| packages=find_packages(exclude=("selftests*",)), | ||
| include_package_data=True, | ||
| zip_safe=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
find_packages() is including optional plugin packages by accident.
With the project root scan and only excluding “selftests*”, packages under optional_plugins/* (e.g., avocado_result_upload) will be picked up in wheels, causing unintended bundling and conflicts with separate plugin wheels/RPM subpackages.
Restrict to the core “avocado” namespace:
- packages=find_packages(exclude=("selftests*",)),
+ packages=find_packages(include=("avocado", "avocado.*")),You can quickly list discovered packages during sdist/wheel builds locally and confirm only “avocado” packages are present.
🏁 Script executed:
#!/usr/bin/env bash
set -eo pipefail
echo "Top-level directories:"
find . -maxdepth 2 -type d | sed 's|^\./||'
echo
echo "Inspecting optional_plugins:"
if [ -d optional_plugins ]; then
echo "optional_plugins directory found."
echo "Subdirectories:"
find optional_plugins -type d | sed 's|^\./||'
echo
echo "Python packages under optional_plugins (files named __init__.py):"
find optional_plugins -type f -name "__init__.py" | sed 's|^\./||'
else
echo "optional_plugins directory not present."
fiLength of output: 2700
Restrict find_packages() to the avocado namespace
In setup.py around line 212, replace
- packages=find_packages(exclude=("selftests*",)),
+ packages=find_packages(include=("avocado","avocado.*")),This prevents any optional_plugins/* packages from being bundled.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| packages=find_packages(exclude=("selftests*",)), | |
| include_package_data=True, | |
| zip_safe=False, | |
| packages=find_packages(include=("avocado","avocado.*")), | |
| include_package_data=True, | |
| zip_safe=False, |
🤖 Prompt for AI Agents
In setup.py around lines 212 to 214, the current call
packages=find_packages(exclude=("selftests*",)) is too broad and pulls in
optional_plugins; replace it with a find_packages call that explicitly restricts
to the avocado namespace (for example:
packages=find_packages(include=("avocado*",), exclude=("selftests*",))) so only
avocado packages are bundled and optional_plugins are excluded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
optional_plugins/golang/setup.py (1)
36-51: Egg/develop installs will miss package modules (packages not specified).setup() lacks packages/include_package_data, so eggs and develop installs won’t include avocado_golang*. Add discovery and include data.
-from setuptools import setup +from setuptools import setup, find_packages @@ setup( name="avocado-framework-plugin-golang", version=VERSION, description="Avocado Plugin for Execution of Golang tests", + packages=find_packages(include=("avocado_golang", "avocado_golang.*")), + include_package_data=True, entry_points={optional_plugins/mail/setup.py (1)
40-47: Packages not included in egg/develop installs.Add discovery for avocado_result_mail* and include data.
-from setuptools import setup +from setuptools import setup, find_packages @@ setup( name="avocado-framework-plugin-result-mail", version=VERSION, description="Avocado Mail Notification for Jobs", + packages=find_packages(include=("avocado_result_mail", "avocado_result_mail.*")), + include_package_data=True, entry_points={
♻️ Duplicate comments (17)
selftests/utils.py (1)
27-32: Use specific exception type instead of bareException.Catching
Exceptionis too broad and may hide unexpected errors (e.g.,AttributeError,TypeError) that should propagate. Theimportlib.metadata.distribution()function raisesPackageNotFoundErrorwhen a distribution isn't found.Apply this diff to handle the specific exception:
+from importlib.metadata import PackageNotFoundError, distribution -from importlib.metadata import distribution def python_module_available(module_name): """ Checks if a given Python module is available :param module_name: the name of the module :type module_name: str :returns: if the Python module is available in the system :rtype: bool """ try: distribution(module_name) return True - except Exception: - # Catch all exceptions (PackageNotFoundError, etc.) + except PackageNotFoundError: return Falseexamples/plugins/tests/rogue/pyproject.toml (1)
19-20: Package discovery is misconfigured
py-modules = ["avocado_rogue"]tells setuptools to ship a singleavocado_rogue.py, yet all entry points importavocado_rogue.runner/resolver. With the actual package layout (avocado_rogue/runner.py, etc.), the build omits those modules and any install/import will fail. Switch to package discovery instead ofpy-modules.-[tool.setuptools] -py-modules = ["avocado_rogue"] +[tool.setuptools.packages.find] +include = ["avocado_rogue"]setup.py (4)
215-233: Verify console script target ‘scripts.external_runner:main’ is packaged.Ensure scripts/ is a package and included, otherwise the entry point will fail.
#!/bin/bash # Read-only verification of packaging for scripts.external_runner set -euo pipefail echo "Check scripts package files" if [ -f "scripts/external_runner.py" ]; then echo "✓ scripts/external_runner.py exists" else echo "✗ scripts/external_runner.py is missing"; exit 1 fi if [ -f "scripts/__init__.py" ]; then echo "✓ scripts/__init__.py exists (packaged as a module)" else echo "✗ scripts/__init__.py missing; console script import will fail"; exit 1 fi echo "Check setup/pyproject include scripts package" rg -n -C1 -P 'find_packages\([^)]*include[^)]*\)' setup.py || true rg -n -C1 -P '^\[tool\.setuptools\.packages\.find\]' pyproject.toml || true
207-345: Avoid duplicating entry_points in setup.py; programmatically load from pyproject.toml.Keeps metadata in sync and reduces drift/maintenance.
I can provide a helper to parse pyproject with tomllib/tomli and convert to setuptools’ entry_points mapping on demand.
16-26: Replace distutils clean import (breaks on Python 3.12+).Line 31 still imports from distutils. Use setuptools’ clean.
Based on learnings
-from distutils.command.clean import clean # pylint: disable=W0402 +from setuptools.command.clean import clean
207-214: find_packages() is too broad; it will pick up optional_plugins.Restrict to the avocado namespace to avoid bundling optional plugins in the core wheel.
- packages=find_packages(exclude=("selftests*",)), + packages=find_packages(include=("avocado", "avocado.*")),pyproject.toml (3)
14-16: Restore runtime dependencies.The
[project].dependenciesarray contains only"setuptools", but the core package imports third-party modules at runtime (e.g.,psutil,requests,jsonschema). Without these dependencies declared,pip install avocado-frameworkwill succeed but the package will raiseImportErrorwhen imported.Restore the full dependency list from the former setup.py. For example:
dependencies = [ "setuptools", + "psutil>=5.9.0", + "requests>=2.25.0", + "jsonschema>=3.2.0", + # ... other required packages ]
30-30: Remove unsupported Python 3.14 classifier.The trove classifier
"Programming Language :: Python :: 3.14"is not yet published by PyPI. Including it will cause package uploads to PyPI to be rejected with "Invalid classifier" errors.Apply this diff:
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]
54-54: Console scriptavocado-external-runnerwill fail at runtime.Line 54 registers
avocado-external-runner = "scripts.external_runner:main", but line 239 excludesscripts*from packaging. This means thescripts.external_runnermodule will not be included in the wheel/sdist, causing the console script to fail withModuleNotFoundErrorat runtime.Apply this diff:
[tool.setuptools.packages.find] -exclude = ["selftests*", "docs*", "examples*", "contrib*", "scripts*", "optional_plugins*"] +exclude = ["selftests*", "docs*", "examples*", "contrib*", "optional_plugins*"]Also applies to: 238-239
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
38-46: Register timeouts as integers.Both
setup_timeoutandtest_timeoutare currently registered withoutkey_type=int, so they arrive as strings and break arithmetic/time comparisons downstream. Please addkey_type=intto both registrations.- settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 - ) + settings.register_option( + section=section, + key="setup_timeout", + help_msg=help_msg, + default=3600, + key_type=int, + ) ... - settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 - ) + settings.register_option( + section=section, + key="test_timeout", + help_msg=help_msg, + default=14400, + key_type=int, + )
106-114: Handle slot initialization failures.Any missing/invalid slot file or failed login currently raises and crashes the spawner. Please wrap the load/login block in
try/except, warn on per-slot failures, and continue so one bad slot doesn’t kill initialization.- with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + except (FileNotFoundError, json.JSONDecodeError, KeyError) as exc: + ... + else: + RemoteSpawner.slots_cache[session] = False
137-145: Escape the task identifier in the remote command.
pgrep ... -f {identifier}without quoting breaks on whitespace/shell metacharacters and is a command-injection risk because task IDs are user-controlled. Please wrap the identifier withshlex.quote()(import already present).- status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {safe_identifier}")
148-193: Don’t run the task synchronously.
run_remote_cmd_asyncwaits for completion, sospawn_task()blocks until the task exits. That defeatswait_task()/is_task_alive()semantics and prevents concurrency. Launch the remote command in the background (e.g.nohup ... & echo $!), store the PID/handle onruntime_task, and return immediately so wait/terminate can manage it.
182-191: Keep remote stdout/stderr.Appending
> /dev/nulldiscards all task output, leaving nothing for debugging or result collection. Drop the redirection or send it to a per-task log you can retrieve.- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)
195-201: Use a unique, sanitized output directory per task.Hard-coding
/tmp/.avocado_task_output_dircauses collisions and violates temp-dir safety checks (Ruff S108). Derive a per-task path (sanitize the identifier or use UUID), ensure it exists remotely, and pass that intosetup_output_dir.
202-206: Add a timeout to wait_task.
wait_task()loops forever ifis_task_alivenever flips, so a hung remote task stalls the job indefinitely. Honorspawner.remote.test_timeout(or a dedicated wait timeout) and abort once exceeded.
208-216: Improve termination logging.The failure log doesn’t interpolate the host and drops the traceback; Ruff also suggests moving the return to an
else. UseLOG.exception(f"Failed to terminate task on {session.host}:{session.port}")and place the successreturn Truein anelseblock.try: session.read_up_to_prompt() - return True - except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") - return False + except exceptions.ExpectTimeoutError: + LOG.exception( + f"Failed to terminate task on {session.host}:{session.port}" + ) + return False + else: + return True
🧹 Nitpick comments (10)
optional_plugins/golang/pyproject.toml (2)
1-3: Consider raising the setuptools lower bound (and dropping wheel here).Setuptools 80.x is current and includes many PEP 621 fixes; 61.0 is quite old. Recommend
setuptools>=68(or higher) and omittingwheelfrom [build-system] (pip brings it as needed).Based on learnings
-[build-system] -requires = ["setuptools>=61.0", "wheel"] +[build-system] +requires = ["setuptools>=68"] build-backend = "setuptools.build_meta"
27-29: Use HTTPS for the homepage URL.Avoid HTTP and redirects.
[project.urls] -Homepage = "http://avocado-framework.github.io/" +Homepage = "https://avocado-framework.github.io/"optional_plugins/golang/setup.py (1)
1-1: Shebang present but file not executable.Either make it executable or drop the shebang.
Please confirm intent. If not directly executed, remove the first line.
-#!/usr/bin/env python3 +#optional_plugins/robot/setup.py (1)
1-1: Shebang present but file not executable.Either chmod +x or remove the shebang.
If not intended to be run directly, remove it:
-#!/usr/bin/env python3 +#optional_plugins/mail/setup.py (1)
1-1: Shebang present but file not executable.Make executable or remove the shebang.
-#!/usr/bin/env python3 +#.github/workflows/setup.yml (2)
113-113: Standardize on python -m pip.Use the interpreter-managed pip consistently to avoid PATH/venv mismatches.
- run: pip3 install -r requirements-dev.txt + run: python3 -m pip install -r requirements-dev.txt @@ - run: pip3 install -r requirements-dev.txt + run: python3 -m pip install -r requirements-dev.txt @@ - pip install -r requirements-dev.txt + python3 -m pip install -r requirements-dev.txtAlso applies to: 149-149, 215-215
176-179: Install venv support (python3-venv) or drop the package install.You’re using python3 -m venv, which requires the python3-venv package on Ubuntu. Installing python3-virtualenv is unnecessary here.
- - name: Install packages - run: | - sudo apt-get update - sudo apt-get install -y python3-virtualenv + - name: Ensure venv support + run: | + sudo apt-get update + sudo apt-get install -y python3-venvRepeat the same change in the Developer Virtualenv job.
Also applies to: 209-211
Makefile (3)
78-81: Add a “test” alias and mark missing phony targets.Satisfy checkmake and provide a conventional test target aliasing check.
check: clean uninstall develop # Unless manually set, this is equivalent to AVOCADO_CHECK_LEVEL=0 $(PYTHON) -m selftests.check + +test: check @@ -.PHONY: pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables man +.PHONY: all test pip install clean uninstall requirements-dev smokecheck check develop develop-external develop-plugins develop-plugin variables manBased on static analysis hints
Also applies to: 124-124
82-84: Prefer pip editable installs over setup.py develop.Align with the pyproject/pip migration and reduce reliance on legacy setup.py behavior.
develop: - $(PYTHON) setup.py develop $(PYTHON_DEVELOP_ARGS) + $(PYTHON) -m pip install -e . $(PYTHON_DEVELOP_ARGS) @@ - $(PYTHON) setup.py develop $(PYTHON_DEVELOP_ARGS) --external + $(PYTHON) -m pip install -e . $(PYTHON_DEVELOP_ARGS) @@ develop-plugins: @echo "Installing all optional plugins in develop mode..." @for plugin in $(AVOCADO_OPTIONAL_PLUGINS); do \ echo "Installing $$plugin..."; \ - $(PYTHON) -m pip install -e "$$plugin" $(PYTHON_DEVELOP_ARGS); \ + $(PYTHON) -m pip install -e "$$plugin" $(PYTHON_DEVELOP_ARGS); \ done @@ develop-plugin: ifndef PLUGIN $(error PLUGIN is not defined. Usage: make develop-plugin PLUGIN=html) endif @echo "Installing plugin: $(PLUGIN)..." - $(PYTHON) -m pip install -e "optional_plugins/$(PLUGIN)" $(PYTHON_DEVELOP_ARGS) + $(PYTHON) -m pip install -e "optional_plugins/$(PLUGIN)" $(PYTHON_DEVELOP_ARGS)Also applies to: 89-89, 91-98, 99-105
108-115: Use pattern variables in the man rule.Make the rule generic and future-proof.
- @if command -v rst2man >/dev/null 2>&1; then \ - rst2man man/avocado.rst man/avocado.1; \ + @if command -v rst2man >/dev/null 2>&1; then \ + rst2man "$<" "$@"; \ else \ echo "ERROR: rst2man not found, cannot build manpage"; \ exit 1; \ fi
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(3 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(2 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(2 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(2 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(2 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(2 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(2 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(2 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(2 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(3 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/utils.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (2)
- examples/plugins/cli-cmd/hello/pyproject.toml
- optional_plugins/varianter_pict/README.rst
🚧 Files skipped from review as they are similar to previous changes (28)
- .github/actions/version/action.yml
- optional_plugins/varianter_yaml_to_mux/README.rst
- optional_plugins/varianter_cit/pyproject.toml
- .github/workflows/prerelease.yml
- optional_plugins/spawner_remote/pyproject.toml
- optional_plugins/mail/pyproject.toml
- examples/plugins/tests/README.rst
- optional_plugins/varianter_pict/pyproject.toml
- examples/plugins/test-pre-post/hello/setup.py
- optional_plugins/robot/pyproject.toml
- optional_plugins/ansible/README.rst
- docs/source/guides/contributor/chapters/plugins.rst
- examples/plugins/tests/magic/pyproject.toml
- optional_plugins/ansible/pyproject.toml
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- examples/plugins/test-pre-post/hello/pyproject.toml
- Makefile.gh
- spell.ignore
- optional_plugins/html/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- examples/plugins/cli-cmd/hello_option/setup.py
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- .github/workflows/ci.yml
- examples/plugins/cli-cmd/hello/setup.py
- .github/workflows/push_ci.yml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/resultsdb/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/robot/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/html/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/result_upload/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
optional_plugins/varianter_yaml_to_mux/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/spawner_remote/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/varianter_pict/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/golang/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/mail/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/varianter_cit/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
optional_plugins/ansible/setup.py
1-1: Shebang is present but file is not executable
(EXE001)
selftests/utils.py
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (40)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: Fedora selftests
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: macOS with Python 3.11
🔇 Additional comments (26)
optional_plugins/robot/avocado_robot/robot.py (2)
44-44: LGTM! Consistent with the API compatibility change.The usage of
test_nameis correct and maintains backward compatibility while supporting the new TestCase object API.
41-42: Require manual verification of Robot Framework API compatibility
- Test with both old (string test names) and new (TestCase objects) Robot Framework versions to confirm
hasattr(test_case, "name")handles both correctly and thatnameis always a valid string.- Add tests covering both scenarios and document supported Robot Framework versions (e.g., in requirements or project docs).
docs/source/guides/contributor/chapters/environment.rst (1)
55-62: LGTM! Documentation correctly updated for modern packaging.The migration from
python setup.py developtopip install -e .is the recommended approach, and the terminology updates (editable install vs. egg link) align with current Python packaging standards.examples/plugins/README.rst (1)
10-24: LGTM! Clear documentation for pip-based plugin workflow.The updated instructions provide clear examples for both installation and uninstallation using pip, which is more intuitive than the previous setup.py-based approach.
examples/plugins/cli-cmd/hello_parser/setup.py (1)
1-30: LGTM! Minimal setup.py correctly implements backward compatibility.The file now serves its intended purpose: maintaining compatibility with legacy tooling while delegating all configuration to pyproject.toml. The docstring clearly explains the rationale.
examples/plugins/job-pre-post/sleep/setup.py (1)
1-30: LGTM! Consistent backward-compatible setup.py.This file follows the same minimal pattern as other plugins in the PR, correctly delegating all configuration to pyproject.toml while maintaining backward compatibility.
examples/plugins/tests/rogue/setup.py (1)
1-30: LGTM! Backward-compatible setup.py follows PR conventions.Consistent with the other minimal setup.py files in this migration, providing backward compatibility while moving configuration to pyproject.toml.
optional_plugins/README.rst (1)
10-34: LGTM! Clear documentation for pip-based plugin management.The updated instructions provide comprehensive examples for installing, uninstalling, and managing optional plugins using modern pip-based workflows and updated make targets.
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-30: LGTM! Consistent minimal setup.py pattern.This file correctly follows the established pattern for backward-compatible setup.py files in the migration to pyproject.toml-based configuration.
optional_plugins/varianter_cit/setup.py (2)
16-26: LGTM!The docstring clearly explains the purpose of this minimal setup.py for backward compatibility with egg distributions.
32-48: LGTM!The minimal setup() call correctly includes entry_points for egg builds, keeping them in sync with pyproject.toml as noted in the docstring.
python-avocado.spec (4)
8-8: LGTM!The package naming updates from
avocado-toavocado_framework-correctly align with the pyproject.toml-based packaging structure.Also applies to: 18-18
102-104: LGTM!The setup directory names correctly match the updated gittar archive naming.
220-220: LGTM!Using
python3 -m selftests.checkfor test invocation is the correct approach for module-based execution, aligning with the pyproject.toml migration.
243-250: Adjust spec exclusions to match actual install layout
- Exclude
avocado_result_htmlunder%{python3_sitelib}/optional_plugins/html/avocado_result_html*instead of directly under%{python3_sitelib}.- Verify whether
contribandscriptsland at top-levelsite-packagesor within a package namespace (e.g.avocado/contrib*,avocado/scripts*) and update the%excludedirectives accordingly.optional_plugins/result_upload/pyproject.toml (1)
1-44: LGTM!The pyproject.toml configuration correctly defines the build system, project metadata, entry points, and packaging configuration following PEP-621 standards. The dynamic version/readme loading and entry points align with the broader migration strategy.
optional_plugins/result_upload/setup.py (1)
36-48: LGTM!The minimal setup() call correctly includes entry_points for egg builds, addressing the previous review concerns about broken plugin discovery. The entry points are properly synced with pyproject.toml.
pyproject.toml (2)
1-3: LGTM!The build system configuration, core project metadata, and project URLs are correctly defined following PEP-621 standards.
Also applies to: 5-12, 33-37
39-53: LGTM!The console scripts and plugin entry points are comprehensively defined, covering all plugin groups (init, cli, runners, spawners, etc.). The structure aligns well with the broader migration to pyproject.toml-based packaging.
Also applies to: 56-166
docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: LGTM!The documentation correctly updates the packaging example from setup.py to pyproject.toml, following PEP-621 standards. The example demonstrates dynamic version sourcing and avocado-framework dependency declaration, which aligns with the migration strategy.
88-101: LGTM!The installation instructions correctly update from the deprecated
python setup.py developto the modernpip install -e .approach for editable installs..github/workflows/vmimage.yml (1)
42-42: LGTM!The update from
python setup.py developtopython -m pip install --user -e .correctly modernizes the workflow to use pip-based editable installs, aligning with the pyproject.toml migration..github/workflows/weekly.yml (2)
39-39: LGTM!The updates from
python3 setup.py developtopython3 -m pip install --user -e .correctly modernize both workflow jobs to use pip-based editable installs.Also applies to: 83-83
47-47: LGTM!The changes from direct script invocation to module-based execution (
python3 -m selftests.check) align with the pyproject.toml migration and ensure the correct module is executed.Also applies to: 89-89
.github/workflows/setup.yml (1)
33-44: Verify user-base bin is on PATH for --user installs.avocado goes to ~/.local/bin with --user; ensure PATH includes it before invoking avocado.
Add before “Avocado version”:
- name: Ensure user bin on PATH run: echo "$HOME/.local/bin" >> $GITHUB_PATHoptional_plugins/resultsdb/pyproject.toml (1)
1-48: Packaging config looks good.Project metadata, dynamic version/readme, entry points, and package discovery are correctly set.
| @@ -1,4 +1,4 @@ | |||
| #!/bin/env python3 | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shebang present but file not executable.
The static analysis tool flags that this file has a shebang but lacks executable permissions. Either add executable permissions (chmod +x) or remove the shebang if the file is not meant to be executed directly.
Apply this fix:
chmod +x optional_plugins/result_upload/setup.py🧰 Tools
🪛 Ruff (0.14.0)
1-1: Shebang is present but file is not executable
(EXE001)
🤖 Prompt for AI Agents
In optional_plugins/result_upload/setup.py at line 1, the file contains a
shebang but is not marked executable; make the file executable by adding the
executable permission (e.g., chmod +x) so the shebang is respected, or
alternatively remove the shebang if this script is not intended to be run
directly—prefer adding the executable bit if it should be runnable.
optional_plugins/resultsdb/setup.py
Outdated
| @@ -1,4 +1,4 @@ | |||
| #!/bin/env python3 | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop the shebang (or make the file executable).
This is not a runnable script; the shebang triggers EXE001. Prefer removing it.
As a fix:
-#!/usr/bin/env python3Based on static analysis hints
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #!/usr/bin/env python3 |
🧰 Tools
🪛 Ruff (0.14.0)
1-1: Shebang is present but file is not executable
(EXE001)
🤖 Prompt for AI Agents
In optional_plugins/resultsdb/setup.py at lines 1-1, the file starts with a
shebang but is not an executable script which triggers EXE001; remove the
leading "#!/usr/bin/env python3" line (or alternatively make the file executable
and ensure it is intended to be run as a script). After removing the shebang,
run lint/static analysis to confirm EXE001 is resolved.
| @@ -1,4 +1,4 @@ | |||
| #!/bin/env python3 | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop the shebang (or make the file executable).
Not a script; remove to silence EXE001.
As a fix:
-#!/usr/bin/env python3Based on static analysis hints
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #!/usr/bin/env python3 |
🧰 Tools
🪛 Ruff (0.14.0)
1-1: Shebang is present but file is not executable
(EXE001)
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/setup.py around line 1, the file contains a
shebang but is not an executable script which triggers EXE001; remove the
leading "#!/usr/bin/env python3" line to silence the warning (or alternatively
make the file executable and keep the shebang if it is intended to be run
directly).
b149318 to
1d4c3bf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
optional_plugins/ansible/setup.py (1)
28-36: Align dependency markers in pyproject.toml with setup.py
Mirror thecffipython_version markers, addcryptography<46.0.0; python_version<'3.10', and include or confirmmarkupsafe<3.0.0in optional_plugins/ansible/pyproject.toml.
♻️ Duplicate comments (23)
selftests/utils.py (1)
30-32: Catch specific exception type instead of bare Exception.This issue was previously identified: catching
Exceptionis too broad and may mask unexpected errors (e.g.,AttributeError,TypeError) that should propagate. Theimportlib.metadata.distribution()function raisesPackageNotFoundErrorwhen a distribution isn't found.The fix was already suggested in the previous review comment—import and catch
PackageNotFoundErrorspecifically instead of the bareException.examples/plugins/cli-cmd/hello/setup.py (1)
1-15: Past review comment already addressed.The metadata in this setup.py now correctly matches the pyproject.toml configuration. The name, description, and entry points are consistent.
Makefile.gh (1)
65-69: Add guard for pyproject.toml existence before building wheels.The unconditional
python -m buildinvocation will fail for any plugin directory lacking a pyproject.toml file. This inconsistency with thebuild-eggtarget (lines 78-83, which checks for setup.py existence) creates a fragile build process.Apply this diff to add the guard:
build-wheel: pip $(PYTHON) -m pip install $(PYTHON_DEVELOP_ARGS) build if test ! -d PYPI_UPLOAD; then mkdir PYPI_UPLOAD; fi $(PYTHON) -m build -o PYPI_UPLOAD for PLUGIN in $(AVOCADO_OPTIONAL_PLUGINS); do\ - cd $$PLUGIN;\ - $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ - cd -;\ + if test -f $$PLUGIN/pyproject.toml; then\ + cd $$PLUGIN;\ + $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ + cd -;\ + fi;\ doneexamples/plugins/tests/magic/pyproject.toml (1)
25-25: Complete the package discovery configuration.The
[tool.setuptools.packages.find]section is empty. Entry points referenceavocado_magicmodule, so you must specify which packages to include for proper packaging.Apply this diff:
[tool.setuptools.packages.find] +include = ["avocado_magic*"]examples/plugins/tests/rogue/pyproject.toml (1)
19-20: Package declaration doesn't match entry point targets.The configuration declares
py-modules = ["avocado_rogue"](single-file module) but entry points target submodules likeavocado_rogue.runner:mainandavocado_rogue.resolver:RogueResolver, which require a package directory structure.If avocado_rogue is a package directory (with
__init__.py,resolver.py,runner.py), apply this diff:[tool.setuptools] -py-modules = ["avocado_rogue"] +packages = ["avocado_rogue"]If it's a single file
avocado_rogue.py, the entry points must be updated to target the top-level module instead.python-avocado.spec (1)
243-250: Verify the new package exclusions match actual install locations.The additions of
contrib*,scripts*, andavocado_result_html*to the exclusions list should align with the actual package structure. A past review flagged thatavocado_result_html*may need path correction.Run the following script to verify these directories/packages exist and their install locations:
#!/bin/bash # Description: Verify excluded paths exist and check their installed locations # Check contrib directory echo "=== Checking contrib directory ===" fd -t d '^contrib$' --max-depth 2 # Check scripts directory echo "=== Checking scripts directory ===" fd -t d '^scripts$' --max-depth 2 # Check avocado_result_html locations echo "=== Checking avocado_result_html package ===" fd -t d 'avocado_result_html' --max-depth 4 # Check if avocado_result_html is in optional_plugins echo "=== Checking optional_plugins structure ===" fd -t d . optional_plugins --max-depth 2setup.py (4)
31-31: Critical: distutils import breaks on Python 3.12+.The import
from distutils.command.clean import cleanwill fail on Python 3.12+ as distutils was removed from the standard library.Apply this diff:
-from distutils.command.clean import clean # pylint: disable=W0402 +from setuptools.command.clean import cleanBased on learnings
212-212: Critical: find_packages() includes optional plugins unintentionally.With
packages=find_packages(exclude=("selftests*",)), packages underoptional_plugins/*(e.g.,avocado_result_upload) will be included in the wheel, causing conflicts with separate plugin packages.Apply this diff:
- packages=find_packages(exclude=("selftests*",)), + packages=find_packages(include=("avocado", "avocado.*")),
237-237: Critical: scripts.external_runner requires scripts/init.py.The console script entry point
"avocado-external-runner = scripts.external_runner:main"referencesscriptsas a package, but withoutscripts/__init__.py, the module won't be packaged and the entry point will fail at runtime.Verify and add
scripts/__init__.py:#!/bin/bash # Description: Check if scripts/__init__.py exists and scripts package is properly configured echo "=== Checking scripts/__init__.py ===" if [ -f "scripts/__init__.py" ]; then echo "✓ scripts/__init__.py exists" else echo "✗ scripts/__init__.py is missing - will break console script" fi echo "=== Checking scripts/external_runner.py ===" if [ -f "scripts/external_runner.py" ]; then echo "✓ scripts/external_runner.py exists" rg -q 'def main\(' scripts/external_runner.py && echo "✓ main() function found" || echo "✗ main() function not found" else echo "✗ scripts/external_runner.py is missing" fi
221-350: Major: Entry points duplication creates maintenance burden.The 130-line entry_points dictionary duplicates configuration from pyproject.toml. Any plugin changes must be updated in both files, creating a significant maintenance risk.
Consider these options:
Eliminate egg builds (preferred): Deprecate egg distribution support and remove setup.py entirely, relying only on wheel/sdist from pyproject.toml.
Programmatic sync: Parse pyproject.toml at build time to generate entry_points.
Add validation: Create a CI check comparing entry_points between both files.
Would you like me to generate a validation script?
pyproject.toml (3)
14-16: Critical: Missing runtime dependencies.The
[project].dependencieslist contains only"setuptools", but the codebase imports many third-party packages (e.g.,psutil,requests,jsonschema) that were previously in setup.py'sinstall_requires. This will causeImportErrorat runtime afterpip install avocado-framework.Restore the full dependency list from setup.py. At minimum, add:
- psutil (for avocado.plugins.sysinfo)
- requests (for avocado.utils.asset)
- jsonschema (for schema validation)
dependencies = [ "setuptools", + "psutil>=5.9.5", + "requests>=2.32.3", + "jsonschema>=3.2.0", ]Move purely optional features to
[project.optional-dependencies].Based on learnings
30-30: Major: Remove unsupported Python 3.14 classifier.PyPI does not yet publish the
"Programming Language :: Python :: 3.14"classifier. Including it will cause package upload failures.Apply this diff:
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]Re-add it only after PyPI publishes the official classifier.
54-54: Critical: scripts.external_runner entry point will fail.The console script
avocado-external-runner = "scripts.external_runner:main"references thescriptsmodule, but line 239 excludes"scripts*"from packaging. The entry point will fail at runtime withModuleNotFoundError.Apply this diff:
[tool.setuptools.packages.find] -exclude = ["selftests*", "docs*", "examples*", "contrib*", "scripts*", "optional_plugins*"] +exclude = ["selftests*", "docs*", "examples*", "contrib*", "optional_plugins*"]Alternatively, move the external_runner module into a packaged location (e.g.,
avocado.scripts.external_runner) and update the entry point..github/workflows/prerelease.yml (1)
51-51: Critical: Typo in module name.The command contains
selftets.checkinstead ofselftests.check. This will cause the workflow to fail with aModuleNotFoundError.Apply this diff:
- run: python3 -m selftets.check --select=pre-release,vmimage + run: python3 -m selftests.check --select=pre-release,vmimageoptional_plugins/spawner_remote/setup.py (1)
1-1: Drop the non-portable shebang (or make the file executable).Not a script; remove to silence EXE001. Also uses /bin/env.
-#!/bin/env python3optional_plugins/ansible/setup.py (1)
1-1: Drop the shebang (or use /usr/bin/env and make executable).Not intended to be executed directly; remove to avoid EXE001.
-#!/bin/env python3optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (7)
143-145: Shell-escape the identifier in pgrep.Avoid breakage/injection with special chars.
- status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {safe_identifier}")
148-193: Spawn must be non-blocking; keep output (don’t redirect to /dev/null).run_remote_cmd_async waits for completion, so current spawn_task blocks and discards logs.
- cmd = shlex.join(entry_point_args) + " > /dev/null" - timeout = self.config.get("spawner.remote.test_timeout") - status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) + # Launch in background and capture PID; keep stdout/stderr to a remote log + remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1 & echo $!" + # Short timeout since backgrounding returns immediately + status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, 30) LOG.debug(f"Command exited with code {status}") if status != 0: LOG.error( f"Error exit code {status} on {session.host}:{session.port} " f"with output:\n{output}" ) return FalseOptionally parse and store the PID from output for advanced liveness checks.
195-201: Use a unique, sanitized remote output directory per task.Single fixed path collides across tasks and is flagged insecure.
- output_lxc_path = "/tmp/.avocado_task_output_dir" + safe_id = "".join(c if c.isalnum() or c in "._-" else "_" for c in runtime_task.task.identifier)[:64] + output_lxc_path = f"/tmp/.avocado_task_output_dir_{safe_id}"
202-206: Add timeout to wait_task to avoid infinite waits.Honor spawner.remote.test_timeout (or a dedicated wait timeout).
- async def wait_task(self, runtime_task): - while True: - if not RemoteSpawner.is_task_alive(runtime_task): - return - await asyncio.sleep(0.1) + async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start = asyncio.get_event_loop().time() + while True: + if not RemoteSpawner.is_task_alive(runtime_task): + return + if timeout and (asyncio.get_event_loop().time() - start) > timeout: + raise RemoteSpawnerException("Task wait timed out") + await asyncio.sleep(0.1)
208-216: Improve terminate_task logging and flow.Use LOG.exception for traceback; return in else as per TRY300.
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") return False + else: + return True
38-46: Timeout options need key_type=int to avoid string timeouts.Without key_type=int these become strings, breaking arithmetic/timeout usage.
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) ... help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-115: Harden slot initialization with error handling.Single bad file/malformed JSON/failed login currently crashes initialization.
- for session_slot in self.config.get("spawner.remote.slots"): + for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
🧹 Nitpick comments (7)
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: Handle empty test case names.TestCase.name never returns None but can be an empty string. To prevent empty
test_namevalues downstream, consider skipping or warning on unnamed tests:# Handle both string (old API) and TestCase object (new API) test_name = test_case.name if hasattr(test_case, "name") else test_case -if not test_name: - continue +# Skip or warn on empty test names +if not test_name: + continue # or log a warning for unnamed tests test_suite[data.name].append( {"test_name": test_name, "test_source": data.source} )optional_plugins/varianter_cit/setup.py (1)
22-22: Use context manager for file handling consistency.Other setup.py files in this PR (html, robot, varianter_pict) use a context manager when reading VERSION. Apply the same pattern here for consistency and proper resource management.
Apply this diff:
-VERSION = open("VERSION", "r", encoding="utf-8").read().strip() +with open("VERSION", "r", encoding="utf-8") as version_file: + VERSION = version_file.read().strip().github/workflows/setup.yml (2)
176-181: Use python3-venv (or drop apt entirely) when creating venvs.You install python3-virtualenv but call python3 -m venv. Either:
- Use the stdlib venv (recommended) and install python3-venv if needed:
- sudo apt-get install -y python3-venv
- Or use virtualenv: python3 -m virtualenv env
Example fix:
- sudo apt-get install -y python3-virtualenv + sudo apt-get install -y python3-venv
113-113: Standardize on python -m pip.Minor consistency/readability improvement; prefer python3 -m pip over bare pip3.
Also applies to: 149-149, 215-215
optional_plugins/ansible/pyproject.toml (1)
31-31: Use HTTPS for the project URL.Small polish.
-Homepage = "http://avocado-framework.github.io/" +Homepage = "https://avocado-framework.github.io/"optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (2)
81-85: Prefer get_running_loop() in async context.Minor modernization.
- loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop()
73-75: Annotate mutable class attributes as ClassVar.Silences RUF012 and clarifies intent.
+from typing import ClassVar @@ - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar[dict] = {}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)selftests/utils.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (4)
- docs/source/guides/contributor/chapters/environment.rst
- optional_plugins/varianter_pict/README.rst
- examples/plugins/cli-cmd/hello_parser/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
🚧 Files skipped from review as they are similar to previous changes (28)
- spell.ignore
- examples/plugins/job-pre-post/sleep/pyproject.toml
- examples/plugins/README.rst
- .github/actions/version/action.yml
- optional_plugins/ansible/README.rst
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/README.rst
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- examples/plugins/tests/README.rst
- optional_plugins/spawner_remote/pyproject.toml
- optional_plugins/resultsdb/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/setup.py
- optional_plugins/resultsdb/setup.py
- optional_plugins/golang/pyproject.toml
- optional_plugins/golang/setup.py
- .github/workflows/vmimage.yml
- optional_plugins/robot/pyproject.toml
- optional_plugins/result_upload/setup.py
- docs/source/guides/contributor/chapters/plugins.rst
- optional_plugins/mail/pyproject.toml
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
- optional_plugins/mail/setup.py
- .github/workflows/ci.yml
- examples/plugins/cli-cmd/hello_priority/setup.py
- examples/plugins/tests/magic/setup.py
- optional_plugins/html/pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
selftests/utils.py
29-29: Consider moving this statement to an else block
(TRY300)
30-30: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (42)
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Egg task ubuntu:24.04
- GitHub Check: Fedora selftests
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: macOS with Python 3.11
- GitHub Check: Static checks
🔇 Additional comments (32)
selftests/utils.py (1)
6-6: LGTM! Modern migration from pkg_resources to importlib.metadata.The shift from deprecated
pkg_resourcesto the standard-libraryimportlib.metadataaligns with current packaging best practices. Per setuptools v80.9.0 release notes,pkg_resourcesis scheduled for removal later in 2025, making this migration timely and necessary.Based on learnings
Also applies to: 28-28
docs/source/guides/writer/chapters/subclassing.rst (2)
28-47: LGTM: Well-structured pyproject.toml example.The example correctly demonstrates:
- Modern build-system configuration with setuptools>=61.0
- Dynamic versioning from VERSION file
- Proper dependency declaration on avocado-framework
- Standard package discovery configuration
The migration from setup.py to pyproject.toml is clearly documented.
88-101: LGTM: Installation instructions properly updated.The documentation correctly updates from
python setup.py developtopip install -e ., which aligns with modern Python packaging best practices and the deprecation of direct setup.py invocation.examples/plugins/job-pre-post/sleep/setup.py (1)
1-22: LGTM: Consistent backward-compatibility wrapper.The minimal setup.py correctly retains the configuration for backward compatibility while the header comments appropriately indicate that primary configuration has moved to pyproject.toml. The entry points and module configuration are complete.
examples/plugins/cli-cmd/hello/pyproject.toml (1)
1-14: LGTM: Complete pyproject.toml configuration for CLI plugin.The configuration properly defines:
- Modern build-system with setuptools and wheel
- Clear project metadata matching the setup.py
- Correctly namespaced entry point under
avocado.plugins.cli.cmd- Appropriate py-modules declaration
This aligns with the project's migration to pyproject.toml-based packaging.
optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-48: LGTM: Comprehensive and well-structured plugin configuration.This pyproject.toml exemplifies best practices for the migration:
- Dynamic versioning and readme from external files (DRY principle)
- Properly categorized entry points (init, cli, varianter)
- Clear dependency declarations including avocado-framework
- Appropriate Python version constraint (>=3.9)
- Complete metadata with license and classifiers
The configuration is thorough and production-ready.
examples/plugins/tests/rogue/setup.py (1)
1-24: LGTM: Proper backward-compatibility wrapper with essential configuration.The setup.py correctly:
- Adds header comments indicating configuration moved to pyproject.toml
- Removes long_description (now handled by pyproject.toml)
- Retains essential configuration: name, version, description, py_modules, and entry_points
- Maintains all necessary entry points (resolver, runner, console script)
This follows the established migration pattern across the repository.
optional_plugins/README.rst (1)
10-34: LGTM: Documentation properly updated for pip-based workflow.The documentation changes correctly:
- Replace
python setup.py developwithpip install -ecommands- Add explicit uninstall instructions using
pip uninstall- Provide concrete examples for html and ansible plugins
- Update make target names to more descriptive
develop-pluginsanddevelop-pluginThese changes align with the deprecation of direct setup.py invocation and modern Python packaging best practices.
optional_plugins/html/setup.py (1)
16-18: Clear documentation of backward compatibility approach.The comments effectively explain why setup.py is retained and how to maintain consistency with pyproject.toml.
examples/plugins/test-pre-post/hello/pyproject.toml (1)
1-17: LGTM!The packaging configuration is correct and consistent - the single-file module declaration (
py-modules) aligns with the entry point targets.examples/plugins/test-pre-post/hello/setup.py (1)
1-2: Clear backward compatibility documentation.The comments effectively communicate the purpose of this minimal setup.py file.
optional_plugins/robot/setup.py (1)
16-18: LGTM!The backward compatibility approach is well-documented and consistent with other plugins in this PR.
optional_plugins/varianter_pict/setup.py (1)
16-18: LGTM!The backward compatibility documentation is clear and aligns with the migration strategy.
optional_plugins/varianter_cit/setup.py (1)
16-18: LGTM!The backward compatibility documentation is clear and consistent with other plugins.
python-avocado.spec (3)
8-18: LGTM: Tarball naming aligns with pyproject.toml package structure.The renaming from
avocado-*.tar.gztoavocado_framework-*.tar.gzis consistent with the package name declared in pyproject.toml and follows Python package naming conventions.
102-104: LGTM: Setup extraction paths updated correctly.The
%setup -q -ndirectives now referenceavocado_framework-*instead ofavocado-*, matching the updated tarball structure.
220-220: LGTM: Selftests invocation modernized.The change from
selftests/check.pytopython3 -m selftests.checkaligns with Python best practices for module execution and is consistent with the broader PR migration strategy.optional_plugins/result_upload/pyproject.toml (1)
1-44: LGTM: Well-structured plugin configuration.The pyproject.toml configuration follows PEP 621 standards and properly declares:
- Build system requirements with setuptools>=61.0
- Package metadata with appropriate classifiers
- Entry points for both CLI and result plugins
- Dynamic version/readme loading
- Package discovery limited to avocado_result_upload*
The configuration is consistent with other optional plugins in the repository.
Makefile (6)
9-10: LGTM: New plugin development targets improve workflow.The addition of
develop-pluginsanddevelop-plugintargets provides convenient shortcuts for plugin development, aligning with the new pyproject.toml-based plugin structure.
33-61: LGTM: Enhanced clean target is thorough.The expanded clean target now explicitly handles:
- Build artifacts and cache files
- Optional plugins cleanup
- Example plugins cleanup
The explicit cleanup with error handling (
|| true) ensures robustness.
64-67: LGTM: Modernized install/uninstall to use pip.The migration from
setup.py installtopython -m pip installand fromsetup.py develop --uninstalltopip uninstallaligns with modern Python packaging best practices.
80-80: LGTM: Selftests invocation modernized.The change to
python -m selftests.checkis consistent with the repository-wide migration to module-based test execution.
91-104: LGTM: Plugin installation targets well-implemented.The new
develop-pluginsanddevelop-plugintargets:
- Use pip for editable installs
- Provide clear error messages when PLUGIN is not defined
- Support the new optional plugins structure
These targets will streamline plugin development workflows.
108-114: LGTM: Manpage generation guarded appropriately.The addition of
rst2manavailability checking prevents cryptic failures when the tool is missing. The explicit error message guides users to install the required dependency.pyproject.toml (2)
168-232: LGTM: Optional dependencies well-organized.The optional dependencies are properly structured with:
- Separate groups for each plugin (html, ansible, golang, etc.)
- A comprehensive
all_pluginsgroup for convenient installation- Development dependencies grouped separately
This organization makes it easy for users to install specific plugins as needed.
245-250: LGTM: Package data properly configured.The package data configuration ensures that non-Python assets (etc, libexec, schemas) are included in the distribution, which is essential for the framework's functionality.
.github/workflows/push_ci.yml (1)
97-97: LGTM: CI build migrated to pip-based installation.The change from
python setup.py develop --usertopython -m pip install --user -e .follows modern Python packaging best practices and aligns with the broader migration strategy..github/workflows/prerelease.yml (1)
48-49: LGTM: Installation steps modernized.The workflow now uses pip-based installation for both dependencies and the editable package install, aligning with the repository-wide migration.
.github/workflows/weekly.yml (4)
39-39: LGTM: Installation migrated to pip.The change to
python3 -m pip install --user -e .is consistent with the repository-wide migration to pip-based workflows.
47-47: LGTM: Selftests invocation modernized.The migration to
python3 -m selftests.checkfollows Python best practices for module execution.
83-83: LGTM: Consistent pip-based installation.This change mirrors the update in the first job, maintaining consistency across the workflow.
89-89: LGTM: Module-based test execution with plugin exclusions.The command properly uses module invocation while maintaining the plugin exclusion list for testing without optional plugins.
| run: python3 -m pip install --user -e . | ||
| - name: Installing plugins | ||
| run: | | ||
| python3 setup.py plugin --install=golang --user | ||
| python3 setup.py plugin --install=html --user | ||
| python3 setup.py plugin --install=result_upload --user | ||
| python3 setup.py plugin --install=resultsdb --user | ||
| python3 setup.py plugin --install=robot --user | ||
| python3 setup.py plugin --install=varianter_cit --user | ||
| python3 setup.py plugin --install=varianter_pict --user | ||
| python3 setup.py plugin --install=varianter_yaml_to_mux --user | ||
| python3 -m pip install ./optional_plugins/golang --user | ||
| python3 -m pip install ./optional_plugins/html --user | ||
| python3 -m pip install ./optional_plugins/result_upload --user | ||
| python3 -m pip install ./optional_plugins/resultsdb --user | ||
| python3 -m pip install ./optional_plugins/robot --user | ||
| python3 -m pip install ./optional_plugins/varianter_cit --user | ||
| python3 -m pip install ./optional_plugins/varianter_pict --user | ||
| python3 -m pip install ./optional_plugins/varianter_yaml_to_mux --user | ||
| - name: Avocado version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure PATH includes user base bin for --user installs.
Commands installed to ~/.local/bin may not be on PATH; avocado may not be found.
Add after Python setup (once per job using --user):
- name: Add user base bin to PATH
run: echo "$(python3 -m site --user-base)/bin" >> "$GITHUB_PATH"Also applies to: 115-116
🤖 Prompt for AI Agents
.github/workflows/setup.yml around lines 33 to 44 (and also apply same change at
lines 115-116): the workflow uses pip --user to install packages which drop
executables into the per-user bin (e.g. ~/.local/bin) that may not be on PATH;
add a job step right after the Python setup/install step to append the user base
bin to GITHUB_PATH so subsequent steps can find those installed commands (use
python3 -m site --user-base to compute the path and echo "<that>/bin" >>
"$GITHUB_PATH").
| "avocado.plugins.init": ["remote = avocado_spawner_remote:RemoteSpawnerInit"], | ||
| "avocado.plugins.spawner": ["remote = avocado_spawner_remote:RemoteSpawner"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix entry_points to point at the spawner module.
Classes live in avocado_spawner_remote/spawner.py. Update the targets to avoid runtime import errors.
- "avocado.plugins.init": ["remote = avocado_spawner_remote:RemoteSpawnerInit"],
- "avocado.plugins.spawner": ["remote = avocado_spawner_remote:RemoteSpawner"],
+ "avocado.plugins.init": ["remote = avocado_spawner_remote.spawner:RemoteSpawnerInit"],
+ "avocado.plugins.spawner": ["remote = avocado_spawner_remote.spawner:RemoteSpawner"],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "avocado.plugins.init": ["remote = avocado_spawner_remote:RemoteSpawnerInit"], | |
| "avocado.plugins.spawner": ["remote = avocado_spawner_remote:RemoteSpawner"], | |
| "avocado.plugins.init": ["remote = avocado_spawner_remote.spawner:RemoteSpawnerInit"], | |
| "avocado.plugins.spawner": ["remote = avocado_spawner_remote.spawner:RemoteSpawner"], |
🤖 Prompt for AI Agents
In optional_plugins/spawner_remote/setup.py around lines 35-36, the entry_points
currently point to avocado_spawner_remote:RemoteSpawnerInit and
avocado_spawner_remote:RemoteSpawner but the classes live in
avocado_spawner_remote/spawner.py; fix by updating the entry_points to target
the spawner module (e.g., avocado_spawner_remote.spawner:RemoteSpawnerInit and
avocado_spawner_remote.spawner:RemoteSpawner) so the installer writes correct
import paths and avoids runtime import errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
examples/plugins/job-pre-post/sleep/setup.py (1)
1-22: Trim setup.py to a minimal shim
Update examples/plugins/job-pre-post/sleep/setup.py to callsetup()without arguments—remove duplicated metadata now defined in pyproject.toml.optional_plugins/ansible/setup.py (1)
24-46: Add explicitpackagesfor egg builds
Includepackages=find_packages(include=['avocado_ansible*'])in the setup() call of optional_plugins/ansible/setup.py to ensure the avocado_ansible modules are discovered.optional_plugins/varianter_pict/setup.py (1)
28-42: Add explicit packages to setup()The setup() call in optional_plugins/varianter_pict/setup.py doesn’t auto-discover any packages; add
packages=find_packages(include=['avocado_varianter_pict*'])
to ensure the plugin modules are included in egg builds.optional_plugins/result_upload/setup.py (1)
28-42: Add packages directive to setup.py
Setuptools isn’t discovering any packages (find_packages returned empty). Inoptional_plugins/result_upload/setup.py, update thesetup()call to includepackages=find_packages(include=['avocado_result_upload*'])so your plugin code is properly packaged.
optional_plugins/resultsdb/setup.py (1)
28-49: Add namespace package discovery to setup.py
setup()omitspackages, sobdist_eggwon’t include theavocado_resultsdbcode. Sinceavocado_resultsdb/is a PEP 420 namespace (no__init__.py), add:from setuptools import find_namespace_packages … setup( …, packages=find_namespace_packages(include=['avocado_resultsdb*']), …, )Or add an
__init__.pyunderavocado_resultsdb/and switch tofind_packages.
♻️ Duplicate comments (22)
examples/plugins/test-pre-post/hello/setup.py (1)
1-16: Same inconsistency as in job-pre-post/sleep plugin.The header comments indicate configuration moved to pyproject.toml, but the
setup()call still contains full configuration. Apply the same resolution as the previous plugin.optional_plugins/resultsdb/setup.py (1)
1-1: Shebang path still needs correction.The shebang uses
/bin/envinstead of the more portable/usr/bin/env. While past review comments indicate this was addressed, the issue remains in the current code.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/result_upload/setup.py (1)
1-1: Shebang path still needs correction.The shebang uses
/bin/envinstead of/usr/bin/env. This portability issue should be fixed even though past review comments indicate it was addressed.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/ansible/setup.py (1)
1-1: Shebang path still needs correction.The shebang uses
/bin/envinstead of/usr/bin/env, affecting portability.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3optional_plugins/varianter_pict/setup.py (1)
1-1: Shebang path still needs correction.The shebang uses
/bin/envinstead of/usr/bin/env, which is less portable.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3examples/plugins/tests/magic/pyproject.toml (1)
25-25: Complete the package discovery configuration.The empty
[tool.setuptools.packages.find]section may prevent setuptools from discovering the avocado_magic package, which is referenced in the entry points.Apply this diff:
[tool.setuptools.packages.find] +include = ["avocado_magic*"]This ensures that setuptools will discover and package the avocado_magic module and any subpackages.
setup.py (3)
221-350: Entry_points duplication requires ongoing synchronization.This 130-line dict duplicates pyproject.toml configuration. While documented as necessary for egg builds (lines 24-25), any plugin changes must be updated in both locations.
Verify synchronization between setup.py and pyproject.toml:
#!/bin/bash # Compare entry point groups echo "Entry point groups in setup.py:" rg -o '^\s+"([^"]+)"\s*:\s*\[' setup.py | sed 's/.*"\([^"]*\)".*/\1/' | sort echo -e "\nEntry point groups in pyproject.toml:" rg '^\[project\.entry-points\."([^"]+)"\]' pyproject.toml | sed 's/\[project.entry-points."\([^"]*\)"\]/\1/' | sort echo -e "\nDifferences (if any):" diff <(rg -o '^\s+"([^"]+)"\s*:\s*\[' setup.py | sed 's/.*"\([^"]*\)".*/\1/' | sort) \ <(rg '^\[project\.entry-points\."([^"]+)"\]' pyproject.toml | sed 's/\[project.entry-points."\([^"]*\)"\]/\1/' | sort)
237-237: Ensure scripts package is properly configured.Line 237 references
scripts.external_runner:main. Verify that thescripts/directory has an__init__.pyand is included in the package discovery, or the console script will fail.Run this verification:
#!/bin/bash # Verify scripts module packaging if [ -f "scripts/__init__.py" ]; then echo "✓ scripts/__init__.py exists" else echo "✗ scripts/__init__.py missing - add it to make scripts a package" fi if [ -f "scripts/external_runner.py" ]; then echo "✓ scripts/external_runner.py exists" if rg -q 'def main\(' scripts/external_runner.py; then echo "✓ main() function found" else echo "✗ main() function not found" fi else echo "✗ scripts/external_runner.py missing" fi
212-212: Restrict find_packages to the avocado namespace.The current
exclude=("selftests*",)is too broad and may accidentally include packages fromoptional_plugins/*in the wheel, causing conflicts with separate plugin packages.Based on past reviews, apply this fix:
- packages=find_packages(exclude=("selftests*",)), + packages=find_packages(include=("avocado", "avocado.*")),optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
38-46: Add key_type=int to timeout settings.Lines 40 and 45 register numeric timeout options without specifying
key_type=int, so they'll be parsed as strings, breaking arithmetic operations downstream.Apply this fix:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-114: Add error handling for slot initialization.Reading JSON configuration files and creating remote sessions can fail (malformed JSON, missing files, connection errors), but no error handling is present. A single bad slot config will crash spawner initialization.
Add robust error handling:
if len(RemoteSpawner.slots_cache) == 0: for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")Based on learnings
136-146: Shell-escape task identifier in pgrep command.Line 144 interpolates
runtime_task.task.identifierdirectly into a shell command without escaping. If the identifier contains special characters (spaces, quotes, shell metacharacters), the command will break or could lead to command injection.Add shell escaping:
@staticmethod def is_task_alive(runtime_task): if runtime_task.spawner_handle is None: return False session = runtime_task.spawner_handle + safe_identifier = shlex.quote(runtime_task.task.identifier) status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" + f"pgrep -r R,S -f {safe_identifier}" ) return status == 0
182-189: Remove output redirection that discards test results.Line 182 redirects stdout to
/dev/null, discarding all test output, logs, and results. This makes debugging impossible and defeats the purpose of running tests remotely.Remove the output redirection:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Or capture to a retrievable file:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"
148-193: spawn_task blocks until task completion.Line 184 uses
run_remote_cmd_asyncwhich waits for the command to finish, making spawn_task synchronous. This defeatswait_task/is_task_aliveand prevents concurrent task execution.Launch the remote task in background and return immediately:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + # Launch in background and capture PID + remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log" + cmd = f"nohup {shlex.join(entry_point_args)} > {shlex.quote(remote_log)} 2>&1 & echo $!" timeout = self.config.get("spawner.remote.test_timeout") status, output = await RemoteSpawner.run_remote_cmd_async(session, cmd, timeout) - LOG.debug(f"Command exited with code {status}") - if status != 0: - LOG.error( - f"Error exit code {status} on {session.host}:{session.port} " - f"with output:\n{output}" - ) - return False - - return True + if status == 0: + # Store PID for later checks + runtime_task.spawner_handle_pid = output.strip() + return True + else: + LOG.error(f"Failed to launch task on {session.host}:{session.port}: {output}") + return FalseThen update
is_task_aliveto check the stored PID andwait_taskto poll until completion.
195-201: Use unique, sanitized remote output directories.Line 197 hardcodes
/tmp/.avocado_task_output_dir, causing concurrent tasks to collide and corrupt logs.Generate a per-task directory:
def create_task_output_dir(self, runtime_task): output_dir_path = self.task_output_dir(runtime_task) - output_lxc_path = "/tmp/.avocado_task_output_dir" + # Use task ID for unique remote path + task_id = getattr(runtime_task, 'id', runtime_task.task.identifier) + # Sanitize for filesystem safety + safe_id = "".join(c if c.isalnum() or c in ('-', '_') else '_' for c in task_id) + output_lxc_path = f"/tmp/.avocado_task_output_dir_{safe_id}" os.makedirs(output_dir_path, exist_ok=True) runtime_task.task.setup_output_dir(output_lxc_path)
202-206: Add timeout to wait_task loop.The infinite loop at lines 203-206 will hang forever if
is_task_alivenever returns False (due to a hung task or detection bug).Honor the configured timeout:
async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() while True: if not RemoteSpawner.is_task_alive(runtime_task): return + if asyncio.get_event_loop().time() - start_time > timeout: + LOG.error(f"Task wait timeout of {timeout}s exceeded") + raise asyncio.TimeoutError(f"Task did not complete within {timeout}s") await asyncio.sleep(0.1)
208-216: Fix logging and use logging.exception for errors.Line 215 has an f-string error (missing 'f' prefix) and doesn't log the exception traceback.
Apply this fix:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") return False + else: + return Truepyproject.toml (3)
1-16: Critical: Restore missing runtime dependencies.Lines 14-16 only list
setuptoolsas a dependency, but the core package imports third-party modules (e.g.,psutil,requests,jsonschema) that were previously ininstall_requires. Without them,pip install avocado-frameworkwill succeed but raiseImportErrorat runtime.Restore the full dependency list from the former setup.py:
dependencies = [ "setuptools", + "psutil>=5.9.5", + "requests>=2.32.3", + "jsonschema>=3.2.0", + # Add other required packages from old install_requires ]Move purely optional features to
[project.optional-dependencies].
24-31: Remove unsupported Python 3.14 classifier.Line 30 includes
"Programming Language :: Python :: 3.14", which is not yet published by PyPI. This will cause package uploads to be rejected with "Invalid classifier".Remove it now and re-add later when PyPI supports it:
"Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]
39-55: Verify scripts package is included for console scripts.Line 54 registers
avocado-external-runner = "scripts.external_runner:main", but line 239 excludesscripts*from packaging. This will cause the console script to fail at runtime.Either remove
scripts*from exclusions or move the external_runner module to an included package:[tool.setuptools.packages.find] -exclude = ["selftests*", "docs*", "examples*", "contrib*", "scripts*", "optional_plugins*"] +exclude = ["selftests*", "docs*", "examples*", "contrib*", "optional_plugins*"]Makefile.gh (1)
66-68: Add conditional check for pyproject.toml.The build-wheel target now unconditionally runs
python -m buildin all plugin directories. This will fail for any plugins that haven't been migrated to pyproject.toml yet.Add a guard similar to the build-egg target:
for PLUGIN in $(AVOCADO_OPTIONAL_PLUGINS); do\ + if test -f $$PLUGIN/pyproject.toml; then\ cd $$PLUGIN;\ $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ cd -;\ + fi;\ done.github/workflows/setup.yml (1)
33-44: Verify PATH includes user base bin for --user installs.The
--userflag installs executables to~/.local/bin(or the platform equivalent), which may not be onPATHby default in GitHub Actions runners. Theavocadocommand at line 45 could fail if the user base bin directory is not accessible.Verify that the user base bin is on PATH:
#!/bin/bash # Check if user base bin is typically on PATH in GitHub Actions Ubuntu runners python3 -c "import site; print(site.USER_BASE + '/bin')" # Expected: should print something like /home/runner/.local/bin # Check if this is typically on PATH echo $PATH | grep -q "\.local/bin" && echo "User bin is on PATH" || echo "User bin NOT on PATH"If verification shows it's not on PATH, add after the Python setup step:
- name: Add user base bin to PATH run: echo "$(python3 -m site --user-base)/bin" >> "$GITHUB_PATH"Also applies to lines 115-116.
🧹 Nitpick comments (2)
optional_plugins/varianter_cit/setup.py (1)
22-22: Add error handling for VERSION file read.If the VERSION file is missing or unreadable, setup.py will fail with an unclear error during egg builds.
Consider wrapping in a try/except block:
-VERSION = open("VERSION", "r", encoding="utf-8").read().strip() +try: + VERSION = open("VERSION", "r", encoding="utf-8").read().strip() +except FileNotFoundError: + raise FileNotFoundError("VERSION file not found. Ensure you're running from the plugin directory.")setup.py (1)
38-41: Consider adding error handling for VERSION file.If the VERSION file is missing, the error message will be unclear during egg builds.
Add basic error handling:
-with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as f: - VERSION = f.read().strip() +try: + with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as f: + VERSION = f.read().strip() +except FileNotFoundError: + raise FileNotFoundError(f"VERSION file not found at {BASE_PATH}. Run from repository root.")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (63)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/push_ci.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(6 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (2)
- examples/plugins/cli-cmd/hello_priority/setup.py
- optional_plugins/varianter_pict/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (28)
- optional_plugins/varianter_yaml_to_mux/README.rst
- examples/plugins/cli-cmd/hello_option/setup.py
- optional_plugins/result_upload/pyproject.toml
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/tests/README.rst
- examples/plugins/tests/rogue/setup.py
- .github/workflows/push_ci.yml
- docs/source/guides/contributor/chapters/environment.rst
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/ansible/pyproject.toml
- optional_plugins/varianter_pict/README.rst
- optional_plugins/resultsdb/pyproject.toml
- .github/workflows/prerelease.yml
- spell.ignore
- examples/plugins/job-pre-post/sleep/pyproject.toml
- optional_plugins/spawner_remote/setup.py
- examples/plugins/tests/magic/setup.py
- optional_plugins/html/pyproject.toml
- examples/plugins/cli-cmd/hello_priority/pyproject.toml
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/tests/rogue/pyproject.toml
- examples/plugins/cli-cmd/hello_parser/setup.py
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/README.rst
- .github/workflows/vmimage.yml
- .github/workflows/weekly.yml
- optional_plugins/html/setup.py
- optional_plugins/ansible/README.rst
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (36)
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Fedora selftests
- GitHub Check: Podman spawner with 3rd party runner plugin
- GitHub Check: Windows with Python 3.13
- GitHub Check: Version task ubuntu:24.04
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: macOS with Python 3.11
- GitHub Check: Static checks
🔇 Additional comments (55)
.github/actions/version/action.yml (1)
9-12: LGTM! Modern pip-based installation workflow.The migration from
python setup.py developtopip install -e .is appropriate and aligns with modern Python packaging best practices. ThePIP_BREAK_SYSTEM_PACKAGES=1environment variable is suitable for CI environments where you control the Python installation.optional_plugins/robot/avocado_robot/robot.py (1)
41-44: Good defensive coding for API compatibility.The change properly handles both the old string-based API and the new TestCase object API for Robot Framework tests. Using
hasattrto check for thenameattribute before accessing it is appropriate and maintains backward compatibility.optional_plugins/README.rst (1)
10-34: Excellent documentation update for modern packaging workflow.The documentation now correctly guides developers to use pip-based installation (
pip install -e) instead of the deprecatedpython setup.py developcommand. The examples are clear, include both installation and uninstallation commands, and cover both individual plugin management and bulk operations via Makefile targets.optional_plugins/golang/setup.py (2)
33-33: LGTM! Python version constraint aligns with project requirements.The
python_requires=">=3.9"constraint is appropriate given that Python 3.8 support has been dropped from the project (as noted in the PR comments). This ensures compatibility and prevents installation on unsupported Python versions.
16-18: Entry points are synchronized with pyproject.toml.All
console_scriptsand plugin entry-points insetup.pyexactly match the sections inpyproject.toml. No further action required.docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: Excellent modernization of packaging examples.The documentation now teaches users modern Python packaging practices using
pyproject.tomlwith PEP 621 metadata. The example demonstrates:
- Proper build system configuration with setuptools backend
- Dynamic version sourcing from a VERSION file
- Clear project metadata structure
- Dependency specification
This is a significant improvement that will help users avoid deprecated patterns.
88-101: Installation instructions reflect modern pip workflow.The updated installation example correctly demonstrates using
pip install -e .for editable installs instead of the deprecatedpython setup.py developcommand. The output shown is realistic and helps users understand what to expect during installation.optional_plugins/spawner_remote/pyproject.toml (1)
14-16: Bump aexpect minimum version to 1.8.0In optional_plugins/spawner_remote/pyproject.toml change
aexpect>=1.6.2toaexpect>=1.8.0to pick up Pyro5 compatibility, portability fixes, and rsync enhancements. Verify thatremote.remote_login()andrun_remote_cmd_async()continue to work as expected.docs/source/guides/contributor/chapters/plugins.rst (4)
97-102: LGTM! Documentation correctly updated for pyproject.toml workflow.The documentation accurately reflects the migration from setup.py to pyproject.toml-based packaging, including the modern pip-based installation command (
pip install -e .).
111-114: LGTM! Entry-points syntax correctly updated to TOML format.The documentation correctly demonstrates the new entry-points syntax in pyproject.toml format.
170-173: LGTM! Settings entry-points example correctly formatted.The example properly demonstrates the pyproject.toml-based settings entry-points configuration.
325-327: LGTM! Installation command properly updated.The documentation correctly instructs users to use
pip install -e .for development mode installation, which is the modern approach for pyproject.toml-based packages.examples/plugins/cli-cmd/hello_option/pyproject.toml (4)
1-3: LGTM! Build system configuration is correct.The build-system configuration properly specifies setuptools>=61.0 and wheel with the standard setuptools.build_meta backend.
5-8: LGTM! Project metadata is appropriate for an example plugin.The project metadata is correctly defined with name, version, and description suitable for this example CLI plugin.
10-11: LGTM! Entry-point correctly registered.The entry-point properly registers the hello_option CLI command under the avocado.plugins.cli.cmd namespace.
13-14: LGTM! Module packaging correctly configured.The py-modules configuration appropriately specifies the single hello_option module for packaging.
optional_plugins/resultsdb/setup.py (1)
16-18: LGTM! Clear documentation of the minimal setup.py approach.The comment helpfully explains the rationale for keeping a minimal setup.py and reminds maintainers to keep critical fields synchronized with pyproject.toml.
optional_plugins/result_upload/setup.py (1)
16-18: LGTM! Clear documentation of the minimal setup.py approach.The comment effectively explains the backward compatibility rationale and the need to keep entry_points synchronized with pyproject.toml.
examples/plugins/tests/magic/pyproject.toml (4)
1-3: LGTM! Build system configuration is correct.The build-system configuration properly specifies the required dependencies and backend.
5-8: LGTM! Project metadata is appropriate.The project metadata is correctly configured for this test plugin example.
10-11: LGTM! Console script correctly registered.The avocado-runner-magic console script is properly configured to enable command-line usage of the magic runner.
13-23: LGTM! Plugin entry-points correctly registered.All necessary plugin entry-points (init, resolver, discoverer, and runner) are properly configured for the magic test type.
optional_plugins/ansible/setup.py (1)
16-18: LGTM! Clear documentation of the minimal setup.py approach.The comment consistently explains the backward compatibility strategy across all optional plugins.
optional_plugins/varianter_pict/setup.py (1)
16-18: LGTM! Clear documentation of the minimal setup.py approach.The comment maintains consistency across all optional plugins in explaining the backward compatibility rationale.
optional_plugins/golang/pyproject.toml (5)
1-3: LGTM! Build system configuration is correct.The build-system configuration properly specifies setuptools and wheel with the standard backend.
5-25: LGTM! Comprehensive project metadata.The project metadata is well-structured with dynamic version/readme, appropriate classifiers, and consistent Python version requirements.
27-37: LGTM! Entry-points correctly configured.The project URLs and entry-points are properly defined, including the console script for the golang runner and the plugin registrations.
39-43: LGTM! Package discovery properly configured.The setuptools configuration correctly specifies package discovery with the appropriate include pattern for avocado_golang packages.
45-47: LGTM! Dynamic sources correctly configured.The dynamic version and readme sources are properly configured, with the readme content-type appropriately specified as text/x-rst.
optional_plugins/varianter_cit/setup.py (1)
16-18: LGTM!The comment clearly documents the backward compatibility purpose and explains the minimal setup.py approach for egg builds.
python-avocado.spec (4)
8-8: LGTM!The gittar macro updates correctly reflect the new
avocado_framework-naming convention for tarballs, consistent with the broader packaging modernization.Also applies to: 18-18
102-104: LGTM!The %setup directive updates correctly align with the new avocado_framework tarball naming.
220-220: LGTM!The migration from
selftests/check.pyto-m selftests.checkaligns with the module-based execution pattern adopted across the repository.
259-263: Conditional exclusion logic is correct.The nested conditionals properly scope the exclusions to non-RHEL and specific Fedora versions where certain plugins should not be included.
examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
1-14: LGTM!The pyproject.toml configuration is well-structured and follows best practices:
- Modern build system with setuptools>=61.0
- Clear project metadata
- Proper entry point registration for the CLI plugin
- Appropriate py-modules configuration
This aligns with the repository-wide migration to pyproject.toml-based packaging.
setup.py (1)
16-26: LGTM!The docstring clearly explains the backward compatibility purpose and documents the entry_points duplication issue. This helps maintainers understand the temporary nature of this setup.
pyproject.toml (2)
56-166: LGTM!The entry points are comprehensive and well-organized across all plugin namespaces. Ensure these stay synchronized with the duplicate definitions in setup.py for egg build compatibility (as noted in setup.py comments).
168-232: LGTM!The optional dependencies are well-structured, providing fine-grained plugin installation via extras and an
all_pluginsconvenience group.optional_plugins/varianter_yaml_to_mux/pyproject.toml (1)
1-48: LGTM!The pyproject.toml configuration is well-structured:
- Modern build system with setuptools>=61.0
- Complete project metadata with dynamic version/readme
- Proper dependency declaration including avocado-framework and PyYAML
- Three entry points correctly configured for init, CLI, and varianter plugins
- Package discovery properly scoped to avocado_varianter_yaml_to_mux
This aligns with the repository-wide migration to pyproject.toml-based packaging.
optional_plugins/varianter_yaml_to_mux/setup.py (1)
16-18: LGTM: Minimal setup.py configuration aligns with pyproject.toml migration.The addition of explanatory comments and
python_requires=">=3.9"appropriately supports the backward compatibility goal while primary configuration moves to pyproject.toml.Also applies to: 33-33
optional_plugins/mail/setup.py (1)
16-18: LGTM: Minimal setup.py configuration aligns with pyproject.toml migration.The addition of explanatory comments and
python_requires=">=3.9"appropriately supports the backward compatibility goal.Also applies to: 33-33
.github/workflows/setup.yml (3)
121-121: LGTM: Manpage generation migrated to make-based command.The change from
setup.pytomake manaligns with the build system modernization.Also applies to: 157-157
123-123: LGTM: Test execution migrated to module-based invocation.Using
python3 -m selftests.checkinstead ofsetup.py testaligns with modern Python packaging best practices.Also applies to: 159-159
181-194: LGTM: Virtualenv workflow migrated to pip-based installs.The virtualenv setup now uses
python3 -m venvandpip installcommands, which is the modern approach replacingsetup.pyinvocations.optional_plugins/robot/setup.py (1)
16-18: LGTM: Minimal setup.py configuration aligns with pyproject.toml migration.The addition of explanatory comments and
python_requires=">=3.9"appropriately supports the backward compatibility goal.Also applies to: 36-36
optional_plugins/mail/pyproject.toml (1)
1-48: LGTM: Standardized pyproject.toml structure for plugin packaging.The pyproject.toml follows setuptools build backend conventions with appropriate metadata, entry points, and dynamic version/readme handling. The structure aligns well with the broader migration effort.
.github/workflows/ci.yml (3)
32-32: LGTM: Test execution migrated to module-based invocation.The migration from
setup.py testtopython3 -m selftests.checkwith appropriate skip/select flags aligns with modern Python packaging practices and the broader PR objectives.Also applies to: 99-99, 143-143
89-89: LGTM: Python version display flag corrected.Using
python -VV(verbose version info) instead of the redundantpython3 -V --versionis the correct approach.Also applies to: 131-131, 167-167
93-93: LGTM: Dependency installation migrated to module-based pip.Using
python3 -m pip installensures the pip associated with the correct Python interpreter is used.optional_plugins/robot/pyproject.toml (1)
1-48: LGTM: Standardized pyproject.toml structure for Robot plugin packaging.The pyproject.toml follows setuptools build backend conventions with appropriate metadata, entry points, and dynamic version/readme handling. The structure aligns well with the broader migration effort.
Makefile (5)
9-10: LGTM: New plugin development targets enhance developer workflow.The addition of
develop-pluginsanddevelop-plugintargets with clear usage messages and implementation simplifies the development workflow for optional plugins.Also applies to: 91-105
34-61: LGTM: Comprehensive clean target covers all artifacts.The expanded clean target now properly removes build artifacts, caches, and generated files from the main project, optional plugins, and example plugins.
64-64: LGTM: Install and uninstall migrated to pip-based commands.Using
python -m pip installandpython -m pip uninstallaligns with modern Python packaging practices and the broader migration fromsetup.pyto pip-based workflows.Also applies to: 67-67
80-80: LGTM: Check target migrated to module-based test invocation.Using
python -m selftests.checkinstead of directly executing the script aligns with the migration objectives.
109-114: LGTM: Man page generation includes defensive check for rst2man.The conditional check for
rst2manavailability prevents build failures with a clear error message when the tool is missing.
| dependencies = [ | ||
| "avocado-framework", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synchronize avocado-framework version constraint with setup.py.
The setup.py comment at line 17 states "Keep install_requires and entry_points in sync with pyproject.toml for egg build compatibility." However, there's a version constraint mismatch:
setup.pyline 32: pins to exact versionf"avocado-framework=={VERSION}"pyproject.tomlline 15: no version constraint
This inconsistency can cause different dependency resolution between wheel/sdist builds (using pyproject.toml) and egg builds (using setup.py).
Apply this diff to synchronize the version constraint:
dependencies = [
- "avocado-framework",
+ "avocado-framework=={VERSION}",
]Note: You'll need to add logic to read VERSION from the VERSION file and substitute it, or use dynamic dependencies. Alternatively, use a version range that both configs can share, such as "avocado-framework" in both if exact pinning isn't required for eggs.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In optional_plugins/mail/pyproject.toml around lines 14 to 16, the pyproject
dependency for avocado-framework lacks the exact version pin present in setup.py
(setup.py pins f"avocado-framework=={VERSION}"). Update pyproject.toml to match
setup.py by either: 1) programmatically substituting the VERSION value into
pyproject's dependencies (read the VERSION file at build time and set
"avocado-framework==<VERSION>"), or 2) change setup.py to avoid hard-pinning and
use a shared range (e.g., "avocado-framework>=x.y,<x.y+1") that you place in
both files; ensure both configs use the same exact constraint so wheel/sdist and
egg builds resolve the same avocado-framework version.
| dependencies = [ | ||
| "avocado-framework", | ||
| "robotframework" | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synchronize and update robotframework version constraint.
Two issues need addressing:
-
Version constraint mismatch: The
setup.pycomment at line 17 states "Keep install_requires and entry_points in sync with pyproject.toml for egg build compatibility." However:setup.pyline 34:"robotframework>=4.1, <7.0; python_version >= '3.9'"pyproject.tomlline 16:"robotframework"(no constraint)
-
Outdated upper bound: The
<7.0constraint insetup.pyexcludes Robot Framework 7.x releases (latest is 7.3.2 as of October 2025).
Apply this diff to synchronize and update the version constraint:
dependencies = [
"avocado-framework",
- "robotframework"
+ "robotframework>=4.1,<8.0; python_version >= '3.9'"
]Also update setup.py line 34 to match:
- "robotframework>=4.1, <7.0; python_version >= '3.9'",
+ "robotframework>=4.1,<8.0; python_version >= '3.9'",This ensures both configs use the same constraint and supports the current 7.x release series.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| dependencies = [ | |
| "avocado-framework", | |
| "robotframework" | |
| ] | |
| dependencies = [ | |
| "avocado-framework", | |
| "robotframework>=4.1,<8.0; python_version >= '3.9'" | |
| ] |
🤖 Prompt for AI Agents
In optional_plugins/robot/pyproject.toml (lines 14–17) and setup.py (line 34),
the robotframework version constraints are out of sync and the upper bound
excludes the 7.x series; update both to the same constraint allowing current 7.x
releases, e.g. change the pyproject dependency entry to
"robotframework>=4.1,<8.0" (adding the same python_version marker if your
project uses environment markers in pyproject), and update setup.py line 34 to
"robotframework>=4.1, <8.0; python_version >= '3.9'" so both files match and
permit Robot Framework 7.x.
| setup( | ||
| name="avocado-framework-plugin-varianter-cit", | ||
| version=open("VERSION", "r", encoding="utf-8").read().strip(), | ||
| description="Varianter with combinatorial capabilities", | ||
| long_description=get_long_description(), | ||
| long_description_content_type="text/x-rst", | ||
| author="Avocado Developers", | ||
| author_email="avocado-devel@redhat.com", | ||
| url="http://avocado-framework.github.io/", | ||
| packages=packages, | ||
| version=VERSION, | ||
| include_package_data=True, | ||
| install_requires=[f"avocado-framework=={VERSION}"], | ||
| python_requires=">=3.9", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Verify install_requires synchronization with pyproject.toml.
Line 28 hardcodes the dependency avocado-framework=={VERSION}. Ensure this remains synchronized with the corresponding entry in optional_plugins/varianter_cit/pyproject.toml.
Run this script to compare dependencies:
🏁 Script executed:
#!/bin/bash
# Compare install_requires between setup.py and pyproject.toml dependencies
echo "Dependencies in setup.py:"
rg -A2 'install_requires' optional_plugins/varianter_cit/setup.py
echo -e "\nDependencies in pyproject.toml:"
rg -A5 '^\[project\]' optional_plugins/varianter_cit/pyproject.toml | rg -A3 'dependencies'Length of output: 305
🏁 Script executed:
#!/bin/bash
echo "Dependencies block in pyproject.toml:"
rg -n 'dependencies' optional_plugins/varianter_cit/pyproject.toml
echo -e "\nLooking for avocado-framework entry:"
rg -n 'avocado-framework' optional_plugins/varianter_cit/pyproject.tomlLength of output: 225
Pin avocado-framework in pyproject.toml to match setup.py
In optional_plugins/varianter_cit/pyproject.toml change "avocado-framework" to "avocado-framework=={VERSION}" under [project].dependencies.
🤖 Prompt for AI Agents
In optional_plugins/varianter_cit/pyproject.toml (update the
[project].dependencies entry), replace the unpinned "avocado-framework"
dependency with the pinned form "avocado-framework=={VERSION}" so it matches the
install_requires in setup.py; ensure the dependency string is quoted and present
as an element in the dependencies array exactly as
"avocado-framework=={VERSION}".
python-avocado.spec
Outdated
| %exclude %{python3_sitelib}/contrib* | ||
| %exclude %{python3_sitelib}/scripts* | ||
| %exclude %{python3_sitelib}/avocado_result_html* | ||
| %if ! 0%{?rhel} | ||
| %if ! 0%{?fedora} > 35 | ||
| %exclude %{python3_sitelib}/avocado_resultsdb* | ||
| %endif | ||
| %endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the exclusion paths match installed package structure.
Lines 243-245 add exclusions for contrib*, scripts*, and avocado_result_html*. Since these are broad globs at the %{python3_sitelib} level, confirm they match the actual installation paths.
Run this script to check what's actually installed at these paths:
🏁 Script executed:
#!/bin/bash
# Check if these patterns match actual installation locations
echo "Checking for patterns in site-packages:"
echo "1. Looking for contrib*:"
fd -t d 'contrib' --max-depth 2
echo -e "\n2. Looking for scripts*:"
fd -t d 'scripts' --max-depth 2
echo -e "\n3. Looking for avocado_result_html*:"
fd -t d 'avocado_result_html' --max-depth 3Length of output: 256
Fix avocado_result_html exclusion path
The avocado_result_html plugin lives in optional_plugins/html, so %exclude %{python3_sitelib}/avocado_result_html* won’t match. Update it to:
%exclude %{python3_sitelib}/optional_plugins/html/avocado_result_html*
🤖 Prompt for AI Agents
In python-avocado.spec around lines 243 to 250, the %exclude for the
avocado_result_html plugin points at %{python3_sitelib}/avocado_result_html* but
the plugin is installed under optional_plugins/html; update the exclusion path
to %{python3_sitelib}/optional_plugins/html/avocado_result_html* so the RPM
excludes the actual installed files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
optional_plugins/result_upload/setup.py (1)
28-41: Egg build is empty without packages; also align dependency pin with pyproject.
- setup() lacks packages, so
bdist_eggwill not include code.- pyproject uses unpinned avocado-framework, but setup.py pins it, causing inconsistent dependency resolution.
Apply:
-from setuptools import setup +from setuptools import setup, find_packages @@ setup( @@ - install_requires=[f"avocado-framework=={VERSION}"], + install_requires=["avocado-framework"], + packages=find_packages(include=["avocado_result_upload*"]),optional_plugins/resultsdb/setup.py (1)
28-49: Make egg builds include code; remove dead urllib3 marker; align dependency pin.
- Missing packages => empty egg.
urllib3<2.3.0; python_version < '3.9'is unreachable sincepython_requires=">=3.9".- Pinning avocado-framework here but not in pyproject causes divergence.
Apply:
-from setuptools import setup +from setuptools import setup, find_packages @@ - install_requires=[ - f"avocado-framework=={VERSION}", - "resultsdb-api==2.1.5", - "urllib3<2.3.0; python_version < '3.9'", - ], + install_requires=[ + "avocado-framework", + "resultsdb-api==2.1.5", + ], + packages=find_packages(include=["avocado_resultsdb*"]),
♻️ Duplicate comments (21)
optional_plugins/spawner_remote/setup.py (2)
34-37: Entry points target wrong module (ImportError at runtime).The entry points reference
avocado_spawner_remote:RemoteSpawnerInitandavocado_spawner_remote:RemoteSpawner, but the classes reside inavocado_spawner_remote.spawner. This will cause import failures when the plugin is loaded.Apply this diff to correct the module paths:
entry_points={ - "avocado.plugins.init": ["remote = avocado_spawner_remote:RemoteSpawnerInit"], - "avocado.plugins.spawner": ["remote = avocado_spawner_remote:RemoteSpawner"], + "avocado.plugins.init": ["remote = avocado_spawner_remote.spawner:RemoteSpawnerInit"], + "avocado.plugins.spawner": ["remote = avocado_spawner_remote.spawner:RemoteSpawner"], },
28-33: Egg builds will omit plugin code without packages argument.The setup() call lacks a
packagesargument, causingbdist_eggto skip the plugin modules. Add explicit package discovery.Apply this diff:
-from setuptools import setup +from setuptools import setup, find_packages BASE_PATH = os.path.dirname(__file__) with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as version_file: VERSION = version_file.read().strip() setup( name="avocado-framework-plugin-spawner-remote", version=VERSION, include_package_data=True, + packages=find_packages(include=["avocado_spawner_remote*"]), install_requires=[f"avocado-framework=={VERSION}", "aexpect>=1.6.2"], python_requires=">=3.9",optional_plugins/ansible/setup.py (1)
24-37: Add packages argument for egg build compatibility.The setup() call lacks a
packagesargument, so egg builds won't include the ansible plugin modules.Apply this diff:
-from setuptools import setup +from setuptools import setup, find_packages VERSION = open("VERSION", "r", encoding="utf-8").read().strip() setup( name="avocado-framework-plugin-ansible", version=VERSION, include_package_data=True, + packages=find_packages(include=["avocado_ansible*"]), install_requires=[ f"avocado-framework=={VERSION}", "cffi==1.17.1; python_version<'3.10'", "cffi; python_version>='3.10'", "cryptography<46.0.0; python_version<'3.10'", "pycparser", "ansible-core", "markupsafe<3.0.0", ], python_requires=">=3.9",examples/plugins/tests/magic/pyproject.toml (1)
25-25: Complete package discovery configuration.The empty
[tool.setuptools.packages.find]section won't discover theavocado_magicpackage referenced by the entry points. Specify which packages to include.Apply this diff:
[tool.setuptools.packages.find] +include = ["avocado_magic*"].github/workflows/setup.yml (1)
33-44: Ensure ~/.local/bin is on PATH for --user installs.The workflow uses
pip install --userwhich installs executables to~/.local/bin. This directory may not be onPATH, causing subsequentavocadocommands to fail.Add a step to update PATH after Python setup:
- name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Add user base bin to PATH run: echo "$(python3 -m site --user-base)/bin" >> "$GITHUB_PATH" - name: Installing Avocado run: python3 -m pip install --user -e .Apply this same fix to lines 115-116 and other jobs using
--user.optional_plugins/ansible/pyproject.toml (1)
14-19: Sync dependencies with setup.py to avoid divergent installs.The pyproject.toml dependencies are missing environment-specific version constraints and packages present in setup.py. This causes different dependency resolutions for wheel vs egg installs.
Apply this diff to match setup.py:
dependencies = [ "avocado-framework", - "cffi", + "cffi==1.17.1; python_version<'3.10'", + "cffi; python_version>='3.10'", + "cryptography<46.0.0; python_version<'3.10'", "pycparser", "ansible-core", + "markupsafe<3.0.0", ]Based on learnings
optional_plugins/result_upload/setup.py (1)
1-1: Fix non-portable shebang or drop it.Use /usr/bin/env, or remove the shebang since this file isn’t meant to be executed directly. Current shebang also triggers EXE001 if not executable.
Apply one:
-#!/bin/env python3 +#!/usr/bin/env python3Or remove:
-#!/bin/env python3optional_plugins/resultsdb/setup.py (1)
1-1: Fix non-portable shebang or remove it.Use /usr/bin/env or drop the shebang to avoid EXE001 on non-executable files.
-#!/bin/env python3 +#!/usr/bin/env python3Or:
-#!/bin/env python3setup.py (1)
212-212: find_packages() scope remains too broad despite past review.A previous review recommended restricting
find_packages()to the avocado namespace to prevent accidentally bundling optional_plugins packages. The current code still usesfind_packages(exclude=("selftests*",)), which could include unintended packages.Verify which packages are actually discovered:
#!/bin/bash # List packages that would be discovered by find_packages python3 -c " from setuptools import find_packages packages = find_packages(exclude=('selftests*',)) print('Packages found:') for pkg in sorted(packages): print(f' - {pkg}') print() print('Checking for optional_plugins packages:') for pkg in packages: if 'optional_plugins' in pkg or pkg.startswith('avocado_'): print(f' WARNING: {pkg} might be an optional plugin') "optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
136-146: Verify task identifier is properly shell-escaped.Past reviews flagged that the task identifier in line 144 should be shell-escaped to prevent command injection or breakage with special characters. This was marked as addressed in commits 60f4aa9 to 56fcda5.
Verify the current implementation properly escapes the identifier:
#!/bin/bash # Check if shlex is imported and used for shell escaping rg -n "import shlex" optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py rg -n "shlex.quote.*identifier" optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py # Check the actual pgrep command construction rg -A2 -B2 "pgrep.*identifier" optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
38-46: Add key_type=int to timeout option registrations.The timeout options (
setup_timeoutandtest_timeout) are registered with integer defaults (3600, 14400) but withoutkey_type=int. This causes values to be parsed as strings, breaking arithmetic operations downstream.Apply this diff:
help_msg = "Test timeout enforced for remote host setup hook" settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 + section=section, key="setup_timeout", help_msg=help_msg, default=3600, key_type=int ) help_msg = "Test timeout enforced for sessions (just for this spawner)" settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 + section=section, key="test_timeout", help_msg=help_msg, default=14400, key_type=int )
106-114: Add error handling for slot initialization failures.Reading JSON slot configurations can fail (malformed JSON, missing files, connection errors), but no error handling is present. A single bad slot configuration will crash the spawner.
Apply this diff:
if len(RemoteSpawner.slots_cache) == 0: for session_slot in self.config.get("spawner.remote.slots"): if not session_slot: continue - with open(session_slot, "r", encoding="utf-8") as f: - session_data = json.load(f) - session = remote.remote_login(**session_data) - RemoteSpawner.slots_cache[session] = False + try: + with open(session_slot, "r", encoding="utf-8") as f: + session_data = json.load(f) + session = remote.remote_login(**session_data) + RemoteSpawner.slots_cache[session] = False + except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: + LOG.warning(f"Failed to initialize slot from {session_slot}: {e}") + except Exception as e: + LOG.error(f"Unexpected error initializing slot from {session_slot}: {e}")
148-193: spawn_task blocks until task completion, defeating spawner semantics.The
spawn_taskmethod usesrun_remote_cmd_asyncwhich waits for command completion (line 184), making it synchronous. This defeats the purpose ofwait_task/is_task_aliveand prevents concurrent task execution.To fix:
- Launch the remote task in background (e.g.,
nohup ... >/tmp/<taskid>.log 2>&1 & echo $!)- Capture and store the PID in
runtime_task.spawner_handle- Return
Trueimmediately without waiting- Update
is_task_aliveto check the stored PID- Update
wait_taskto poll until the process exits
182-182: Output redirection to /dev/null loses all test results.Redirecting output to
/dev/nulldiscards stdout/stderr, making debugging impossible and losing test results.Remove the redirection or capture to a retrievable file:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)Or capture to a log file:
- cmd = shlex.join(entry_point_args) + " > /dev/null" + remote_log = f"/tmp/avocado-task-{task.identifier.replace('/', '_')}.log" + cmd = shlex.join(entry_point_args) + f" > {shlex.quote(remote_log)} 2>&1"
197-197: Use unique, sanitized remote output directory per task.Every task writes to the same fixed path
/tmp/.avocado_task_output_dir, causing collisions and race conditions for concurrent tasks.Generate a unique, sanitized path per task:
def create_task_output_dir(self, runtime_task): output_dir_path = self.task_output_dir(runtime_task) - output_lxc_path = "/tmp/.avocado_task_output_dir" + # Sanitize task identifier for use in path + safe_id = runtime_task.task.identifier.replace('/', '_').replace(' ', '_') + output_lxc_path = f"/tmp/.avocado_task_output_dir_{safe_id}" os.makedirs(output_dir_path, exist_ok=True) runtime_task.task.setup_output_dir(output_lxc_path)
202-206: Add timeout to wait_task to prevent infinite blocking.
wait_taskloops forever ifis_task_alivenever returnsFalse(due to a hang or detection bug).Honor
spawner.remote.test_timeoutto break out:async def wait_task(self, runtime_task): + timeout = self.config.get("spawner.remote.test_timeout") + start_time = asyncio.get_event_loop().time() while True: if not RemoteSpawner.is_task_alive(runtime_task): return + if asyncio.get_event_loop().time() - start_time > timeout: + raise asyncio.TimeoutError(f"Task did not complete within {timeout}s") await asyncio.sleep(0.1)
208-216: Fix logging and use logging.exception for proper traceback.Line 215 has an f-string formatting issue and should use
logging.exceptionto include traceback.Apply this diff:
async def terminate_task(self, runtime_task): session = runtime_task.spawner_handle session.sendcontrol("c") try: session.read_up_to_prompt() - return True except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") return False + else: + return Truepyproject.toml (4)
54-54: Verify scripts.external_runner module is packaged.The console script
avocado-external-runner = "scripts.external_runner:main"requires thescriptspackage, but line 239 excludesscripts*from packaging.Verify if scripts package is needed and properly excluded:
#!/bin/bash # Check if scripts directory exists and contains Python modules if [ -d "scripts" ]; then echo "scripts directory exists" find scripts -name "*.py" -type f | head -10 echo "" # Check if external_runner.py exists if [ -f "scripts/external_runner.py" ]; then echo "scripts/external_runner.py found" rg -n "def main" scripts/external_runner.py else echo "scripts/external_runner.py NOT found" fi else echo "scripts directory does NOT exist" fi
238-239: scripts exclusion may break avocado-external-runner entry point.*Past review noted that excluding
scripts*from packaging (line 239) will prevent thescripts.external_runnermodule from being included, breaking the console script at line 54.Either:
- Remove
scripts*from the exclude list if it's meant to be packaged- Move the external_runner functionality to a packaged module and update the entry point
14-16: Restore missing runtime dependencies to prevent ImportError.The
dependencieslist contains only"setuptools", but the core package imports third-party modules that were previously insetup.py'sinstall_requires. Past review flagged that modules likepsutil,requests, andjsonschemaare imported but not listed, causingImportErrorafter installation.Verify which modules are actually imported:
#!/bin/bash # Search for third-party imports in the avocado package echo "Checking for third-party imports..." rg -g "avocado/**/*.py" "^import (psutil|requests|jsonschema|aexpect)" --no-filename | sort -u rg -g "avocado/**/*.py" "^from (psutil|requests|jsonschema|aexpect)" --no-filename | sort -u
30-30: Remove unsupported Python 3.14 classifier.The classifier
"Programming Language :: Python :: 3.14"is not yet published by PyPI and will cause upload rejections.Apply this diff:
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ]
🧹 Nitpick comments (4)
optional_plugins/robot/avocado_robot/robot.py (1)
42-42: Consider usingisinstance()for more explicit type checking.While
hasattr(test_case, "name")works for duck typing, it could match unintended objects that happen to have anameattribute. For more robust type safety, consider checking the type explicitly or using a try/except block.Example using try/except:
-test_name = test_case.name if hasattr(test_case, "name") else test_case +try: + test_name = test_case.name +except AttributeError: + test_name = test_caseOr, if you know the expected types from Robot Framework's API:
+from robot.model import TestCase +# ... in find_tests function: -test_name = test_case.name if hasattr(test_case, "name") else test_case +test_name = test_case.name if isinstance(test_case, TestCase) else test_case.github/workflows/ci.yml (1)
27-32: Consider migrating develop install to pip for consistency.While the test invocation correctly uses
python3 -m selftests.check, line 28 still usespython3 setup.py develop --user. For consistency with the rest of the PR, consider migrating topython3 -m pip install --user -e ..Apply this diff for consistency:
- name: Installing Avocado in develop mode - run: python3 setup.py develop --user + run: python3 -m pip install --user -e ..github/workflows/weekly.yml (1)
39-39: Ensure pip user bin is on PATH in GitHub Actions.--user installs scripts to ~/.local/bin, which may not be on PATH in all runners. Make it explicit.
Apply this step after installation:
- name: Installing Avocado in develop mode run: python3 -m pip install --user -e . + - name: Ensure pip user bin on PATH + run: echo "$HOME/.local/bin" >> $GITHUB_PATHAlso applies to: 83-83
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (1)
73-74: Add ClassVar type annotations to mutable class attributes.Static analysis flags that
METHODSandslots_cacheshould be annotated withtyping.ClassVarto clarify they are class-level attributes.+from typing import ClassVar + class RemoteSpawner(Spawner, SpawnerMixin): description = "Remote (host) based spawner" - METHODS = [SpawnMethod.STANDALONE_EXECUTABLE] - slots_cache = {} + METHODS: ClassVar = [SpawnMethod.STANDALONE_EXECUTABLE] + slots_cache: ClassVar = {}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (62)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(7 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (2)
- examples/plugins/tests/magic/setup.py
- examples/plugins/cli-cmd/hello_parser/setup.py
🚧 Files skipped from review as they are similar to previous changes (30)
- examples/plugins/README.rst
- optional_plugins/varianter_pict/README.rst
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/varianter_yaml_to_mux/pyproject.toml
- examples/plugins/cli-cmd/hello_option/pyproject.toml
- examples/plugins/tests/rogue/pyproject.toml
- .github/workflows/vmimage.yml
- optional_plugins/varianter_cit/pyproject.toml
- optional_plugins/robot/pyproject.toml
- optional_plugins/golang/pyproject.toml
- examples/plugins/tests/README.rst
- optional_plugins/spawner_remote/pyproject.toml
- .github/workflows/prerelease.yml
- examples/plugins/cli-cmd/hello_parser/pyproject.toml
- examples/plugins/job-pre-post/sleep/pyproject.toml
- examples/plugins/cli-cmd/hello/setup.py
- optional_plugins/varianter_cit/setup.py
- optional_plugins/robot/setup.py
- optional_plugins/varianter_pict/setup.py
- spell.ignore
- .github/actions/version/action.yml
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/cli-cmd/hello_option/setup.py
- optional_plugins/html/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- docs/source/guides/contributor/chapters/plugins.rst
- docs/source/guides/contributor/chapters/environment.rst
- optional_plugins/ansible/README.rst
- Makefile.gh
- optional_plugins/mail/pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/robot/avocado_robot/robot.py (1)
avocado/core/test.py (1)
name(367-373)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (39)
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Fedora develop install/uninstall task
- GitHub Check: Fedora selftests
- GitHub Check: Podman spawner with 3rd party runner plugin
- GitHub Check: macOS with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (42)
optional_plugins/robot/avocado_robot/robot.py (1)
41-44: Verify that this API compatibility change is intentional for this PR.This change handles compatibility between old and new Robot Framework APIs, which seems unrelated to the PR's stated objective of migrating from setup.py to pyproject.toml. Please confirm whether:
- This change is required due to updated Robot Framework dependencies pulled in during the migration.
- This is an intentional bundled fix for a known issue.
- This should be split into a separate PR.
Understanding the relationship helps ensure changes are appropriately scoped and documented.
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-2: LGTM! Clear backward-compatibility header.The added comments clearly indicate the file's purpose and the migration to pyproject.toml, which aligns with the PR's modernization goals.
optional_plugins/varianter_yaml_to_mux/README.rst (1)
6-6: LGTM! Documentation formatting improvements.The conversion from Sphinx roles (
:mod:,:class:) to inline code literals improves readability and maintains compatibility with various documentation renderers.Also applies to: 11-11, 14-14, 632-632, 639-639, 649-649, 655-656, 786-786, 790-790, 797-798
examples/plugins/tests/rogue/setup.py (1)
1-2: LGTM! Consistent migration pattern.The header comments align with the project-wide migration strategy and clearly communicate the file's reduced role.
examples/plugins/cli-cmd/hello/pyproject.toml (1)
1-14: LGTM! Well-structured pyproject.toml.The packaging configuration follows PEP 621 standards with:
- Modern build system (setuptools>=61.0)
- Clear project metadata
- Proper entry point registration for the CLI plugin
optional_plugins/varianter_pict/pyproject.toml (1)
1-44: LGTM! Comprehensive packaging configuration.The pyproject.toml demonstrates best practices:
- Dynamic version and readme from separate files
- Complete project metadata including classifiers
- Proper dependency declaration on avocado-framework
- Well-defined entry points for CLI and varianter plugins
docs/source/guides/writer/chapters/subclassing.rst (2)
20-47: LGTM! Documentation aligns with modern packaging.The updated examples properly reflect the migration to pyproject.toml and demonstrate:
- PEP 621-compliant project configuration
- Dynamic version handling
- Proper dependency declaration
This will help users adopt the new packaging approach correctly.
88-101: LGTM! Accurate pip install examples.The updated installation output shows the modern editable install workflow using
pip install -e ., which aligns with current best practices and the PR's migration goals.optional_plugins/varianter_yaml_to_mux/setup.py (2)
16-18: LGTM! Clear migration guidance.The header comments properly document the file's purpose and remind maintainers to keep
install_requiresandentry_pointssynchronized with pyproject.toml for egg build compatibility.
33-33: LGTM! Explicit Python version requirement.Adding
python_requires=">=3.9"improves compatibility checking and aligns with the project's minimum Python version.optional_plugins/golang/setup.py (2)
16-18: LGTM!The comment clearly documents the purpose of this minimal setup.py and the synchronization requirement with pyproject.toml.
34-44: Plugin entry points match between setup.py and pyproject.toml. No inconsistencies found.optional_plugins/spawner_remote/setup.py (1)
16-18: LGTM!The comment accurately describes the purpose and synchronization requirement.
optional_plugins/ansible/setup.py (2)
16-18: LGTM!The comment is clear and consistent with other plugin setup files.
38-45: Entry points correctly defined.The entry_points configuration properly registers the ansible plugin's console scripts and runnable runner.
examples/plugins/tests/magic/pyproject.toml (1)
1-23: Configuration is well-structured.The build system, project metadata, and entry points are properly defined for the magic plugin example.
optional_plugins/mail/setup.py (2)
16-18: LGTM!The comment is consistent with the project-wide migration approach.
34-41: Entry points properly configured.The mail plugin's entry points are correctly defined for the init and job.prepost hooks.
.github/workflows/setup.yml (2)
121-123: Migration to pip and selftests.check is correct.The workflow properly uses
make manfor manpage generation andpython3 -m selftests.checkfor tests, aligning with the pyproject.toml migration.
180-194: Virtualenv installation handles PATH correctly.The virtualenv activation ensures executables are on PATH, so the pip installs and avocado commands will work correctly.
optional_plugins/ansible/pyproject.toml (2)
1-13: Build system and metadata are well-configured.The setuptools-based build system with dynamic version/readme handling is properly set up.
39-47: Package discovery and dynamic sources properly configured.The setuptools configuration correctly specifies package inclusion and dynamic version/readme sources.
.github/workflows/ci.yml (3)
93-99: Test migration to selftests.check is correct.The workflow properly migrates from setup.py-based test invocation to
python3 -m selftests.check, aligning with the PR's modernization goals.
167-171: Windows installation properly migrated to pip.The workflow correctly uses
python -m pip install --user -e .for Windows, ensuring cross-platform consistency.
265-359: Distribution-specific Python dependencies properly updated.The workflow ensures pip is installed for each distribution, supporting the migration to pip-based installation across all tested platforms.
.github/workflows/weekly.yml (2)
47-47: LGTM: switch to module-based selftests.
python3 -m selftests.checkis the right direction and matches the project migration.
89-89: LGTM: module-based selftests with plugin disables; please verify plugin IDs.The invocation is fine. Double-check the disabled plugin IDs remained unchanged after the migration.
python-avocado.spec (2)
108-111: LGTM: force setuptools distutils on RHEL 9.This is a pragmatic compatibility tweak for entry-point generation in the RPM buildroot.
Also applies to: 154-157
228-228: LGTM: migrate to module-based selftests.
%{python3} -m selftests.checkaligns with the new invocation.optional_plugins/resultsdb/pyproject.toml (1)
5-17: LGTM: modern packaging and entry points look consistent.Also applies to: 31-39, 43-48
setup.py (3)
16-26: LGTM: Clear documentation of the minimal setup.py purpose.The module docstring clearly explains that this file is retained for backward compatibility with egg builds and tools that still expect setup.py, with configuration moved to pyproject.toml.
221-350: Entry points duplication is acknowledged and intentional.The large entry_points dictionary duplicates configuration from pyproject.toml for egg build compatibility, as documented in lines 24-25. While this creates maintenance burden, it's an intentional trade-off for backward compatibility.
31-31: Update clean import for Python 3.12+
distutils.command.cleanis removed in Python 3.12; replace withfrom setuptools.command.clean import clean(or confirm a setuptools-provided shim exists) to maintain compatibility.Makefile (5)
9-10: LGTM: Clear help text for new plugin targets.The new
develop-pluginsanddevelop-plugintargets are well-documented in the help text.
33-61: Comprehensive clean target implementation.The expanded clean target now handles:
- Build artifacts (build/, dist/, *.egg-info)
- Cache files (pycache, *.pyc)
- Documentation artifacts
- Optional plugins and example plugins
The error handling with
|| trueprevents failures from interrupting the clean process.
91-104: LGTM: New plugin development targets with proper guards.The new
develop-pluginsanddevelop-plugintargets:
- Use pip editable installs (
pip install -e)- Include proper error handling for missing PLUGIN variable
- Iterate through optional plugins correctly
These align with the shift to pip-based workflows.
109-114: Enhanced man page generation with rst2man availability check.The man page target now checks for
rst2manavailability before attempting to generate the man page, providing a clear error message if the tool is missing. This prevents cryptic failures in environments without rst2man.
64-64: Confirm file layout under DESTDIR with pip install
Run an actual install into a temporary DESTDIR and list installed files:TMPDIR=$(mktemp -d) python3 -m pip install . --root "$TMPDIR" --prefix=/usr --no-deps find "$TMPDIR" -type f | sed 's|^$TMPDIR||' | sort rm -rf "$TMPDIR"Verify this matches the layout from
setup.py install --root.optional_plugins/README.rst (2)
10-24: LGTM: Clear pip-based installation documentation.The updated documentation clearly shows:
- How to install plugins using
pip install -e optional_plugins/<plugin-name>- How to uninstall using
pip uninstall <plugin-package-name>- Explicit examples with actual plugin names (html, ansible)
This aligns with the broader migration to pyproject.toml-based packaging.
30-34: Updated make targets reflect new workflows.The documentation correctly shows:
make develop-pluginsto enable all optional pluginsmake develop-plugin PLUGIN=htmlto enable a specific pluginThese match the new Makefile targets.
optional_plugins/html/pyproject.toml (1)
1-47: LGTM: Complete pyproject.toml configuration for HTML plugin.The configuration includes:
- Proper build system setup (setuptools>=61.0, wheel)
- Complete project metadata (name, description, authors, license)
- Python version requirement (>=3.9)
- Dependencies correctly specified (avocado-framework, jinja2)
- Comprehensive classifiers
- Entry points properly configured for three plugin interfaces:
avocado.plugins.cli(HTML)avocado.plugins.init(HTMLInit)avocado.plugins.result(HTMLResult)- Dynamic version and readme loading from files
This aligns with the project-wide migration to pyproject.toml-based packaging.
pyproject.toml (1)
1-250: Comprehensive pyproject.toml configuration for project-wide migration.This file establishes the foundation for the project-wide migration from setup.py to pyproject.toml-based packaging, including:
- Complete build system configuration
- Extensive entry points for console scripts and plugin interfaces
- Optional dependencies grouped by feature
- Package discovery and data inclusion
This aligns with the broader PR goal of modernizing the project's packaging approach.
optional_plugins/mail/setup.py
Outdated
| setup( | ||
| name="avocado-framework-plugin-result-mail", | ||
| version=VERSION, | ||
| description="Avocado Mail Notification for Jobs", | ||
| long_description=get_long_description(), | ||
| long_description_content_type="text/x-rst", | ||
| author="Avocado Developers", | ||
| author_email="avocado-devel@redhat.com", | ||
| url="http://avocado-framework.github.io/", | ||
| packages=find_packages(), | ||
| include_package_data=True, | ||
| install_requires=[f"avocado-framework=={VERSION}"], | ||
| python_requires=">=3.9", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add packages argument for egg builds.
Without a packages argument, egg builds won't include the mail plugin modules.
Apply this diff:
-from setuptools import setup
+from setuptools import setup, find_packages
BASE_PATH = os.path.dirname(__file__)
with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as version_file:
VERSION = version_file.read().strip()
setup(
name="avocado-framework-plugin-result-mail",
version=VERSION,
include_package_data=True,
+ packages=find_packages(include=["avocado_result_mail*"]),
install_requires=[f"avocado-framework=={VERSION}"],
python_requires=">=3.9",🤖 Prompt for AI Agents
In optional_plugins/mail/setup.py around lines 28 to 33, the setup() call lacks
a packages argument which prevents egg builds from including the mail plugin
modules; add a packages argument (e.g. packages=find_packages()) to the setup()
call and ensure you import find_packages from setuptools at the top of the file
(or explicitly list the package names) so the plugin modules are included in
built eggs while keeping include_package_data=True and the existing metadata.
| # data.tests is a list | ||
| for test_case in data.tests: # pylint: disable=E1133 | ||
| # Handle both string (old API) and TestCase object (new API) | ||
| test_name = test_case.name if hasattr(test_case, "name") else test_case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate that test_name is not None or empty.
After extracting test_name, there's no check to ensure it's a valid, non-empty value. If test_case.name returns None or an empty string, it will be used directly, potentially causing downstream issues or confusing test identification.
Consider adding validation:
# Handle both string (old API) and TestCase object (new API)
test_name = test_case.name if hasattr(test_case, "name") else test_case
+if not test_name:
+ raise ValueError(f"Invalid test name for test case: {test_case}")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| test_name = test_case.name if hasattr(test_case, "name") else test_case | |
| # Handle both string (old API) and TestCase object (new API) | |
| test_name = test_case.name if hasattr(test_case, "name") else test_case | |
| if not test_name: | |
| raise ValueError(f"Invalid test name for test case: {test_case}") |
🤖 Prompt for AI Agents
In optional_plugins/robot/avocado_robot/robot.py around line 42, test_name is
assigned from test_case.name or test_case but there is no validation that it is
non-empty; add a guard after the assignment to verify test_name is not None and
not an empty string (trim whitespace), and if invalid either raise a clear
ValueError or substitute a fallback identifier (e.g., "unknown_test" or derived
repr(test_case)) and log a warning so downstream code always receives a usable
test name.
python-avocado.spec
Outdated
| %global gittar avocado_framework-%{version}.tar.gz | ||
| %else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Tarball name/directory likely incorrect; build will fail to fetch/extract.
GitHub archives are typically named and unpack to “avocado-…”. Switching to “avocado_framework-…” for both the tarball and %setup -n will likely 404 on Source0 and fail %setup.
Either revert to avocado-… or prove that releases publish avocado_framework-… artifacts and dirs. Suggested fix:
- %global gittar avocado_framework-%{version}.tar.gz
+ %global gittar avocado-%{version}.tar.gz
@@
- %global gittar avocado_framework-%{shortcommit}.tar.gz
+ %global gittar avocado-%{shortcommit}.tar.gz
@@
-%setup -q -n avocado_framework-%{version}
+%setup -q -n avocado-%{version}
@@
-%setup -q -n avocado_framework-%{commit}
+%setup -q -n avocado-%{commit}Also applies to: 18-19, 102-105
🏁 Script executed:
#!/bin/bash
# Verify which archive names exist for v112.0
set -euo pipefail
for name in avocado_framework-112.0.tar.gz avocado-112.0.tar.gz; do
url="https://github.com/avocado-framework/avocado/archive/refs/tags/112.0.tar.gz"
# The downloaded filename differs; check the extracted top-level dir
curl -sL "$url" | tar -tz | head -1 | sed 's|/.*||' | uniq
done
echo "If top-level dir is 'avocado-112.0', %setup -n must match it."Length of output: 13
Tarball name/directory mismatch – build will fail
GitHub archives extract into “avocado-”, so using “avocado_framework-…” for Source0 and %setup will fetch a non-existent file and unpack into the wrong directory. Revert to:
- %global gittar avocado_framework-%{version}.tar.gz
+ %global gittar avocado-%{version}.tar.gz
@@
- %global gittar avocado_framework-%{shortcommit}.tar.gz
+ %global gittar avocado-%{shortcommit}.tar.gz
@@
-%setup -q -n avocado_framework-%{version}
+%setup -q -n avocado-%{version}
@@
-%setup -q -n avocado_framework-%{commit}
+%setup -q -n avocado-%{commit}Apply these changes at lines 8–9, 18–19 and 102–105.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| %global gittar avocado_framework-%{version}.tar.gz | |
| %else | |
| %global gittar avocado-%{version}.tar.gz | |
| %else |
🤖 Prompt for AI Agents
In python-avocado.spec around lines 8–9, 18–19 and 102–105, the tarball name and
unpack directory are wrong (using avocado_framework-... but GitHub archives
extract as avocado-<version>), so change the %global gittar/Source0 entries back
to avocado-%{version}.tar.gz and update any %setup or %autosetup invocation(s)
to reference the unpacked directory name (avocado-%{version}) so the build will
find and unpack the correct files; apply these replacements at the specified
line ranges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
optional_plugins/result_upload/setup.py (1)
1-1: Fix the shebang for portability.The shebang uses
/bin/envwhich is not portable across all systems and the past review comment indicating this was addressed appears incorrect. Use/usr/bin/envinstead.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3Additionally, either make the file executable or remove the shebang entirely:
chmod +x optional_plugins/result_upload/setup.pyoptional_plugins/spawner_remote/setup.py (2)
1-1: Fix the shebang for portability.The shebang uses
/bin/envwhich is not portable. Use/usr/bin/envinstead, or remove the shebang if the file is not meant to be executed directly.Apply this diff:
-#!/bin/env python3 +#!/usr/bin/env python3Alternatively, remove the shebang or make the file executable:
chmod +x optional_plugins/spawner_remote/setup.py
34-37: Critical: Entry points missing.spawnermodule component.The entry points in
setup.pypoint toavocado_spawner_remote:Classbut should point toavocado_spawner_remote.spawner:Classto match the actual module structure. This mismatch withpyproject.toml(which correctly uses.spawner) will cause import errors for egg-based installs.Apply this diff:
entry_points={ - "avocado.plugins.init": ["remote = avocado_spawner_remote:RemoteSpawnerInit"], - "avocado.plugins.spawner": ["remote = avocado_spawner_remote:RemoteSpawner"], + "avocado.plugins.init": ["remote = avocado_spawner_remote.spawner:RemoteSpawnerInit"], + "avocado.plugins.spawner": ["remote = avocado_spawner_remote.spawner:RemoteSpawner"], },
♻️ Duplicate comments (18)
Makefile.gh (1)
66-68: Add guard for pyproject.toml existence.The
build-wheeltarget unconditionally runspython -m buildin all plugin directories, which will fail for plugins missingpyproject.toml. Thebuild-eggtarget (lines 78-83) includes a conditional check forsetup.pythat should be mirrored here.Apply this diff to add the guard:
for PLUGIN in $(AVOCADO_OPTIONAL_PLUGINS); do\ + if test -f $$PLUGIN/pyproject.toml; then\ cd $$PLUGIN;\ $(PYTHON) -m build -o ../../PYPI_UPLOAD;\ cd -;\ + fi;\ doneexamples/plugins/cli-cmd/hello_priority/pyproject.toml (1)
10-11: Critical: Entry-point name collision persists.The entry-point name
hellocollides withexamples/plugins/cli-cmd/hello/pyproject.toml. Both plugins register the same key under[project.entry-points."avocado.plugins.cli.cmd"], causing plugin loading conflicts at runtime.Apply this diff to resolve the collision:
[project.entry-points."avocado.plugins.cli.cmd"] -hello = "hello_priority:HelloWorld" +hello_priority = "hello_priority:HelloWorld"optional_plugins/mail/pyproject.toml (1)
14-16: Version pinning inconsistency already flagged.The unpinned
"avocado-framework"dependency was already identified in past review comments as inconsistent with the setup.py pinning.optional_plugins/robot/pyproject.toml (1)
15-17: Bound robotframework dependency and keep in sync with setup.pyUnpinned dependency risks breakage. Recommend supporting RF 7.x.
dependencies = [ "avocado-framework", - "robotframework" + "robotframework>=4.1,<8.0" ]Verify parity with setup.py:
#!/bin/bash set -euo pipefail if [ -f optional_plugins/robot/setup.py ]; then rg -nP 'install_requires\s*=\s*\[(?s).*?\]' optional_plugins/robot/setup.py -U -n || true else echo "optional_plugins/robot/setup.py not found" fioptional_plugins/mail/setup.py (1)
28-34: Egg builds will miss plugin modules without packages=find_packages(...)setup() lacks packages, so bdist_egg won’t include avocado_result_mail. Import find_packages and include the package.
Apply:
-from setuptools import setup +from setuptools import setup, find_packages @@ setup( name="avocado-framework-plugin-result-mail", version=VERSION, include_package_data=True, + packages=find_packages(include=["avocado_result_mail*"]), install_requires=[f"avocado-framework=={VERSION}"], python_requires=">=3.9",python-avocado.spec (1)
102-105: Fix %setup -n dir name to match extracted archiveEnsure the directory matches the GitHub archive top-level.
-%setup -q -n avocado_framework-%{version} +%setup -q -n avocado-%{version} @@ -%setup -q -n avocado_framework-%{commit} +%setup -q -n avocado-%{commit}optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (8)
208-216: Improve termination loggingThe exception path logs a literal
{session.host}string and drops the traceback. UseLOG.exception(or format the f-string withexc_info=True) so the host and stack trace are recorded.- except exceptions.ExpectTimeoutError: - LOG.error("Failed to terminate task on {session.host}") - return False + except exceptions.ExpectTimeoutError: + LOG.exception(f"Failed to terminate task on {session.host}:{session.port}") + return False
38-46: Ensure timeout settings are parsed as integersLine 40 and Line 45 register numeric options without
key_type=int, so the config returns strings. Those strings flow intorun_remote_cmd_async()timeouts and break arithmetic/comparisons. Please declare them as integers.- settings.register_option( - section=section, key="setup_timeout", help_msg=help_msg, default=3600 - ) + settings.register_option( + section=section, + key="setup_timeout", + help_msg=help_msg, + default=3600, + key_type=int, + ) ... - settings.register_option( - section=section, key="test_timeout", help_msg=help_msg, default=14400 - ) + settings.register_option( + section=section, + key="test_timeout", + help_msg=help_msg, + default=14400, + key_type=int, + )
106-115: Harden slot initialization against missing/invalid JSONLine 112 opens each slot file without protection. A missing file, malformed JSON, or failed login will raise and abort the spawner. Please wrap this block with targeted exception handling, log the failure, and continue loading the remaining slots.
136-145: Escape task identifiers in remote commandsLine 144 interpolates
runtime_task.task.identifierdirectly into the shell command. Identifiers containing spaces or shell metacharacters break the command, and crafted values open command-injection risks. Quote the identifier before composing thepgrepcommand.- status, _ = session.cmd_status_output( - f"pgrep -r R,S -f {runtime_task.task.identifier}" - ) + safe_identifier = shlex.quote(runtime_task.task.identifier) + status, _ = session.cmd_status_output(f"pgrep -r R,S -f {safe_identifier}")
148-193: Spawn tasks asynchronously instead of blocking until completion
run_remote_cmd_async()on Line 184 waits for the command to finish, sospawn_task()only returns after the remote job is done. That defeats the spawner contract (no parallelism,wait_task/terminate_tasknever see a running process). Please launch the remote command in the background (capture PID/handle), store it onruntime_task, and return immediately so later lifecycle calls can manage the running task.
182-190: Preserve remote stdout/stderrLine 182 appends
> /dev/null, discarding every bit of task output and making failures impossible to debug. Drop the redirection (or redirect to a per-task log you can fetch later).- cmd = shlex.join(entry_point_args) + " > /dev/null" + cmd = shlex.join(entry_point_args)
195-201: Avoid a shared/tmp/.avocado_task_output_dirLine 197 reuses a fixed path for all tasks. Concurrent runs collide, overwrite artifacts, and trigger the Ruff S108 warning. Derive a sanitized, per-task path (e.g. include the identifier or a UUID) and ensure the remote directory exists before use.
202-206: Honor a timeout while waiting for tasks
wait_task()loops forever ifis_task_alive()never flips (hung process or detection bug). Please enforce the configuredspawner.remote.test_timeout(or a dedicated wait timeout): track elapsed time, break once exceeded, and surface a timeout error to callers.pyproject.toml (3)
14-16: Restore runtime dependenciesLine 15 now lists only
"setuptools", but the core package still imports modules such aspsutil,requests,jsonschema, etc. Without declaring them,pip install avocado-frameworksucceeds and the code crashes withImportError. Please port the full install requirements from the previoussetup.pyinto this dependency list (use optional groups for extras).
30-30: Remove unsupported Python 3.14 classifierPyPI currently rejects uploads containing
Programming Language :: Python :: 3.14. Drop this classifier until PyPI publishes it.
238-239: Package thescriptsmodule for registered console scriptsLine 239 excludes
scripts*, yet[project.scripts]exposesavocado-external-runner = "scripts.external_runner:main". The wheel/sdist will miss that module, so the entry point fails at runtime. Removescripts*from the exclusion list (or relocate the module inside an included package)..github/workflows/prerelease.yml (1)
51-51: Critical typo remains unfixed.The module name
selftets.checkshould beselftests.check. This typo will cause the workflow to fail with aModuleNotFoundError.Apply this diff:
- run: python3 -m selftets.check --select=pre-release,vmimage + run: python3 -m selftests.check --select=pre-release,vmimage
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (63)
.github/actions/version/action.yml(1 hunks).github/workflows/ci.yml(13 hunks).github/workflows/prerelease.yml(1 hunks).github/workflows/setup.yml(6 hunks).github/workflows/vmimage.yml(1 hunks).github/workflows/weekly.yml(2 hunks)Makefile(5 hunks)Makefile.gh(1 hunks)docs/source/guides/contributor/chapters/environment.rst(1 hunks)docs/source/guides/contributor/chapters/plugins.rst(4 hunks)docs/source/guides/writer/chapters/subclassing.rst(2 hunks)examples/plugins/README.rst(1 hunks)examples/plugins/cli-cmd/hello/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello/setup.py(1 hunks)examples/plugins/cli-cmd/hello_option/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_option/setup.py(1 hunks)examples/plugins/cli-cmd/hello_parser/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_parser/setup.py(1 hunks)examples/plugins/cli-cmd/hello_priority/pyproject.toml(1 hunks)examples/plugins/cli-cmd/hello_priority/setup.py(1 hunks)examples/plugins/job-pre-post/sleep/pyproject.toml(1 hunks)examples/plugins/job-pre-post/sleep/setup.py(1 hunks)examples/plugins/test-pre-post/hello/pyproject.toml(1 hunks)examples/plugins/test-pre-post/hello/setup.py(1 hunks)examples/plugins/tests/README.rst(1 hunks)examples/plugins/tests/magic/pyproject.toml(1 hunks)examples/plugins/tests/magic/setup.py(1 hunks)examples/plugins/tests/rogue/pyproject.toml(1 hunks)examples/plugins/tests/rogue/setup.py(1 hunks)optional_plugins/README.rst(1 hunks)optional_plugins/ansible/README.rst(1 hunks)optional_plugins/ansible/pyproject.toml(1 hunks)optional_plugins/ansible/setup.py(2 hunks)optional_plugins/golang/pyproject.toml(1 hunks)optional_plugins/golang/setup.py(1 hunks)optional_plugins/html/pyproject.toml(1 hunks)optional_plugins/html/setup.py(1 hunks)optional_plugins/mail/pyproject.toml(1 hunks)optional_plugins/mail/setup.py(1 hunks)optional_plugins/result_upload/pyproject.toml(1 hunks)optional_plugins/result_upload/setup.py(1 hunks)optional_plugins/resultsdb/pyproject.toml(1 hunks)optional_plugins/resultsdb/setup.py(1 hunks)optional_plugins/robot/avocado_robot/robot.py(1 hunks)optional_plugins/robot/pyproject.toml(1 hunks)optional_plugins/robot/setup.py(1 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/__init__.py(0 hunks)optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py(1 hunks)optional_plugins/spawner_remote/pyproject.toml(1 hunks)optional_plugins/spawner_remote/setup.py(1 hunks)optional_plugins/varianter_cit/pyproject.toml(1 hunks)optional_plugins/varianter_cit/setup.py(1 hunks)optional_plugins/varianter_pict/README.rst(1 hunks)optional_plugins/varianter_pict/pyproject.toml(1 hunks)optional_plugins/varianter_pict/setup.py(1 hunks)optional_plugins/varianter_yaml_to_mux/README.rst(4 hunks)optional_plugins/varianter_yaml_to_mux/pyproject.toml(1 hunks)optional_plugins/varianter_yaml_to_mux/setup.py(1 hunks)pyproject.toml(1 hunks)python-avocado.spec(4 hunks)selftests/unit/runner_package.py(2 hunks)setup.py(3 hunks)spell.ignore(1 hunks)
💤 Files with no reviewable changes (1)
- optional_plugins/spawner_remote/avocado_spawner_remote/init.py
✅ Files skipped from review due to trivial changes (5)
- examples/plugins/cli-cmd/hello/pyproject.toml
- examples/plugins/cli-cmd/hello/setup.py
- examples/plugins/job-pre-post/sleep/setup.py
- examples/plugins/test-pre-post/hello/setup.py
- examples/plugins/tests/magic/setup.py
🚧 Files skipped from review as they are similar to previous changes (24)
- examples/plugins/job-pre-post/sleep/pyproject.toml
- .github/workflows/weekly.yml
- examples/plugins/tests/README.rst
- examples/plugins/README.rst
- docs/source/guides/writer/chapters/subclassing.rst
- optional_plugins/README.rst
- examples/plugins/cli-cmd/hello_option/setup.py
- optional_plugins/varianter_yaml_to_mux/README.rst
- examples/plugins/cli-cmd/hello_parser/setup.py
- optional_plugins/result_upload/pyproject.toml
- optional_plugins/ansible/README.rst
- examples/plugins/test-pre-post/hello/pyproject.toml
- optional_plugins/varianter_pict/README.rst
- optional_plugins/varianter_pict/pyproject.toml
- optional_plugins/varianter_cit/pyproject.toml
- examples/plugins/tests/magic/pyproject.toml
- .github/workflows/setup.yml
- .github/actions/version/action.yml
- examples/plugins/tests/rogue/pyproject.toml
- optional_plugins/robot/avocado_robot/robot.py
- optional_plugins/golang/setup.py
- .github/workflows/vmimage.yml
- spell.ignore
- optional_plugins/robot/setup.py
🧰 Additional context used
🧬 Code graph analysis (2)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py (5)
avocado/core/plugin_interfaces.py (2)
Init(23-28)Spawner(321-441)avocado/core/spawners/common.py (3)
SpawnerMixin(35-47)SpawnMethod(6-18)task_output_dir(46-47)avocado/core/settings.py (3)
section(137-138)register_option(642-799)key(141-142)avocado/core/nrunner/runnable.py (1)
pick_runner_module_from_entry_point_kind(630-643)avocado/core/nrunner/task.py (1)
setup_output_dir(171-174)
selftests/unit/runner_package.py (2)
avocado/utils/software_manager/manager.py (1)
is_capable(48-54)avocado/plugins/runners/package.py (2)
PackageRunner(12-156)_run_software_manager(87-109)
🪛 checkmake (0.2.2)
Makefile
[warning] 124-124: Missing required phony target "all"
(minphony)
[warning] 124-124: Missing required phony target "test"
(minphony)
🪛 Ruff (0.14.0)
optional_plugins/spawner_remote/avocado_spawner_remote/spawner.py
73-73: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
74-74: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
126-129: Avoid specifying long messages outside the exception class
(TRY003)
197-197: Probable insecure usage of temporary file or directory: "/tmp/.avocado_task_output_dir"
(S108)
213-213: Consider moving this statement to an else block
(TRY300)
215-215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
219-219: Unused static method argument: runtime_task
(ARG004)
224-224: Unused static method argument: runtime_task
(ARG004)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (47)
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:centos-stream-9-x86_64
- GitHub Check: rpm-build:fedora-43-x86_64
- GitHub Check: rpm-build:fedora-rawhide-x86_64
- GitHub Check: rpm-build:fedora-41-s390x
- GitHub Check: rpm-build:fedora-41-x86_64
- GitHub Check: rpm-build:fedora-42-x86_64
- GitHub Check: rpm-build:epel-9-x86_64
- GitHub Check: rpm-build:fedora-41-ppc64le
- GitHub Check: rpm-build:fedora-41-aarch64
- GitHub Check: Egg task ubi:9.2
- GitHub Check: Version task ubuntu:22.04
- GitHub Check: Podman spawner with 3rd party runner plugin
- GitHub Check: Podman Egg task
- GitHub Check: Fedora selftests
- GitHub Check: macOS with Python 3.11
- GitHub Check: Windows with Python 3.13
- GitHub Check: Windows with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.11
- GitHub Check: Smokecheck on Linux with Python 3.10
- GitHub Check: Static checks
- GitHub Check: Code Coverage (3.11)
🔇 Additional comments (33)
examples/plugins/cli-cmd/hello_priority/setup.py (1)
1-15: LGTM!The backward compatibility shim correctly retains all necessary metadata for egg builds while documenting the migration to pyproject.toml.
examples/plugins/tests/rogue/setup.py (1)
1-24: LGTM!The backward compatibility shim follows the same pattern and correctly preserves all entry points and metadata for egg builds.
examples/plugins/cli-cmd/hello_option/pyproject.toml (1)
1-14: LGTM!The pyproject.toml configuration is well-structured with correct build system requirements, project metadata, and a unique entry point name that avoids collisions.
optional_plugins/spawner_remote/pyproject.toml (1)
1-45: LGTM!The pyproject.toml configuration is correct with proper entry points referencing the
.spawnermodule, appropriate build system requirements, and dependency specifications includingaexpect>=1.6.2.optional_plugins/result_upload/setup.py (1)
16-42: LGTM – entry points in setup.py and pyproject.toml are synchronized.optional_plugins/varianter_pict/setup.py (1)
16-18: LGTM! Minimal setup.py configuration looks good.The migration correctly preserves backward compatibility by keeping essential fields (name, version, install_requires, entry_points) in setup.py while moving metadata to pyproject.toml. The added
python_requires=">=3.9"aligns with the project dropping Python 3.8 support.Also applies to: 33-33
optional_plugins/html/setup.py (1)
16-18: LGTM! Backward compatibility setup maintained correctly.The minimal setup.py approach with
python_requires=">=3.9"is consistent with the migration pattern and project requirements.Also applies to: 37-37
optional_plugins/varianter_cit/setup.py (1)
29-29: LGTM on python_requires addition.The
python_requires=">=3.9"constraint correctly reflects the project's dropped Python 3.8 support.optional_plugins/ansible/setup.py (1)
16-18: LGTM! Backward compatibility setup maintained.The minimal setup.py with
python_requires=">=3.9"and conditional dependencies for different Python versions is appropriate for the migration.Also applies to: 37-37
selftests/unit/runner_package.py (2)
57-71: Mocking approach is correct for unit tests.The refactored tests properly mock
SoftwareManagerand directly test the_run_software_managerlogic with controlled inputs/outputs. The test coverage for install, already-installed, and failed-install scenarios is comprehensive.Also applies to: 73-86, 88-102
50-55: Integration tests already cover the fullrunner.run()flow.
The functional tests inselftests/functional/runner_package.pyinvoke the package runner CLI, exercise process spawning and queue communication, and assert the “started”→“finished” status sequence, timing fields, and error handling.python-avocado.spec (1)
220-220: LGTM: use python -m for selftestsSwitch to “%{python3} -m selftests.check …” is correct and more robust.
examples/plugins/cli-cmd/hello_parser/pyproject.toml (1)
5-14: LGTM: minimal example plugin packaging looks correctName/version/entry-point and py-modules are consistent.
optional_plugins/resultsdb/pyproject.toml (1)
5-48: LGTM: resultsdb plugin pyproject is consistentBuild-system, metadata, deps, and entry points look good.
docs/source/guides/contributor/chapters/plugins.rst (4)
97-101: LGTM! Documentation correctly reflects modern packaging practices.The updates accurately document the migration from
setup.pytopyproject.tomland the use ofpip install -e .for editable installs, which aligns with PEP 517/621 standards.
111-114: LGTM! Entry points format correctly updated.The documentation now correctly shows the TOML-based entry points syntax (
[project.entry-points."avocado.plugins.job.prepost"]) which is the standard for pyproject.toml files.
170-173: LGTM! Settings plugin registration correctly documented.The documentation correctly shows how to register settings plugins using the TOML format in
pyproject.toml, maintaining consistency with the overall migration approach.
325-327: LGTM! Magic plugin example correctly updated.The documentation properly references
pyproject.tomland usespip install -e .for installation, providing developers with accurate guidance for plugin development.optional_plugins/varianter_yaml_to_mux/setup.py (2)
28-46: LGTM! Minimal setup.py correctly configured for backward compatibility.The simplified
setup.py:
- Correctly adds
python_requires=">=3.9"(Python 3.8 was dropped per PR comments)- Retains essential
install_requiresandentry_pointsfor egg build compatibility- Appropriately removes metadata fields now handled by
pyproject.toml
16-18: setup.py comments accurately reflect pyproject.tomlpyproject.toml defines matching entry-points and dependencies for this plugin.
.github/workflows/prerelease.yml (1)
48-49: LGTM! Installation commands modernized appropriately.The changes correctly:
- Use
python3 -m pipto ensure the correct pip is invoked- Replace
setup.py develop --userwithpip install --user -e .(the modern, recommended approach).github/workflows/ci.yml (5)
32-32: LGTM! Static checks correctly updated to use module invocation.The change from
python setup.py testtopython3 -m selftests.checkis appropriate and aligns with modern Python packaging practices.
89-99: LGTM! Linux test configuration correctly modernized.The updates appropriately:
- Use
python -VVfor verbose version display (correctly addressed previous redundant flag issue)- Invoke pip via
python3 -m pipto ensure correct pip instance- Use
python3 -m selftests.checkfor test execution
131-143: LGTM! macOS test configuration consistent with other platforms.The changes maintain consistency across platforms by using
python -VVandpython3 -m selftests.check.
167-171: LGTM! Windows configuration correctly updated.The changes properly:
- Use
python -VVconsistently with other platforms- Install setuptools via
python -m pipif missing (correctly fixed from past review)- Use
python -m pip install --user -e .for editable install
265-356: LGTM! Comprehensive dependency updates across all distros.The updates systematically ensure that
python3-pip(andpython3-venvwhere needed) are installed across all tested distributions (Fedora, UBI, Debian, Ubuntu). This is essential for the pip-based installation workflow.Notable additions:
ca-certificatesfor Ubuntu environments (needed for pip over HTTPS)python3-venvfor Debian/Ubuntu (required for virtual environments)Makefile (7)
9-10: LGTM! New plugin development targets improve developer experience.The addition of
develop-pluginsanddevelop-plugintargets provides convenient workflows for plugin development, aligning well with the project's plugin architecture.
33-61: LGTM! Comprehensive cleanup implementation.The expanded
cleantarget now:
- Removes all build artifacts (build/, dist/, *.egg-info, etc.)
- Cleans optional plugins and example plugins
- Removes Python cache files and temporary directories
- Provides informative echo messages during execution
63-67: LGTM! Installation targets modernized to use pip module invocation.Both
installanduninstalltargets now usepython -m pipwhich ensures:
- The correct pip instance is used (matching the Python interpreter)
- Consistency with other pip invocations across the project
78-80: LGTM! Check target updated to use module invocation.The change from direct script execution to
python -m selftests.checkmaintains consistency with the workflow updates across the project.
91-104: LGTM! Well-implemented plugin development targets.The implementations:
- Use
python -m pip install -efor editable plugin installs (correct approach)- Include proper error handling (
ifndef PLUGIN)- Provide clear user feedback with echo statements
- Support both batch installation and individual plugin selection
109-114: LGTM! Man page generation properly guarded.The addition of a command existence check for
rst2manprovides:
- Clear error messaging when the tool is missing
- Prevents silent failures during the build process
- Better developer experience
124-124: LGTM! PHONY targets correctly updated.The
.PHONYdeclaration properly includes the newly addeddevelop-pluginsanddevelop-plugintargets, ensuring these targets are always executed regardless of file timestamps.
| dependencies = [ | ||
| "avocado-framework", | ||
| "cffi", | ||
| "pycparser", | ||
| "ansible-core", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Sync dependency markers with legacy setup.py (avoid drift)
Confirm whether setup.py had pins/markers (e.g., cffi, cryptography, markupsafe). Keep both files aligned or drop pins in both.
Run to diff constraints:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "pyproject deps:"
rg -n '^dependencies\s*=\s*\[' -n -n -A20 optional_plugins/ansible/pyproject.toml | sed -n '1,40p'
echo
echo "setup.py install_requires (if present):"
if [ -f optional_plugins/ansible/setup.py ]; then
rg -nP 'install_requires\s*=\s*\[(?s).*?\]' optional_plugins/ansible/setup.py -n -N -U -C2 || true
else
echo "optional_plugins/ansible/setup.py not found"
fiLength of output: 1068
Align dependency constraints between pyproject.toml and setup.py
optional_plugins/ansible/pyproject.toml: update dependencies to mirror the pins and markers in optional_plugins/ansible/setup.py (avocado-framework=={VERSION}, cffi==1.17.1; python_version<'3.10', cffi; python_version>='3.10', cryptography<46.0.0; python_version<'3.10', pycparser, ansible-core, markupsafe<3.0.0) or remove them from install_requires to avoid drift.
🤖 Prompt for AI Agents
In optional_plugins/ansible/pyproject.toml around lines 14 to 19, the declared
dependencies must be aligned with the pins and environment markers currently
present in optional_plugins/ansible/setup.py; update the dependencies list to
mirror those exact constraints (e.g. avocado-framework=={VERSION}, cffi==1.17.1;
add conditional markers: "cffi; python_version < '3.10'", "cryptography<46.0.0;
python_version >= '3.10'", "pycparser; python_version < '3.10'", "ansible-core",
"markupsafe<3.0.0" where applicable) or alternatively remove these packages from
setup.py install_requires so pyproject.toml becomes the single source of
truth—make the change so both files contain identical pinned versions and
markers to avoid drift.
| dependencies = [ | ||
| "avocado-framework", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Version pinning inconsistency with setup.py.
The comment in setup.py files states "Keep install_requires and entry_points in sync with pyproject.toml for egg build compatibility." However, this file uses an unpinned "avocado-framework" dependency, while the corresponding setup.py likely pins it as f"avocado-framework=={VERSION}".
This inconsistency causes different dependency resolution between builds:
- Wheel/sdist builds (via pyproject.toml): any avocado-framework version
- Egg builds (via setup.py): exact version pinned
Run this script to compare the dependency specifications:
Consider either:
- Adding dynamic dependency substitution to match the VERSION file
- Using a consistent version range in both files (e.g.,
"avocado-framework>=X.Y,<X.Y+1")
🏁 Script executed:
#!/bin/bash
# Description: Compare avocado-framework dependency between setup.py and pyproject.toml
echo "=== golang/setup.py install_requires ==="
rg -A5 "install_requires" optional_plugins/golang/setup.py
echo -e "\n=== golang/pyproject.toml dependencies ==="
rg -A3 "^dependencies" optional_plugins/golang/pyproject.tomlLength of output: 537
Sync avocado-framework version pin between pyproject.toml and setup.py
In optional_plugins/golang/pyproject.toml, change the unpinned "avocado-framework" dependency to "avocado-framework=={VERSION}" to match setup.py and ensure consistent builds.
🤖 Prompt for AI Agents
In optional_plugins/golang/pyproject.toml around lines 14 to 16, the dependency
"avocado-framework" is not version-pinned; update it to
"avocado-framework=={VERSION}" to match setup.py and ensure consistent
builds—replace the unpinned entry with the exact version used in setup.py (or
reference the same version constant), keep the same quoting and comma style as
other entries.
optional_plugins/resultsdb/setup.py
Outdated
| "urllib3<2.3.0; python_version < '3.9'", | ||
| ], | ||
| python_requires=">=3.9", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove dead conditional dependency.
Line 35 specifies urllib3<2.3.0; python_version < '3.9', but line 37 sets python_requires=">=3.9". This condition can never be satisfied because the package cannot be installed on Python < 3.9.
Apply this diff to remove the dead constraint:
install_requires=[
f"avocado-framework=={VERSION}",
"resultsdb-api==2.1.5",
- "urllib3<2.3.0; python_version < '3.9'",
],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "urllib3<2.3.0; python_version < '3.9'", | |
| ], | |
| python_requires=">=3.9", | |
| install_requires=[ | |
| f"avocado-framework=={VERSION}", | |
| "resultsdb-api==2.1.5", | |
| ], | |
| python_requires=">=3.9", |
🤖 Prompt for AI Agents
In optional_plugins/resultsdb/setup.py around lines 35 to 37, the dependency
line "urllib3<2.3.0; python_version < '3.9'" is dead because
python_requires=">=3.9" prevents installing on Python <3.9; remove that
conditional specifier (delete the entire "urllib3<2.3.0; python_version < '3.9'"
entry) so the requirements list only contains relevant constraints, or if
urllib3 is needed for all supported Pythons add a non-conditional urllib3 spec
instead.
| readme_contents = readme.read() | ||
| return readme_contents | ||
|
|
||
| VERSION = open("VERSION", "r", encoding="utf-8").read().strip() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix resource leak: file handle not closed.
Line 22 opens the VERSION file but never closes it, causing a resource leak. The file handle remains open until garbage collection.
Apply this diff to use a context manager:
-VERSION = open("VERSION", "r", encoding="utf-8").read().strip()
+BASE_PATH = os.path.dirname(__file__)
+with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as version_file:
+ VERSION = version_file.read().strip()Or match the pattern used in other setup.py files in this PR (e.g., varianter_pict/setup.py lines 24-26).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| VERSION = open("VERSION", "r", encoding="utf-8").read().strip() | |
| # before, at line 22: | |
| # VERSION = open("VERSION", "r", encoding="utf-8").read().strip() | |
| BASE_PATH = os.path.dirname(__file__) | |
| with open(os.path.join(BASE_PATH, "VERSION"), "r", encoding="utf-8") as version_file: | |
| VERSION = version_file.read().strip() |
🤖 Prompt for AI Agents
In optional_plugins/varianter_cit/setup.py around line 22, the VERSION file is
opened with open(...) and read without closing the file; change this to use a
context manager (with open("VERSION", "r", encoding="utf-8") as f: VERSION =
f.read().strip()) or use the same pattern as varianter_pict/setup.py (e.g.,
Path("VERSION").read_text(encoding="utf-8").strip()) so the file handle is
closed immediately and no resource leak occurs.
python-avocado.spec
Outdated
| # Settings used for build from snapshots. | ||
| %if 0%{?rel_build} | ||
| %global gittar avocado-%{version}.tar.gz | ||
| %global gittar avocado_framework-%{version}.tar.gz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tarball name/directory mismatch will break source fetch and %setup
GitHub archives extract to avocado-, not avocado_framework-. This will 404/mis-unpack.
Apply:
-%global gittar avocado_framework-%{version}.tar.gz
+%global gittar avocado-%{version}.tar.gz
@@
-%global gittar avocado_framework-%{shortcommit}.tar.gz
+%global gittar avocado-%{shortcommit}.tar.gzAlso applies to: 18-18
🤖 Prompt for AI Agents
In python-avocado.spec around line 8 (and also at line 18), the %global gittar
value uses avocado_framework-%{version}.tar.gz which mismatches GitHub archive
names (they extract to avocado-%{tag}), causing source fetch and %setup to fail;
update the %global gittar to avocado-%{version}.tar.gz and ensure any %setup -c
or %setup -n references use the extracted directory name (avocado-%{version}) so
the source archive and unpacked directory match.
| # For egg builds, we need to specify packages and entry_points explicitly | ||
| # Note: This duplicates configuration from pyproject.toml | ||
| setup( | ||
| name="avocado-framework", | ||
| version=VERSION, | ||
| packages=find_packages(exclude=("selftests*",)), | ||
| include_package_data=True, | ||
| zip_safe=False, | ||
| # Keep install_requires in sync with pyproject.toml dependencies | ||
| # for backward compatibility with older tools | ||
| install_requires=[ | ||
| "setuptools", | ||
| ], | ||
| python_requires=">=3.9", | ||
| entry_points={ | ||
| "console_scripts": [ | ||
| "avocado = avocado.core.main:main", | ||
| "avocado-runner-noop = avocado.plugins.runners.noop:main", | ||
| "avocado-runner-dry-run = avocado.plugins.runners.dry_run:main", | ||
| "avocado-runner-exec-test = avocado.plugins.runners.exec_test:main", | ||
| "avocado-runner-python-unittest = avocado.plugins.runners.python_unittest:main", | ||
| "avocado-runner-avocado-instrumented = avocado.plugins.runners.avocado_instrumented:main", | ||
| "avocado-runner-tap = avocado.plugins.runners.tap:main", | ||
| "avocado-runner-asset = avocado.plugins.runners.asset:main", | ||
| "avocado-runner-package = avocado.plugins.runners.package:main", | ||
| "avocado-runner-pip = avocado.plugins.runners.pip:main", | ||
| "avocado-runner-vmimage = avocado.plugins.runners.vmimage:main", | ||
| "avocado-runner-podman-image = avocado.plugins.runners.podman_image:main", | ||
| "avocado-runner-sysinfo = avocado.plugins.runners.sysinfo:main", | ||
| "avocado-software-manager = avocado.utils.software_manager.main:main", | ||
| "avocado-external-runner = scripts.external_runner:main", | ||
| ], | ||
| "avocado.plugins.init": [ | ||
| "xunit = avocado.plugins.xunit:XUnitInit", | ||
| "jsonresult = avocado.plugins.jsonresult:JSONInit", | ||
| "tmt = avocado.plugins.tmtresult:TMTInit", | ||
| "sysinfo = avocado.plugins.sysinfo:SysinfoInit", | ||
| "tap = avocado.plugins.tap:TAPInit", | ||
| "jobscripts = avocado.plugins.jobscripts:JobScriptsInit", | ||
| "dict_variants = avocado.plugins.dict_variants:DictVariantsInit", | ||
| "json_variants = avocado.plugins.json_variants:JsonVariantsInit", | ||
| "run = avocado.plugins.run:RunInit", | ||
| "podman = avocado.plugins.spawners.podman:PodmanSpawnerInit", | ||
| "lxc = avocado.plugins.spawners.lxc:LXCSpawnerInit", | ||
| "nrunner = avocado.plugins.runner_nrunner:RunnerInit", | ||
| "testlogsui = avocado.plugins.testlogs:TestLogsUIInit", | ||
| "human = avocado.plugins.human:HumanInit", | ||
| "exec-runnables-recipe = avocado.plugins.resolvers:ExecRunnablesRecipeInit", | ||
| ], | ||
| "avocado.plugins.cli": [ | ||
| "xunit = avocado.plugins.xunit:XUnitCLI", | ||
| "json = avocado.plugins.jsonresult:JSONCLI", | ||
| "tmt = avocado.plugins.tmtresult:TMTCLI", | ||
| "journal = avocado.plugins.journal:Journal", | ||
| "tap = avocado.plugins.tap:TAP", | ||
| "zip_archive = avocado.plugins.archive:ArchiveCLI", | ||
| "json_variants = avocado.plugins.json_variants:JsonVariantsCLI", | ||
| "nrunner = avocado.plugins.runner_nrunner:RunnerCLI", | ||
| "podman = avocado.plugins.spawners.podman:PodmanCLI", | ||
| ], | ||
| "avocado.plugins.cli.cmd": [ | ||
| "config = avocado.plugins.config:Config", | ||
| "distro = avocado.plugins.distro:Distro", | ||
| "exec-path = avocado.plugins.exec_path:ExecPath", | ||
| "variants = avocado.plugins.variants:Variants", | ||
| "list = avocado.plugins.list:List", | ||
| "run = avocado.plugins.run:Run", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfo", | ||
| "plugins = avocado.plugins.plugins:Plugins", | ||
| "diff = avocado.plugins.diff:Diff", | ||
| "vmimage = avocado.plugins.vmimage:VMimage", | ||
| "assets = avocado.plugins.assets:Assets", | ||
| "jobs = avocado.plugins.jobs:Jobs", | ||
| "replay = avocado.plugins.replay:Replay", | ||
| "cache = avocado.plugins.cache:Cache", | ||
| ], | ||
| "avocado.plugins.job.prepost": [ | ||
| "jobscripts = avocado.plugins.jobscripts:JobScripts", | ||
| "teststmpdir = avocado.plugins.teststmpdir:TestsTmpDir", | ||
| "human = avocado.plugins.human:HumanJob", | ||
| "testlogsui = avocado.plugins.testlogs:TestLogsUI", | ||
| "suite-dependency = avocado.plugins.dependency:SuiteDependency", | ||
| ], | ||
| "avocado.plugins.test.pre": [ | ||
| "dependency = avocado.plugins.dependency:DependencyResolver", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoTest", | ||
| ], | ||
| "avocado.plugins.test.post": [ | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoTest", | ||
| ], | ||
| "avocado.plugins.result": [ | ||
| "xunit = avocado.plugins.xunit:XUnitResult", | ||
| "json = avocado.plugins.jsonresult:JSONResult", | ||
| "tmt = avocado.plugins.tmtresult:TMTResult", | ||
| "zip_archive = avocado.plugins.archive:Archive", | ||
| ], | ||
| "avocado.plugins.result_events": [ | ||
| "human = avocado.plugins.human:Human", | ||
| "tap = avocado.plugins.tap:TAPResult", | ||
| "journal = avocado.plugins.journal:JournalResult", | ||
| "fetchasset = avocado.plugins.assets:FetchAssetJob", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoJob", | ||
| "testlogging = avocado.plugins.testlogs:TestLogging", | ||
| "bystatus = avocado.plugins.bystatus:ByStatusLink", | ||
| "beaker = avocado.plugins.beaker_result:BeakerResult", | ||
| ], | ||
| "avocado.plugins.varianter": [ | ||
| "json_variants = avocado.plugins.json_variants:JsonVariants", | ||
| "dict_variants = avocado.plugins.dict_variants:DictVariants", | ||
| ], | ||
| "avocado.plugins.resolver": [ | ||
| "exec-test = avocado.plugins.resolvers:ExecTestResolver", | ||
| "python-unittest = avocado.plugins.resolvers:PythonUnittestResolver", | ||
| "avocado-instrumented = avocado.plugins.resolvers:AvocadoInstrumentedResolver", | ||
| "tap = avocado.plugins.resolvers:TapResolver", | ||
| "runnable-recipe = avocado.plugins.resolvers:RunnableRecipeResolver", | ||
| "runnables-recipe = avocado.plugins.resolvers:RunnablesRecipeResolver", | ||
| "exec-runnables-recipe = avocado.plugins.resolvers:ExecRunnablesRecipeResolver", | ||
| ], | ||
| "avocado.plugins.suite.runner": [ | ||
| "nrunner = avocado.plugins.runner_nrunner:Runner", | ||
| ], | ||
| "avocado.plugins.runnable.runner": [ | ||
| "avocado-instrumented = avocado.plugins.runners.avocado_instrumented:AvocadoInstrumentedTestRunner", | ||
| "tap = avocado.plugins.runners.tap:TAPRunner", | ||
| "noop = avocado.plugins.runners.noop:NoOpRunner", | ||
| "dry-run = avocado.plugins.runners.dry_run:DryRunRunner", | ||
| "exec-test = avocado.plugins.runners.exec_test:ExecTestRunner", | ||
| "python-unittest = avocado.plugins.runners.python_unittest:PythonUnittestRunner", | ||
| "asset = avocado.plugins.runners.asset:AssetRunner", | ||
| "package = avocado.plugins.runners.package:PackageRunner", | ||
| "pip = avocado.plugins.runners.pip:PipRunner", | ||
| "podman-image = avocado.plugins.runners.podman_image:PodmanImageRunner", | ||
| "vmimage = avocado.plugins.runners.vmimage:VMImageRunner", | ||
| "sysinfo = avocado.plugins.runners.sysinfo:SysinfoRunner", | ||
| ], | ||
| "avocado.plugins.spawner": [ | ||
| "process = avocado.plugins.spawners.process:ProcessSpawner", | ||
| "podman = avocado.plugins.spawners.podman:PodmanSpawner", | ||
| "lxc = avocado.plugins.spawners.lxc:LXCSpawner", | ||
| ], | ||
| "avocado.plugins.cache": [ | ||
| "requirement = avocado.plugins.requirement_cache:RequirementCache", | ||
| ], | ||
| packages=find_packages(exclude=("selftests*",)), | ||
| include_package_data=True, | ||
| entry_points={ | ||
| "console_scripts": [ | ||
| "avocado = avocado.core.main:main", | ||
| "avocado-runner-noop = avocado.plugins.runners.noop:main", | ||
| "avocado-runner-dry-run = avocado.plugins.runners.dry_run:main", | ||
| "avocado-runner-exec-test = avocado.plugins.runners.exec_test:main", | ||
| "avocado-runner-python-unittest = avocado.plugins.runners.python_unittest:main", | ||
| "avocado-runner-avocado-instrumented = avocado.plugins.runners.avocado_instrumented:main", | ||
| "avocado-runner-tap = avocado.plugins.runners.tap:main", | ||
| "avocado-runner-asset = avocado.plugins.runners.asset:main", | ||
| "avocado-runner-package = avocado.plugins.runners.package:main", | ||
| "avocado-runner-pip = avocado.plugins.runners.pip:main", | ||
| "avocado-runner-vmimage = avocado.plugins.runners.vmimage:main", | ||
| "avocado-runner-podman-image = avocado.plugins.runners.podman_image:main", | ||
| "avocado-runner-sysinfo = avocado.plugins.runners.sysinfo:main", | ||
| "avocado-software-manager = avocado.utils.software_manager.main:main", | ||
| "avocado-external-runner = scripts.external_runner:main", | ||
| ], | ||
| "avocado.plugins.init": [ | ||
| "xunit = avocado.plugins.xunit:XUnitInit", | ||
| "jsonresult = avocado.plugins.jsonresult:JSONInit", | ||
| "tmt = avocado.plugins.tmtresult:TMTInit", | ||
| "sysinfo = avocado.plugins.sysinfo:SysinfoInit", | ||
| "tap = avocado.plugins.tap:TAPInit", | ||
| "jobscripts = avocado.plugins.jobscripts:JobScriptsInit", | ||
| "dict_variants = avocado.plugins.dict_variants:DictVariantsInit", | ||
| "json_variants = avocado.plugins.json_variants:JsonVariantsInit", | ||
| "run = avocado.plugins.run:RunInit", | ||
| "podman = avocado.plugins.spawners.podman:PodmanSpawnerInit", | ||
| "lxc = avocado.plugins.spawners.lxc:LXCSpawnerInit", | ||
| "nrunner = avocado.plugins.runner_nrunner:RunnerInit", | ||
| "testlogsui = avocado.plugins.testlogs:TestLogsUIInit", | ||
| "human = avocado.plugins.human:HumanInit", | ||
| "exec-runnables-recipe = avocado.plugins.resolvers:ExecRunnablesRecipeInit", | ||
| ], | ||
| "avocado.plugins.cli": [ | ||
| "xunit = avocado.plugins.xunit:XUnitCLI", | ||
| "json = avocado.plugins.jsonresult:JSONCLI", | ||
| "tmt = avocado.plugins.tmtresult:TMTCLI", | ||
| "journal = avocado.plugins.journal:Journal", | ||
| "tap = avocado.plugins.tap:TAP", | ||
| "zip_archive = avocado.plugins.archive:ArchiveCLI", | ||
| "json_variants = avocado.plugins.json_variants:JsonVariantsCLI", | ||
| "nrunner = avocado.plugins.runner_nrunner:RunnerCLI", | ||
| "podman = avocado.plugins.spawners.podman:PodmanCLI", | ||
| ], | ||
| "avocado.plugins.cli.cmd": [ | ||
| "config = avocado.plugins.config:Config", | ||
| "distro = avocado.plugins.distro:Distro", | ||
| "exec-path = avocado.plugins.exec_path:ExecPath", | ||
| "variants = avocado.plugins.variants:Variants", | ||
| "list = avocado.plugins.list:List", | ||
| "run = avocado.plugins.run:Run", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfo", | ||
| "plugins = avocado.plugins.plugins:Plugins", | ||
| "diff = avocado.plugins.diff:Diff", | ||
| "vmimage = avocado.plugins.vmimage:VMimage", | ||
| "assets = avocado.plugins.assets:Assets", | ||
| "jobs = avocado.plugins.jobs:Jobs", | ||
| "replay = avocado.plugins.replay:Replay", | ||
| "cache = avocado.plugins.cache:Cache", | ||
| ], | ||
| "avocado.plugins.job.prepost": [ | ||
| "jobscripts = avocado.plugins.jobscripts:JobScripts", | ||
| "teststmpdir = avocado.plugins.teststmpdir:TestsTmpDir", | ||
| "human = avocado.plugins.human:HumanJob", | ||
| "testlogsui = avocado.plugins.testlogs:TestLogsUI", | ||
| "suite-dependency = avocado.plugins.dependency:SuiteDependency", | ||
| ], | ||
| "avocado.plugins.test.pre": [ | ||
| "dependency = avocado.plugins.dependency:DependencyResolver", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoTest", | ||
| ], | ||
| "avocado.plugins.test.post": [ | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoTest", | ||
| ], | ||
| "avocado.plugins.result": [ | ||
| "xunit = avocado.plugins.xunit:XUnitResult", | ||
| "json = avocado.plugins.jsonresult:JSONResult", | ||
| "tmt = avocado.plugins.tmtresult:TMTResult", | ||
| "zip_archive = avocado.plugins.archive:Archive", | ||
| ], | ||
| "avocado.plugins.result_events": [ | ||
| "human = avocado.plugins.human:Human", | ||
| "tap = avocado.plugins.tap:TAPResult", | ||
| "journal = avocado.plugins.journal:JournalResult", | ||
| "fetchasset = avocado.plugins.assets:FetchAssetJob", | ||
| "sysinfo = avocado.plugins.sysinfo:SysInfoJob", | ||
| "testlogging = avocado.plugins.testlogs:TestLogging", | ||
| "bystatus = avocado.plugins.bystatus:ByStatusLink", | ||
| "beaker = avocado.plugins.beaker_result:BeakerResult", | ||
| ], | ||
| "avocado.plugins.varianter": [ | ||
| "json_variants = avocado.plugins.json_variants:JsonVariants", | ||
| "dict_variants = avocado.plugins.dict_variants:DictVariants", | ||
| ], | ||
| "avocado.plugins.resolver": [ | ||
| "exec-test = avocado.plugins.resolvers:ExecTestResolver", | ||
| "python-unittest = avocado.plugins.resolvers:PythonUnittestResolver", | ||
| "avocado-instrumented = avocado.plugins.resolvers:AvocadoInstrumentedResolver", | ||
| "tap = avocado.plugins.resolvers:TapResolver", | ||
| "runnable-recipe = avocado.plugins.resolvers:RunnableRecipeResolver", | ||
| "runnables-recipe = avocado.plugins.resolvers:RunnablesRecipeResolver", | ||
| "exec-runnables-recipe = avocado.plugins.resolvers:ExecRunnablesRecipeResolver", | ||
| ], | ||
| "avocado.plugins.suite.runner": [ | ||
| "nrunner = avocado.plugins.runner_nrunner:Runner", | ||
| ], | ||
| "avocado.plugins.runnable.runner": [ | ||
| ( | ||
| "avocado-instrumented = avocado.plugins." | ||
| "runners.avocado_instrumented:AvocadoInstrumentedTestRunner" | ||
| ), | ||
| "tap = avocado.plugins.runners.tap:TAPRunner", | ||
| "noop = avocado.plugins.runners.noop:NoOpRunner", | ||
| "dry-run = avocado.plugins.runners.dry_run:DryRunRunner", | ||
| "exec-test = avocado.plugins.runners.exec_test:ExecTestRunner", | ||
| "python-unittest = avocado.plugins.runners.python_unittest:PythonUnittestRunner", | ||
| "asset = avocado.plugins.runners.asset:AssetRunner", | ||
| "package = avocado.plugins.runners.package:PackageRunner", | ||
| "pip = avocado.plugins.runners.pip:PipRunner", | ||
| "podman-image = avocado.plugins.runners.podman_image:PodmanImageRunner", | ||
| "vmimage = avocado.plugins.runners.vmimage:VMImageRunner", | ||
| "sysinfo = avocado.plugins.runners.sysinfo:SysinfoRunner", | ||
| ], | ||
| "avocado.plugins.spawner": [ | ||
| "process = avocado.plugins.spawners.process:ProcessSpawner", | ||
| "podman = avocado.plugins.spawners.podman:PodmanSpawner", | ||
| "lxc = avocado.plugins.spawners.lxc:LXCSpawner", | ||
| ], | ||
| "avocado.plugins.cache": [ | ||
| "requirement = avocado.plugins.requirement_cache:RequirementCache", | ||
| ], | ||
| }, | ||
| zip_safe=False, | ||
| python_requires=">=3.9", | ||
| cmdclass={ | ||
| "clean": Clean, | ||
| "develop": Develop, | ||
| "lint": Linter, | ||
| "man": Man, | ||
| "plugin": Plugin, | ||
| "test": Test, | ||
| }, | ||
| install_requires=["setuptools"], | ||
| ) | ||
| }, | ||
| cmdclass={ | ||
| "clean": Clean, | ||
| "develop": Develop, | ||
| }, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Restrict package discovery to avocado namespace (avoid bundling optional_plugins)
find_packages(exclude=("selftests*",)) will pick up optional_plugins/* packages, causing conflicts with separate plugin wheels/RPMs.
- packages=find_packages(exclude=("selftests*",)),
+ packages=find_packages(include=("avocado", "avocado.*")),Ensure avocado-external-runner import is package-resolved
Entry point “scripts.external_runner:main” requires scripts/ to be a package and included. Please confirm scripts/init.py exists and scripts is packaged, or move this module under avocado.*.
install_requires not in sync with pyproject
Only “setuptools” is listed, which breaks egg installs (missing runtime deps). Either sync this with pyproject’s [project.dependencies] or drop egg support. At minimum, mirror core runtime deps here.
Future-proof clean command for Python 3.12+
distutils is removed on 3.12. Switch to setuptools.command.clean.clean.
Outside the selected lines, update the import:
-from distutils.command.clean import clean # pylint: disable=W0402
+from setuptools.command.clean import cleanOptional: add a CI check to compare entry_points between setup.py and pyproject.toml to prevent drift.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check scripts package:"
test -f scripts/external_runner.py && echo "✓ scripts/external_runner.py exists" || echo "✗ missing"
test -f scripts/__init__.py && echo "✓ scripts/__init__.py exists" || echo "✗ scripts/__init__.py missing"
rg -nP 'packages\s*=\s*find_packages\([^)]*\)' setup.py -n || trueLength of output: 145
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "pyproject dependencies (root):"
if [ -f pyproject.toml ]; then rg -n '^dependencies\s*=\s*\[' -n -A20 pyproject.toml | sed -n '1,80p'; else echo "pyproject.toml not found"; fi
echo
echo "setup.py install_requires:"
rg -nP 'install_requires\s*=\s*\[(?s).*?\]' setup.py -U -n || trueLength of output: 888
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check import of distutils.command.clean in setup.py:"
rg -nP 'distutils\.command\.clean.*import' -n setup.py || echo "No import found"
echo
echo "Check import of setuptools.command.clean in setup.py:"
rg -nP 'setuptools\.command\.clean.*import' -n setup.py || echo "No import found"Length of output: 193
Restrict find_packages, ensure scripts package, and update clean import
-
Replace
- packages=find_packages(exclude=("selftests*",)), + packages=find_packages(include=("avocado", "avocado.*")),
to avoid bundling optional_plugins.
-
Add
scripts/__init__.py(or moveexternal_runner.pyunderavocado/…) soscripts.external_runner:mainis importable. -
Replace
-from distutils.command.clean import clean # pylint: disable=W0402 +from setuptools.command.clean import clean
for Python 3.12+ compatibility.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In setup.py around lines 207-356, tighten package discovery and fix imports:
update find_packages(...) to exclude optional_plugins (e.g., add
"optional_plugins*" to the exclude tuple) so optional plugins aren't bundled;
ensure scripts.external_runner is importable by adding scripts/__init__.py (or
moving external_runner.py into the avocado package and adjusting the entry_point
path); and replace the distutils-based Clean import/usage with the
setuptools-compatible variant for Python 3.12+ (swap the import/implementation
to use setuptools' clean command or an equivalent implementation) so cmdclass
remains compatible.
This commit modernizes the project packaging from setup.py to pyproject.toml-based configuration following PEP 517/518/621 standards. Changes include: - Add pyproject.toml for main avocado-framework package - Add pyproject.toml for all optional plugins (ansible, golang, html, mail, result_upload, resultsdb, robot, spawner_remote, varianter_cit, varianter_pict, varianter_yaml_to_mux) - Add pyproject.toml for all example plugins - Update GitHub Actions workflows to use pip install instead of setup.py - Modernize Makefile to use pip commands and improve clean targets - Update documentation to reflect new installation methods - Simplify setup.py files to act as compatibility shims - Refactor spawner_remote plugin structure (move code from __init__.py to spawner.py) - Update python-avocado.spec for RPM packaging compatibility All installation commands now use standard pip commands: - Development install: pip install -e . - Plugin install: pip install ./optional_plugins/<plugin> - Uninstall: pip uninstall avocado-framework Testing and CI workflows have been updated accordingly. Signed-off-by: Yihuang Yu <yihyu@redhat.com>
|
Hello @clebergnu, after much coding and debugging, I made the CI all green. But unfortunately, there are some different kinds of issue to enable pyproject.toml.
Based on the above, I convert this to draft as a tracker, and coderabbit AI made some dirty comments. Will use separate PRs to fix issues step by step. |
Call
python setup.pydirectly is deprecated, to modernize thisproject, let's introduce pyproject.toml, it supports more features. For
compatibility with the past, keep setup.py in present.
Signed-off-by: Yihuang Yu yihyu@redhat.com
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores
Tests