2022-11-16 11:39:29 +01:00
|
|
|
[build-system]
|
2023-05-11 23:13:37 +02:00
|
|
|
requires = []
|
|
|
|
backend-path = ['src']
|
|
|
|
build-backend = 'build_backend'
|
2022-11-16 11:39:29 +01:00
|
|
|
|
2022-10-28 11:41:36 +02:00
|
|
|
[tool.mypy]
|
2024-04-22 10:13:52 +02:00
|
|
|
follow_imports = 'silent' # https://github.com/python-lsp/pylsp-mypy/issues/81
|
|
|
|
scripts_are_modules = true # allow checking all scripts in one invocation
|
|
|
|
explicit_package_bases = true
|
|
|
|
mypy_path = 'src:test/common:bots'
|
|
|
|
exclude = [
|
|
|
|
'tmp/',
|
|
|
|
'tools/vulture-suppressions/',
|
|
|
|
'vendor/',
|
|
|
|
]
|
2024-04-22 10:30:51 +02:00
|
|
|
|
2023-02-06 17:29:42 +01:00
|
|
|
[[tool.mypy.overrides]]
|
2023-10-31 09:19:58 +01:00
|
|
|
ignore_missing_imports = true
|
2024-04-22 10:13:52 +02:00
|
|
|
module = [
|
|
|
|
# run without submodules checked out
|
|
|
|
"cockpit._vendor.*",
|
|
|
|
|
|
|
|
# run without bots checked out
|
|
|
|
"lib.*",
|
|
|
|
"machine.*",
|
|
|
|
"task.*",
|
|
|
|
"testvm",
|
|
|
|
"PIL",
|
|
|
|
|
|
|
|
# run with bots checked out but its dependencies missing
|
|
|
|
"libvirt",
|
|
|
|
"libvirt_qemu",
|
|
|
|
"pika",
|
|
|
|
|
|
|
|
# run without gobject-introspection (used from cockpit-client for Gtk)
|
|
|
|
"gi.*",
|
|
|
|
|
|
|
|
# these are used from various scripts meant to run on the host
|
|
|
|
"dbus",
|
|
|
|
"tracer.query",
|
|
|
|
"vdo.*",
|
|
|
|
]
|
|
|
|
|
|
|
|
[[tool.mypy.overrides]]
|
|
|
|
# https://github.com/python/mypy/issues/11401 prevents us from enabling strict
|
|
|
|
# mode for a given set of files, so instead, we enable the corresponding set of
|
|
|
|
# individual checks the files which are strictly typed.
|
|
|
|
check_untyped_defs = true
|
|
|
|
disallow_any_generics = true
|
|
|
|
disallow_incomplete_defs = true
|
|
|
|
disallow_subclassing_any = true
|
|
|
|
disallow_untyped_calls = true
|
|
|
|
disallow_untyped_decorators = true
|
|
|
|
disallow_untyped_defs = true
|
|
|
|
no_implicit_reexport = true
|
|
|
|
strict_concatenate = true
|
|
|
|
strict_equality = true
|
|
|
|
warn_unused_ignores = true
|
|
|
|
module = [
|
|
|
|
# src
|
|
|
|
'cockpit',
|
|
|
|
'cockpit._version',
|
|
|
|
'cockpit.jsonutil',
|
|
|
|
'cockpit.protocol',
|
|
|
|
'cockpit.transports',
|
|
|
|
|
|
|
|
# test/common
|
|
|
|
'cdp',
|
|
|
|
'testlib',
|
|
|
|
]
|
2022-10-28 11:41:36 +02:00
|
|
|
|
|
|
|
[tool.pylint]
|
|
|
|
max-line-length = 118
|
|
|
|
disable = [
|
|
|
|
"C0114", # Missing module docstring
|
|
|
|
"C0115", # Missing class docstring
|
python bridge: rewrite packages serving code
Rework the packages loading code. The main changes:
- we don't attempt to do checksums anymore. This was taking a large
amount of time when loading the bridge and we never implemented it
properly anyway (since we weren't sending the `.checksum` fields in
the manifests)
- instead, we do scan the list of files in the package one time (at
first use, not load) and build our map of URL paths to filenames at
this point. This allows us to retain our efficient lookup code, but
requires us to do the actual file loading at the time of the request.
Because we're no longer storing the contents of the files in memory,
this is a substantial runtime memory usage reduction.
- drop all of the extra code we had for walking the paths in a
particular order. We just do (r)globs now.
- move all of the code for deciding which packages to load to a
separate class. We now load all of the manifests and evaluate them
(requirements, conditionals, priorities) and only the packages that
we actually intend to serve are then scanned. The new structure also
makes it easier for cockpit-beiboot to do its thing.
- the packages loading code now uses the actual cockpit version number
for requires comparisons instead of the previously hardcoded '300'.
Add an extra check if our version number is `0` (ie: running out of
git) and disable version checking in that case.
- clean up the relationship between `cockpit.packages` and
`cockpit.channels.packages`. Previously, `cockpit.packages` would
access properties on the channel object and call methods on it to
serve the content back. Now the channel requests the data from
`cockpit.packages` (which merely returns the result).
- enabled by the above: full typing throughout, and mypy is happy. We
have one tiny little thorn in that the packages channel is not
strictly capable of knowing that the router to which it's connected
has a `packages` attribute, but that's nothing that we weren't doing
already. Add a comment to draw attention to it.
- to the extent possible, we try to keep the state of the packages
channel away from the packages code proper. This led to an overhaul
of our `Content-Security-Policy` not to include the origin URLs in
the policy output. This is redundant anyway, since that's what
"'self'" is for. We do need to do one hack for websockets though,
until we can convince ourselves about browser support for the
standard. This hack is lifted to the channel level. Adjust tests
accordingly.
- with some small changes to our pyproject.toml, the two rewritten
files (`packages.py` and `channels/packages.py`) are now also passing
pylint, but we don't enable that yet, since everything else is
broken.
2023-07-17 11:03:42 +02:00
|
|
|
"C0116", # Missing function or method docstring
|
2022-10-28 11:41:36 +02:00
|
|
|
"R0902", # Too many instance attributes
|
|
|
|
"R0903", # Too few public methods
|
|
|
|
"R0913", # Too many arguments
|
|
|
|
"R1705", # Unnecessary "else" after "return"
|
python bridge: rewrite packages serving code
Rework the packages loading code. The main changes:
- we don't attempt to do checksums anymore. This was taking a large
amount of time when loading the bridge and we never implemented it
properly anyway (since we weren't sending the `.checksum` fields in
the manifests)
- instead, we do scan the list of files in the package one time (at
first use, not load) and build our map of URL paths to filenames at
this point. This allows us to retain our efficient lookup code, but
requires us to do the actual file loading at the time of the request.
Because we're no longer storing the contents of the files in memory,
this is a substantial runtime memory usage reduction.
- drop all of the extra code we had for walking the paths in a
particular order. We just do (r)globs now.
- move all of the code for deciding which packages to load to a
separate class. We now load all of the manifests and evaluate them
(requirements, conditionals, priorities) and only the packages that
we actually intend to serve are then scanned. The new structure also
makes it easier for cockpit-beiboot to do its thing.
- the packages loading code now uses the actual cockpit version number
for requires comparisons instead of the previously hardcoded '300'.
Add an extra check if our version number is `0` (ie: running out of
git) and disable version checking in that case.
- clean up the relationship between `cockpit.packages` and
`cockpit.channels.packages`. Previously, `cockpit.packages` would
access properties on the channel object and call methods on it to
serve the content back. Now the channel requests the data from
`cockpit.packages` (which merely returns the result).
- enabled by the above: full typing throughout, and mypy is happy. We
have one tiny little thorn in that the packages channel is not
strictly capable of knowing that the router to which it's connected
has a `packages` attribute, but that's nothing that we weren't doing
already. Add a comment to draw attention to it.
- to the extent possible, we try to keep the state of the packages
channel away from the packages code proper. This led to an overhaul
of our `Content-Security-Policy` not to include the origin URLs in
the policy output. This is redundant anyway, since that's what
"'self'" is for. We do need to do one hack for websockets though,
until we can convince ourselves about browser support for the
standard. This hack is lifted to the channel level. Adjust tests
accordingly.
- with some small changes to our pyproject.toml, the two rewritten
files (`packages.py` and `channels/packages.py`) are now also passing
pylint, but we don't enable that yet, since everything else is
broken.
2023-07-17 11:03:42 +02:00
|
|
|
"W0120", # Else clause on loop without a break statement
|
2022-10-28 11:41:36 +02:00
|
|
|
"W1113", # Keyword argument before variable positional arguments (PEP-570 is Python 3.8)
|
|
|
|
]
|
|
|
|
|
2023-05-03 11:00:04 +02:00
|
|
|
[tool.ruff]
|
2024-02-02 09:52:48 +01:00
|
|
|
exclude = [
|
|
|
|
".git/",
|
|
|
|
"modules/",
|
|
|
|
"node_modules/",
|
|
|
|
]
|
|
|
|
line-length = 118
|
2024-04-15 20:10:50 +02:00
|
|
|
preview = true
|
2024-02-02 09:52:48 +01:00
|
|
|
src = []
|
|
|
|
|
|
|
|
[tool.ruff.lint]
|
2023-05-17 15:49:50 +02:00
|
|
|
select = [
|
2023-05-17 18:08:19 +02:00
|
|
|
"A", # flake8-builtins
|
2023-05-17 16:31:34 +02:00
|
|
|
"B", # flake8-bugbear
|
2023-05-22 13:06:52 +02:00
|
|
|
"C4", # flake8-comprehensions
|
2023-06-14 11:05:47 +02:00
|
|
|
"D300", # pydocstyle: Forbid ''' in docstrings
|
2023-05-22 13:09:49 +02:00
|
|
|
"DTZ", # flake8-datetimez
|
2023-05-17 15:49:50 +02:00
|
|
|
"E", # pycodestyle
|
2023-05-22 13:09:49 +02:00
|
|
|
"EXE", # flake8-executable
|
2023-05-17 15:49:50 +02:00
|
|
|
"F", # pyflakes
|
2023-05-22 13:39:16 +02:00
|
|
|
"FBT", # flake8-boolean-trap
|
2023-05-17 19:55:07 +02:00
|
|
|
"G", # flake8-logging-format
|
2023-05-17 15:49:50 +02:00
|
|
|
"I", # isort
|
2023-05-22 13:09:49 +02:00
|
|
|
"ICN", # flake8-import-conventions
|
|
|
|
"ISC", # flake8-implicit-str-concat
|
2023-07-29 03:31:26 +02:00
|
|
|
"PIE", # flake8-pie
|
2023-05-22 13:09:49 +02:00
|
|
|
"PLE", # pylint errors
|
2023-05-22 13:49:23 +02:00
|
|
|
"PGH", # pygrep-hooks
|
2023-05-22 13:05:10 +02:00
|
|
|
"PT", # flake8-pytest-style
|
2023-05-22 13:09:49 +02:00
|
|
|
"RSE", # flake8-raise
|
|
|
|
"RUF", # ruff rules
|
|
|
|
"T10", # flake8-debugger
|
|
|
|
"TCH", # flake8-type-checking
|
2023-09-27 13:39:40 +02:00
|
|
|
"UP032", # f-string
|
2023-05-22 13:09:49 +02:00
|
|
|
"W", # warnings (mostly whitespace)
|
|
|
|
"YTT", # flake8-2020
|
2023-05-17 15:49:50 +02:00
|
|
|
]
|
2023-05-03 11:00:04 +02:00
|
|
|
ignore = [
|
2023-05-17 18:08:19 +02:00
|
|
|
"A003", # Class attribute is shadowing a python builtin
|
2023-05-17 16:31:34 +02:00
|
|
|
"B011", # Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`
|
2023-05-03 11:00:04 +02:00
|
|
|
"E731", # Do not assign a `lambda` expression, use a `def`
|
2023-05-22 13:05:10 +02:00
|
|
|
"PT011", # `pytest.raises(OSError)` is too broad
|
2023-06-22 18:50:13 +02:00
|
|
|
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
|
python bridge: rewrite packages serving code
Rework the packages loading code. The main changes:
- we don't attempt to do checksums anymore. This was taking a large
amount of time when loading the bridge and we never implemented it
properly anyway (since we weren't sending the `.checksum` fields in
the manifests)
- instead, we do scan the list of files in the package one time (at
first use, not load) and build our map of URL paths to filenames at
this point. This allows us to retain our efficient lookup code, but
requires us to do the actual file loading at the time of the request.
Because we're no longer storing the contents of the files in memory,
this is a substantial runtime memory usage reduction.
- drop all of the extra code we had for walking the paths in a
particular order. We just do (r)globs now.
- move all of the code for deciding which packages to load to a
separate class. We now load all of the manifests and evaluate them
(requirements, conditionals, priorities) and only the packages that
we actually intend to serve are then scanned. The new structure also
makes it easier for cockpit-beiboot to do its thing.
- the packages loading code now uses the actual cockpit version number
for requires comparisons instead of the previously hardcoded '300'.
Add an extra check if our version number is `0` (ie: running out of
git) and disable version checking in that case.
- clean up the relationship between `cockpit.packages` and
`cockpit.channels.packages`. Previously, `cockpit.packages` would
access properties on the channel object and call methods on it to
serve the content back. Now the channel requests the data from
`cockpit.packages` (which merely returns the result).
- enabled by the above: full typing throughout, and mypy is happy. We
have one tiny little thorn in that the packages channel is not
strictly capable of knowing that the router to which it's connected
has a `packages` attribute, but that's nothing that we weren't doing
already. Add a comment to draw attention to it.
- to the extent possible, we try to keep the state of the packages
channel away from the packages code proper. This led to an overhaul
of our `Content-Security-Policy` not to include the origin URLs in
the policy output. This is redundant anyway, since that's what
"'self'" is for. We do need to do one hack for websockets though,
until we can convince ourselves about browser support for the
standard. This hack is lifted to the channel level. Adjust tests
accordingly.
- with some small changes to our pyproject.toml, the two rewritten
files (`packages.py` and `channels/packages.py`) are now also passing
pylint, but we don't enable that yet, since everything else is
broken.
2023-07-17 11:03:42 +02:00
|
|
|
"TCH001", # Move application import into a type-checking block
|
2023-09-06 09:38:32 +02:00
|
|
|
"TCH002", # Move third-party import `..packages.Packages` into a type-checking block
|
2023-05-03 11:00:04 +02:00
|
|
|
]
|
|
|
|
|
2024-02-02 09:52:48 +01:00
|
|
|
[tool.ruff.lint.flake8-pytest-style]
|
2023-05-22 13:05:10 +02:00
|
|
|
fixture-parentheses = false
|
|
|
|
mark-parentheses = false
|
|
|
|
|
2024-02-02 09:52:48 +01:00
|
|
|
[tool.ruff.lint.isort]
|
python: include clean-ups for isort
Theoretically, we want to separate things into five buckets (stdlib,
third-party, vendored, cockpit, local-folder) but we also want to take a
more or less stock isort behaviour, so we do this:
In our testcases, we want the "local folder" bucket to refer to the mock
utility classes in the pytest/ directory, while first-party refers to
cockpit. Add __init__.py to test/ and test/pytest/ to ensure that we can
do relative imports (which we should have been doing already).
In src/ we make sure to always refer to our vendored packages by their
full name (`cockpit._vendor.*`) and to do relative imports from cockpit
itself. That ends up putting our vendored packages in the first-party
bucket and cockpit into local-folder, which is approximately correct.
The only issue here is that if we directly include vendored packages
from our testcases, they end up in the same bucket with cockpit itself.
That's not a big problem.
2023-05-22 13:03:20 +02:00
|
|
|
known-first-party = ["cockpit"]
|
|
|
|
|
2022-10-28 11:41:36 +02:00
|
|
|
[tool.pytest.ini_options]
|
2023-03-30 16:48:38 +02:00
|
|
|
addopts = ['--strict-markers'] # cf. https://github.com/cockpit-project/cockpit/pull/18584#issuecomment-1490243994
|
2022-10-31 08:55:33 +01:00
|
|
|
pythonpath = ["src"]
|
|
|
|
testpaths = ["test/pytest"]
|
2022-10-28 11:41:36 +02:00
|
|
|
log_cli = true
|
2023-05-03 11:19:59 +02:00
|
|
|
required_plugins = ["pytest-asyncio"]
|
2022-10-28 11:41:36 +02:00
|
|
|
|
2023-05-04 10:04:46 +02:00
|
|
|
[tool.vulture]
|
|
|
|
paths = [
|
|
|
|
"src",
|
|
|
|
"test/pytest",
|
2024-04-22 10:30:51 +02:00
|
|
|
"tools/vulture_suppressions",
|
2023-05-04 10:04:46 +02:00
|
|
|
]
|
|
|
|
ignore_names = [
|
|
|
|
"do_*",
|
|
|
|
"test[A-Z0-9]*",
|
|
|
|
]
|
|
|
|
ignore_decorators = [
|
|
|
|
"@*.getter",
|
2023-06-07 16:55:51 +02:00
|
|
|
"@*.register_function",
|
|
|
|
"@bus.Interface.Method",
|
|
|
|
"@pytest.hookimpl",
|
2023-05-04 10:04:46 +02:00
|
|
|
]
|
|
|
|
|
2022-10-28 11:41:36 +02:00
|
|
|
[tool.coverage.paths]
|
|
|
|
source = ["src", "*/site-packages"]
|
|
|
|
|
|
|
|
[tool.coverage.run]
|
2022-11-07 09:28:06 +01:00
|
|
|
concurrency = ["multiprocessing"]
|
2022-10-28 11:41:36 +02:00
|
|
|
source_pkgs = ["cockpit"]
|
2022-10-31 08:55:34 +01:00
|
|
|
branch = true
|
2022-10-28 11:41:36 +02:00
|
|
|
|
|
|
|
[tool.coverage.report]
|
|
|
|
show_missing = true
|
2022-10-31 08:55:34 +01:00
|
|
|
skip_covered = true
|
2022-10-28 11:41:36 +02:00
|
|
|
exclude_lines = [
|
2022-10-31 08:55:34 +01:00
|
|
|
"pragma: no cover", # default
|
2022-10-28 11:41:36 +02:00
|
|
|
"raise NotImplementedError",
|
|
|
|
]
|
2023-02-07 17:32:39 +01:00
|
|
|
|
|
|
|
[tool.tox]
|
|
|
|
legacy_tox_ini = """
|
|
|
|
[tox]
|
2023-07-03 10:59:48 +02:00
|
|
|
envlist = lint,pytest
|
2023-02-07 17:32:39 +01:00
|
|
|
isolated_build = True
|
2023-07-03 10:59:48 +02:00
|
|
|
labels =
|
2024-03-11 11:15:40 +01:00
|
|
|
venv = py3{6,8,9,10,11,12,13}-pytest
|
2023-02-07 17:32:39 +01:00
|
|
|
|
2023-07-03 10:59:48 +02:00
|
|
|
# The default test environments use system packages and never PyPI.
|
|
|
|
[testenv:{lint,pytest}]
|
|
|
|
sitepackages = True
|
|
|
|
install_command = python3 -m pip install --no-index --no-build-isolation {opts} {packages}
|
|
|
|
wheel_build_env = pkg
|
|
|
|
|
|
|
|
# All other environments (names like py311-lint, py36-pytest, etc) are isolated
|
|
|
|
# from the system and get their packages from PyPI, according to the specific
|
|
|
|
# test environment being requested. We build the wheel in a common environment.
|
2023-02-07 17:32:39 +01:00
|
|
|
[testenv]
|
2023-07-03 10:59:48 +02:00
|
|
|
package = wheel
|
|
|
|
wheel_build_env = venv-pkg
|
|
|
|
skip_install = lint: True
|
|
|
|
deps =
|
|
|
|
lint: mypy
|
|
|
|
lint: ruff
|
|
|
|
lint: vulture
|
|
|
|
pytest
|
2023-02-07 17:32:39 +01:00
|
|
|
pytest-asyncio
|
2023-07-03 10:59:48 +02:00
|
|
|
pytest: pytest-cov
|
|
|
|
pytest: pytest-timeout
|
|
|
|
pytest: pytest-xdist
|
|
|
|
allowlist_externals = test/static-code
|
|
|
|
commands =
|
|
|
|
pytest: python3 -m pytest -opythonpath= {posargs}
|
|
|
|
lint: test/static-code --tap
|
2023-02-07 17:32:39 +01:00
|
|
|
"""
|