Skip to content

Lint with mypy on CI - #219

Merged
marmarek merged 5 commits into
QubesOS:mainfrom
ben-grande:mypy
Aug 8, 2026
Merged

Lint with mypy on CI#219
marmarek merged 5 commits into
QubesOS:mainfrom
ben-grande:mypy

Conversation

@ben-grande

Copy link
Copy Markdown
Contributor

I'd like mypy to run on #213.

@ben-grande
ben-grande marked this pull request as draft July 24, 2026 09:05
@ben-grande

Copy link
Copy Markdown
Contributor Author

@nihalxkumar You modified some of these files in your PR, I think that it is easier:

  • We enable CI in your PR
  • You check what new issues were introduced and fix them in the same PR

Rather than fixing those errors in a separate PR, as that might cause some merge conflicts.

@nihalxkumar

Copy link
Copy Markdown
Contributor

I ran the mypy check on my branch. It reports the same 34 errors already present on main, with no new errors from my changes
I think we should use #219 to fix the baseline errors before this CI job is brought into qvm-template-upgrade branch

@ben-grande
ben-grande marked this pull request as ready for review July 27, 2026 10:52
@ben-grande

Copy link
Copy Markdown
Contributor Author

with no new errors from my changes

Bodies of untyped functions are not checked, so you can add return type to functions you added to make mypy lint them.

@codecov-commenter

codecov-commenter commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.68794% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.38%. Comparing base (4973653) to head (8c5c6eb).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
vmupdate/update_manager.py 76.92% 15 Missing ⚠️
vmupdate/qube_connection.py 62.50% 6 Missing ⚠️
vmupdate/agent/source/common/process_result.py 80.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #219      +/-   ##
==========================================
- Coverage   71.42%   71.38%   -0.05%     
==========================================
  Files          12       12              
  Lines        1344     1384      +40     
==========================================
+ Hits          960      988      +28     
- Misses        384      396      +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nihalxkumar

Copy link
Copy Markdown
Contributor

🙋 01027e3 (This PR) L431 renames the dom0 list to entrypoint_cmd, but L463 still passes entrypoint.
on the AdminVM + dom0 path it's unassigned and qubes-vm-update --dom0 raises UnboundLocalError.

My patch for 213: https://gist.github.com/nihalxkumar/b5d76eb71ba8ebaa45ac90af08d6e9b2
will commit and rebase after this PR lands

@ben-grande

Copy link
Copy Markdown
Contributor Author

🙋 01027e3 (This PR) L431 renames the dom0 list to entrypoint_cmd, but L463 still passes entrypoint.
on the AdminVM + dom0 path it's unassigned and qubes-vm-update --dom0 raises UnboundLocalError.

I was trying to circumvent a mypy error that entrypoint had two types, str and list. I now see that I missed one step.

Comment thread vmupdate/agent/source/dnf/dnf5_api.py Outdated

def add_new_download(
self, _user_data, description: str, total_to_download: float
self, _user_data, description: str, total_to_download: int

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This (and other changes to function signatures in this class) is wrong - the function is called by libdnf and according to its documentation it uses float here:

 |  add_new_download(self, user_data, description, total_to_download)
 |      Notify the client that a new download has been created.
 |      :type user_data: void
 |      :param user_data: User data entered together with url/package to download.
 |      :type description: string
 |      :param description: The message describing new download (url/packagename).
 |      :type total_to_download: float
 |      :param total_to_download: Total number of bytes to download.
 |      :rtype: void
 |      :return: Associated user data for new download.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Was this automatic detection somehow that I could have done via editor or some other tool? To fix, I looked at help(libdnf5.repo.DownloadCallbacks.add_new_download).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nope, I just checked type changes in this PR that looked suspicious to me.

@marmarek

marmarek commented Aug 7, 2026

Copy link
Copy Markdown
Member

This looks to be caused by this PR. qubes-vm-update --targets=dom0 prints not much details (just it got some exception, but not even exception name), but after adding strategical traceback.format_exc() in vmupdate/update_manager.py line 407, I got this:

dom0:out: ERROR (exception Traceback (most recent call last):
dom0:out:   File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 399, in update_qube
dom0:out:     result = runner.run_agent(
dom0:out:         agent_args=agent_args,
dom0:out:         status_notifier=status_notifier,
dom0:out:         termination=termination,
dom0:out:     )
dom0:out:   File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 468, in run_agent
dom0:out:     result = self._run_agent(agent_args, new_status_notifier, termination)
dom0:out:   File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 510, in _run_agent
dom0:out:     assert src_dir is not None
dom0:out:            ^^^^^^^^^^^^^^^^^^^
dom0:out: AssertionError
dom0:out: )

# silent is equivalent to quiet for dom0-update
entrypoint.append("--silent")
entrypoint_cmd.append("--silent")
entrypoint: list[str] | str = entrypoint_cmd

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With keeping it a list, secondary variable isn't really needed, please restore to using just entrypoint (just adding type hint should be enough, if mypy can't figure it out on its own).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

update_manager.py:433: error: Item "str" of "list[str] | str" has no attribute "append"  [union-attr]
update_manager.py:436: error: Item "str" of "list[str] | str" has no attribute "append"  [union-attr]

I added two variables to deal with this. I thought it was better to have a type per variable instead of using # type: ignore.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if you let it be just list[str] in this code branch? It should still be compatible with list[str] | str later, no?

@marmarek marmarek Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But if that doesn't work, then fine, lets have a separate variable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What if you let it be just list[str] in this code branch? It should still be compatible with list[str] | str later, no?

Mypy doesn't like setting type twice for a variable.

update_manager.py:439: error: Name "entrypoint" already defined on line 431  [no-redef]

@ben-grande

Copy link
Copy Markdown
Contributor Author

dom0:out: ERROR (exception Traceback (most recent call last):
dom0:out: File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 399, in update_qube
dom0:out: result = runner.run_agent(
dom0:out: agent_args=agent_args,
dom0:out: status_notifier=status_notifier,
dom0:out: termination=termination,
dom0:out: )
dom0:out: File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 468, in run_agent
dom0:out: result = self._run_agent(agent_args, new_status_notifier, termination)
dom0:out: File "/usr/lib/python3.13/site-packages/vmupdate/update_manager.py", line 510, in _run_agent
dom0:out: assert src_dir is not None
dom0:out: ^^^^^^^^^^^^^^^^^^^
dom0:out: AssertionError
dom0:out: )

This is strange. I don't know what used to happen before, because:

It can be empty string though:

>>> import os
>>> import tempfile
>>> arch_format = ".tar.gz"
>>> arch_dir = tempfile.mkdtemp()
>>> root_dir = os.path.dirname(None)
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    root_dir = os.path.dirname(None)
  File "<frozen posixpath>", line 178, in dirname
TypeError: expected str, bytes or os.PathLike object, not NoneType
>>> root_dir = os.path.dirname("")
>>> root_dir
''
>>> base_dir = os.path.basename("".strip(os.sep))
>>> base_dir
''
>>> src_arch = os.path.join(arch_dir, base_dir + arch_format)
>>> src_arch
'/tmp/tmpxxt_4vja/.tar.gz'

But this is really weird.

@marmarek

marmarek commented Aug 7, 2026

Copy link
Copy Markdown
Member

it can't be None on qube_connection

But that's transfer_agent function, which isn't called for AdminVM. So, in case of AdminVM, None is fine

@ben-grande

ben-grande commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

openQArun TEST=system_tests_network_updates TEST_TEMPLATES=debian-13-xfce UPDATE_TEMPLATES=debian-13-xfce


Ok, this repo is not in the allow list...

@marmarek

marmarek commented Aug 7, 2026

Copy link
Copy Markdown
Member

Regarding last push, you forgot to remove old assert location

@ben-grande

Copy link
Copy Markdown
Contributor Author

Do you know what failed here? QubesOS/qubes-core-admin#783 (comment)

@marmarek

marmarek commented Aug 7, 2026

Copy link
Copy Markdown
Member

It "worked" (but see the failure there, merge conflict): https://gitlab.com/QubesOS/qubes-continuous-integration/-/pipelines/2740561055
But, github has some silly limits, setting deployment status failed:

{"message":"Validation Failed","errors":[{"resource":"DeploymentStatus","code":"custom","message":"This deployment has reached the maximum number of statuses."}],"documentation_url":"https://docs.github.com/rest/deployments/statuses#create-a-deployment-status","status":"422"}

@ben-grande

ben-grande commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

It "worked" (but see the failure there, merge conflict):

Ok, github broke the search syntax

https://doc.qubes-os.org/en/latest/developer/debugging/automated-tests.html#add-label-to-your-pr-on-github

org:QubesOS is:pr is:open label:openqa-group-1

https://github.com/search?q=org%3AQubesOS+is%3Apr+label%3Aopenqa-group-2+is%3Aopen&type=code

Some qualifiers in your query (is:pr, label) are not supported when searching code. Try searching for pull requests instead?

The new URL is:

https://github.com/search?q=org%3AQubesOS+is%3Apr+label%3Aopenqa-group-2+is%3Aopen&type=pullrequests&query=org%3AQubesOS+is%3Apr+label%3Aopenqa-group-2+is%3Aopen

And if you notice, the type=pullrequests is not part of the query, requiring a click on the link, rather than allowing us to provide a human readable search syntax, which I expected to have less change of breaking.

@marmarek
marmarek merged commit 8c5c6eb into QubesOS:main Aug 8, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants