mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-05-04 20:51:49 +02:00
Compare commits
8 commits
9380af1c2a
...
0d78f4d455
Author | SHA1 | Date | |
---|---|---|---|
0d78f4d455 | |||
![]() |
504a9e1df2 | ||
![]() |
3b3f02528a | ||
![]() |
ca3e634b49 | ||
![]() |
0bb13f9d7b | ||
![]() |
10c52dbf8c | ||
![]() |
1f42d68259 | ||
![]() |
3a1b41f988 |
9 changed files with 538 additions and 332 deletions
5
BUILD.md
5
BUILD.md
|
@ -260,11 +260,16 @@ The following instructions require typing commands in a terminal in dom0.
|
|||
|
||||
```
|
||||
qvm-create --class AppVM --label red --template fedora-40-dz dz
|
||||
qvm-volume resize dz:private $(numfmt --from=auto 5Gi)
|
||||
```
|
||||
|
||||
> :bulb: Alternatively, you can use a different app qube for Dangerzone
|
||||
> development. In that case, replace `dz` with the qube of your choice in the
|
||||
> steps below.
|
||||
>
|
||||
> In the commands above, we also resize the private volume of the `dz` qube
|
||||
> to 5GiB, since the Tesseract data that will be downloaded in the next steps
|
||||
> take a bit of space.
|
||||
|
||||
4. Add an RPC policy (`/etc/qubes/policy.d/50-dangerzone.policy`) that will
|
||||
allow launching a disposable qube (`dz-dvm`) when Dangerzone converts a
|
||||
|
|
197
QA.md
Normal file
197
QA.md
Normal file
|
@ -0,0 +1,197 @@
|
|||
## QA
|
||||
|
||||
To ensure that new releases do not introduce regressions, and support existing
|
||||
and newer platforms, we have to test that the produced packages work as expected.
|
||||
|
||||
Check the following:
|
||||
|
||||
- [ ] Make sure that the tip of the `main` branch passes the CI tests.
|
||||
- [ ] Make sure that the Apple account has a valid application password and has
|
||||
agreed to the latest Apple terms (see [macOS release](#macos-release)
|
||||
section).
|
||||
|
||||
Because it is repetitive, we wrote a script to help with the QA.
|
||||
It can run the tasks for you, pausing when it needs manual intervention.
|
||||
|
||||
You can run it with a command like:
|
||||
|
||||
```bash
|
||||
poetry run ./dev_scripts/qa.py {distro}-{version}
|
||||
```
|
||||
|
||||
### The checklist
|
||||
|
||||
- [ ] Create a test build in Windows and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Build and run the Dangerzone .exe
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in macOS (Intel CPU) and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in macOS (M1/2 CPU) and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Ubuntu LTS platform (Ubuntu 24.04
|
||||
as of writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create a .deb package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Fedora platform (Fedora 41 as of
|
||||
writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create an .rpm package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Qubes Fedora template (Fedora 40 as
|
||||
of writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create a Qubes .rpm package and install it system-wide.
|
||||
- [ ] Ensure that the Dangerzone application appears in the "Applications"
|
||||
tab.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below) and make sure
|
||||
they spawn disposable qubes.
|
||||
|
||||
### Scenarios
|
||||
|
||||
#### 1. Dangerzone correctly identifies that Docker/Podman is not installed
|
||||
|
||||
_(Only for MacOS / Windows)_
|
||||
|
||||
Temporarily hide the Docker/Podman binaries, e.g., rename the `docker` /
|
||||
`podman` binaries to something else. Then run Dangerzone. Dangerzone should
|
||||
prompt the user to install Docker/Podman.
|
||||
|
||||
#### 2. Dangerzone correctly identifies that Docker is not running
|
||||
|
||||
_(Only for MacOS / Windows)_
|
||||
|
||||
Stop the Docker Desktop application. Then run Dangerzone. Dangerzone should
|
||||
prompt the user to start Docker Desktop.
|
||||
|
||||
|
||||
#### 3. Updating Dangerzone handles external state correctly.
|
||||
|
||||
_(Applies to Windows/MacOS)_
|
||||
|
||||
Install the previous version of Dangerzone, downloaded from the website.
|
||||
|
||||
Open the Dangerzone application and enable some non-default settings.
|
||||
**If there are new settings, make sure to change those as well**.
|
||||
|
||||
Close the Dangerzone application and get the container image for that
|
||||
version. For example:
|
||||
|
||||
```
|
||||
$ docker images dangerzone.rocks/dangerzone:latest
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
dangerzone.rocks/dangerzone latest <image ID> <date> <size>
|
||||
```
|
||||
|
||||
Then run the version under QA and ensure that the settings remain changed.
|
||||
|
||||
Afterwards check that new docker image was installed by running the same command
|
||||
and seeing the following differences:
|
||||
|
||||
```
|
||||
$ docker images dangerzone.rocks/dangerzone:latest
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
|
||||
```
|
||||
|
||||
#### 4. Dangerzone successfully installs the container image
|
||||
|
||||
_(Only for Linux)_
|
||||
|
||||
Remove the Dangerzone container image from Docker/Podman. Then run Dangerzone.
|
||||
Dangerzone should install the container image successfully.
|
||||
|
||||
#### 5. Dangerzone retains the settings of previous runs
|
||||
|
||||
Run Dangerzone and make some changes in the settings (e.g., change the OCR
|
||||
language, toggle whether to open the document after conversion, etc.). Restart
|
||||
Dangerzone. Dangerzone should show the settings that the user chose.
|
||||
|
||||
#### 6. Dangerzone reports failed conversions
|
||||
|
||||
Run Dangerzone and convert the `tests/test_docs/sample_bad_pdf.pdf` document.
|
||||
Dangerzone should fail gracefully, by reporting that the operation failed, and
|
||||
showing the following error message:
|
||||
|
||||
> The document format is not supported
|
||||
|
||||
#### 7. Dangerzone succeeds in converting multiple documents
|
||||
|
||||
Run Dangerzone against a list of documents, and tick all options. Ensure that:
|
||||
* Conversions take place sequentially.
|
||||
* Attempting to close the window while converting asks the user if they want to
|
||||
abort the conversions.
|
||||
* Conversions are completed successfully.
|
||||
* Conversions show individual progress in real-time (double-check for Qubes).
|
||||
* _(Only for Linux)_ The resulting files open with the PDF viewer of our choice.
|
||||
* OCR seems to have detected characters in the PDF files.
|
||||
* The resulting files have been saved with the proper suffix, in the proper
|
||||
location.
|
||||
* The original files have been saved in the `unsafe/` directory.
|
||||
|
||||
#### 8. Dangerzone is able to handle drag-n-drop
|
||||
|
||||
Run Dangerzone against a set of documents that you drag-n-drop. Files should be
|
||||
added and conversion should run without issue.
|
||||
|
||||
> [!TIP]
|
||||
> On our end-user container environments for Linux, we can start a file manager
|
||||
> with `thunar &`.
|
||||
|
||||
#### 9. Dangerzone CLI succeeds in converting multiple documents
|
||||
|
||||
_(Only for Windows and Linux)_
|
||||
|
||||
Run Dangerzone CLI against a list of documents. Ensure that conversions happen
|
||||
sequentially, are completed successfully, and we see their progress.
|
||||
|
||||
#### 10. Dangerzone can open a document for conversion via right-click -> "Open With"
|
||||
|
||||
_(Only for Windows, MacOS and Qubes)_
|
||||
|
||||
Go to a directory with office documents, right-click on one, and click on "Open
|
||||
With". We should be able to open the file with Dangerzone, and then convert it.
|
||||
|
||||
#### 11. Dangerzone shows helpful errors for setup issues on Qubes
|
||||
|
||||
_(Only for Qubes)_
|
||||
|
||||
Check what errors does Dangerzone throw in the following scenarios. The errors
|
||||
should point the user to the Qubes notifications in the top-right corner:
|
||||
|
||||
1. The `dz-dvm` template does not exist. We can trigger this scenario by
|
||||
temporarily renaming this template.
|
||||
2. The Dangerzone RPC policy does not exist. We can trigger this scenario by
|
||||
temporarily renaming the `dz.Convert` policy.
|
||||
3. The `dz-dvm` disposable Qube cannot start due to insufficient resources. We
|
||||
can trigger this scenario by temporarily increasing the minimum required RAM
|
||||
of the `dz-dvm` template to more than the available amount.
|
|
@ -6,7 +6,7 @@ Take potentially dangerous PDFs, office documents, or images and convert them to
|
|||
|  | 
|
||||
|--|--|
|
||||
|
||||
Dangerzone works like this: You give it a document that you don't know if you can trust (for example, an email attachment). Inside of a sandbox, Dangerzone converts the document to a PDF (if it isn't already one), and then converts the PDF into raw pixel data: a huge list of RGB color values for each page. Then, in a separate sandbox, Dangerzone takes this pixel data and converts it back into a PDF.
|
||||
Dangerzone works like this: You give it a document that you don't know if you can trust (for example, an email attachment). Inside of a sandbox, Dangerzone converts the document to a PDF (if it isn't already one), and then converts the PDF into raw pixel data: a huge list of RGB color values for each page. Then, outside of the sandbox, Dangerzone takes this pixel data and converts it back into a PDF.
|
||||
|
||||
_Read more about Dangerzone in the [official site](https://dangerzone.rocks/about/)._
|
||||
|
||||
|
|
390
RELEASE.md
390
RELEASE.md
|
@ -1,12 +1,13 @@
|
|||
# Release instructions
|
||||
|
||||
This section documents the release process. Unless you're a dangerzone developer making a release, you'll probably never need to follow it.
|
||||
This section documents how we currently release Dangerzone for the different distributions we support.
|
||||
|
||||
## Pre-release
|
||||
|
||||
Before making a release, all of these should be complete:
|
||||
Here is a list of tasks that should be done before issuing the release:
|
||||
|
||||
- [ ] Copy the checkboxes from these instructions onto a new issue and call it **QA and Release version \<VERSION\>**
|
||||
- [ ] Create a new issue named **QA and Release for version \<VERSION\>**, to track the general progress.
|
||||
You can generate its content with the the `poetry run ./dev_scripts/generate-release-tasks.py` command.
|
||||
- [ ] [Add new Linux platforms and remove obsolete ones](https://github.com/freedomofpress/dangerzone/blob/main/RELEASE.md#add-new-platforms-and-remove-obsolete-ones)
|
||||
- [ ] Bump the Python dependencies using `poetry lock`
|
||||
- [ ] [Check for official PySide6 versions](https://github.com/freedomofpress/dangerzone/blob/main/RELEASE.md#check-for-official-pyside6-versions)
|
||||
|
@ -16,6 +17,8 @@ Before making a release, all of these should be complete:
|
|||
- [ ] Bump the Debian version by adding a new changelog entry in `debian/changelog`
|
||||
- [ ] Update screenshot in `README.md`, if necessary
|
||||
- [ ] CHANGELOG.md should be updated to include a list of all major changes since the last release
|
||||
- [ ] A draft release should be created. Copy the release notes text from the template at [`docs/templates/release-notes`](https://github.com/freedomofpress/dangerzone/tree/main/docs/templates/)
|
||||
- [ ] Do the QA tasks
|
||||
|
||||
## Add new Linux platforms and remove obsolete ones
|
||||
|
||||
|
@ -38,7 +41,7 @@ In case of a new version (beta, RC, or official release):
|
|||
`BUILD.md` files where necessary.
|
||||
4. Send a PR with the above changes.
|
||||
|
||||
In case of an EOL version:
|
||||
In case of the removal of a version:
|
||||
|
||||
1. Remove any mention to this version from our repo.
|
||||
* Consult the previous paragraph, but also `grep` your way around.
|
||||
|
@ -62,192 +65,13 @@ Follow the instructions in `docs/developer/TESTING.md` to run the tests.
|
|||
|
||||
These tests will identify any regressions or progression in terms of document coverage.
|
||||
|
||||
## QA
|
||||
|
||||
To ensure that new releases do not introduce regressions, and support existing
|
||||
and newer platforms, we have to do the following:
|
||||
|
||||
- [ ] Make sure that the tip of the `main` branch passes the CI tests.
|
||||
- [ ] Make sure that the Apple account has a valid application password and has
|
||||
agreed to the latest Apple terms (see [macOS release](#macos-release)
|
||||
section).
|
||||
- [ ] Create a test build in Windows and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Build and run the Dangerzone .exe
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in macOS (Intel CPU) and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in macOS (M1/2 CPU) and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Ubuntu LTS platform (Ubuntu 24.04
|
||||
as of writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create a .deb package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Fedora platform (Fedora 41 as of
|
||||
writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create an .rpm package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
- [ ] Create a test build in the most recent Qubes Fedora template (Fedora 40 as
|
||||
of writing this) and make sure it works:
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create a Qubes .rpm package and install it system-wide.
|
||||
- [ ] Ensure that the Dangerzone application appears in the "Applications"
|
||||
tab.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below) and make sure
|
||||
they spawn disposable qubes.
|
||||
|
||||
### Scenarios
|
||||
|
||||
#### 1. Dangerzone correctly identifies that Docker/Podman is not installed
|
||||
|
||||
_(Only for MacOS / Windows)_
|
||||
|
||||
Temporarily hide the Docker/Podman binaries, e.g., rename the `docker` /
|
||||
`podman` binaries to something else. Then run Dangerzone. Dangerzone should
|
||||
prompt the user to install Docker/Podman.
|
||||
|
||||
#### 2. Dangerzone correctly identifies that Docker is not running
|
||||
|
||||
_(Only for MacOS / Windows)_
|
||||
|
||||
Stop the Docker Desktop application. Then run Dangerzone. Dangerzone should
|
||||
prompt the user to start Docker Desktop.
|
||||
|
||||
|
||||
#### 3. Updating Dangerzone handles external state correctly.
|
||||
|
||||
_(Applies to Windows/MacOS)_
|
||||
|
||||
Install the previous version of Dangerzone, downloaded from the website.
|
||||
|
||||
Open the Dangerzone application and enable some non-default settings.
|
||||
**If there are new settings, make sure to change those as well**.
|
||||
|
||||
Close the Dangerzone application and get the container image for that
|
||||
version. For example:
|
||||
|
||||
```
|
||||
$ docker images dangerzone.rocks/dangerzone:latest
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
dangerzone.rocks/dangerzone latest <image ID> <date> <size>
|
||||
```
|
||||
|
||||
Then run the version under QA and ensure that the settings remain changed.
|
||||
|
||||
Afterwards check that new docker image was installed by running the same command
|
||||
and seeing the following differences:
|
||||
|
||||
```
|
||||
$ docker images dangerzone.rocks/dangerzone:latest
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
|
||||
```
|
||||
|
||||
#### 4. Dangerzone successfully installs the container image
|
||||
|
||||
_(Only for Linux)_
|
||||
|
||||
Remove the Dangerzone container image from Docker/Podman. Then run Dangerzone.
|
||||
Dangerzone should install the container image successfully.
|
||||
|
||||
#### 5. Dangerzone retains the settings of previous runs
|
||||
|
||||
Run Dangerzone and make some changes in the settings (e.g., change the OCR
|
||||
language, toggle whether to open the document after conversion, etc.). Restart
|
||||
Dangerzone. Dangerzone should show the settings that the user chose.
|
||||
|
||||
#### 6. Dangerzone reports failed conversions
|
||||
|
||||
Run Dangerzone and convert the `tests/test_docs/sample_bad_pdf.pdf` document.
|
||||
Dangerzone should fail gracefully, by reporting that the operation failed, and
|
||||
showing the following error message:
|
||||
|
||||
> The document format is not supported
|
||||
|
||||
#### 7. Dangerzone succeeds in converting multiple documents
|
||||
|
||||
Run Dangerzone against a list of documents, and tick all options. Ensure that:
|
||||
* Conversions take place sequentially.
|
||||
* Attempting to close the window while converting asks the user if they want to
|
||||
abort the conversions.
|
||||
* Conversions are completed successfully.
|
||||
* Conversions show individual progress in real-time (double-check for Qubes).
|
||||
* _(Only for Linux)_ The resulting files open with the PDF viewer of our choice.
|
||||
* OCR seems to have detected characters in the PDF files.
|
||||
* The resulting files have been saved with the proper suffix, in the proper
|
||||
location.
|
||||
* The original files have been saved in the `unsafe/` directory.
|
||||
|
||||
#### 8. Dangerzone is able to handle drag-n-drop
|
||||
|
||||
Run Dangerzone against a set of documents that you drag-n-drop. Files should be
|
||||
added and conversion should run without issue.
|
||||
|
||||
> [!TIP]
|
||||
> On our end-user container environments for Linux, we can start a file manager
|
||||
> with `thunar &`.
|
||||
|
||||
#### 9. Dangerzone CLI succeeds in converting multiple documents
|
||||
|
||||
_(Only for Windows and Linux)_
|
||||
|
||||
Run Dangerzone CLI against a list of documents. Ensure that conversions happen
|
||||
sequentially, are completed successfully, and we see their progress.
|
||||
|
||||
#### 10. Dangerzone can open a document for conversion via right-click -> "Open With"
|
||||
|
||||
_(Only for Windows, MacOS and Qubes)_
|
||||
|
||||
Go to a directory with office documents, right-click on one, and click on "Open
|
||||
With". We should be able to open the file with Dangerzone, and then convert it.
|
||||
|
||||
#### 11. Dangerzone shows helpful errors for setup issues on Qubes
|
||||
|
||||
_(Only for Qubes)_
|
||||
|
||||
Check what errors does Dangerzone throw in the following scenarios. The errors
|
||||
should point the user to the Qubes notifications in the top-right corner:
|
||||
|
||||
1. The `dz-dvm` template does not exist. We can trigger this scenario by
|
||||
temporarily renaming this template.
|
||||
2. The Dangerzone RPC policy does not exist. We can trigger this scenario by
|
||||
temporarily renaming the `dz.Convert` policy.
|
||||
3. The `dz-dvm` disposable Qube cannot start due to insufficient resources. We
|
||||
can trigger this scenario by temporarily increasing the minimum required RAM
|
||||
of the `dz-dvm` template to more than the available amount.
|
||||
|
||||
## Release
|
||||
|
||||
Once we are confident that the release will be out shortly, and doesn't need any more changes:
|
||||
|
||||
- [ ] Create a PGP-signed git tag for the version, e.g., for dangerzone `v0.1.0`:
|
||||
|
||||
```
|
||||
```bash
|
||||
git tag -s v0.1.0
|
||||
git push origin v0.1.0
|
||||
```
|
||||
|
@ -263,6 +87,8 @@ Once we are confident that the release will be out shortly, and doesn't need any
|
|||
|
||||
### macOS Release
|
||||
|
||||
This needs to happen for both Silicon and Intel chipsets.
|
||||
|
||||
#### Initial Setup
|
||||
|
||||
- Build machine must have:
|
||||
|
@ -277,48 +103,87 @@ Once we are confident that the release will be out shortly, and doesn't need any
|
|||
|
||||
#### Releasing and Signing
|
||||
|
||||
Here is what you need to do:
|
||||
|
||||
- [ ] Verify and install the latest supported Python version from
|
||||
[python.org](https://www.python.org/downloads/macos/) (do not use the one from
|
||||
brew as it is known to [cause issues](https://github.com/freedomofpress/dangerzone/issues/471))
|
||||
* In case of a new Python installation or minor version upgrade, e.g., from
|
||||
3.11 to 3.12 , reinstall Poetry with `python3 -m pip install poetry`
|
||||
* You can verify the correct Python version is used with `poetry debug info`
|
||||
- [ ] Verify and checkout the git tag for this release
|
||||
- [ ] Run `poetry install --sync`
|
||||
- [ ] On the silicon mac, build the container image:
|
||||
|
||||
- [ ] Checkout the dependencies, and clean your local copy:
|
||||
|
||||
```bash
|
||||
|
||||
# In case of a new Python installation or minor version upgrade, e.g., from
|
||||
# 3.11 to 3.12, reinstall Poetry
|
||||
python3 -m pip install poetry
|
||||
|
||||
# You can verify the correct Python version is used
|
||||
poetry debug info
|
||||
|
||||
# Replace with the actual version
|
||||
export DZ_VERSION=$(cat share/version.txt)
|
||||
|
||||
# Verify and checkout the git tag for this release:
|
||||
git checkout v$VERSION
|
||||
|
||||
# Clean the git repository
|
||||
git clean -df
|
||||
|
||||
# Clean up the environment
|
||||
poetry env remove --all
|
||||
|
||||
# Install the dependencies
|
||||
poetry install --sync
|
||||
```
|
||||
python3 ./install/common/build-image.py
|
||||
|
||||
- [ ] Only on Silicon Mac, build the container image and the OCR language data
|
||||
|
||||
```bash
|
||||
# ONLY ON SILICON MAC,
|
||||
# It should already be built on the Intel one.
|
||||
poetry run ./install/common/build-image.py
|
||||
poetry run ./install/common/download-tessdata.py
|
||||
|
||||
# Copy the container image to the assets folder
|
||||
cp share/container.tar.gz ~dz/release-assets/$VERSION/dangerzone-$VERSION-arm64.tar.gz
|
||||
cp share/image-id.txt ~dz/release-assets/$VERSION/.
|
||||
```
|
||||
Then copy the `share/container.tar.gz` to the assets folder on `dangerzone-$VERSION-arm64.tar.gz`, along with the `share/image-id.txt` file.
|
||||
- [ ] Run `poetry run ./install/macos/build-app.py`; this will make `dist/Dangerzone.app`
|
||||
|
||||
- [ ] Build the app bundle
|
||||
|
||||
```bash
|
||||
poetry run ./install/macos/build-app.py
|
||||
```
|
||||
|
||||
- [ ] Make sure that the build application works with the containerd graph
|
||||
driver (see [#933](https://github.com/freedomofpress/dangerzone/issues/933))
|
||||
- [ ] Run `poetry run ./install/macos/build-app.py --only-codesign`; this will make `dist/Dangerzone.dmg`
|
||||
* You need to run this command as the account that has access to the code signing certificate
|
||||
* You must run this command from the MacOS UI, from a terminal application.
|
||||
- [ ] Notarize it: `xcrun notarytool submit --wait --apple-id "<email>" --keychain-profile "dz-notarytool-release-key" dist/Dangerzone.dmg`
|
||||
* You need to change the `<email>` in the above command with the email
|
||||
associated with the Apple Developer ID.
|
||||
* This command assumes that you have created, and stored in the Keychain, an
|
||||
application password associated with your Apple Developer ID, which will be
|
||||
used specifically for `notarytool`.
|
||||
- [ ] Wait for it to get approved:
|
||||
* If it gets rejected, you should be able to see why with the same command
|
||||
(or use the `log` option for a more verbose JSON output)
|
||||
* You will also receive an update in your email.
|
||||
- [ ] After it's approved, staple the ticket: `xcrun stapler staple dist/Dangerzone.dmg`
|
||||
- [ ] Sign the application bundle, and notarize it
|
||||
|
||||
You need to run this command as the account that has access to the code signing certificate
|
||||
|
||||
This command assumes that you have created, and stored in the Keychain, an
|
||||
application password associated with your Apple Developer ID, which will be
|
||||
used specifically for `notarytool`.
|
||||
|
||||
This process ends up with the final file:
|
||||
```bash
|
||||
# Sign the .App and make it a .dmg
|
||||
poetry run ./install/macos/build-app.py --only-codesign
|
||||
|
||||
```
|
||||
dist/Dangerzone.dmg
|
||||
```
|
||||
# Notarize it. You must run this command from the MacOS UI
|
||||
# from a terminal application.
|
||||
xcrun notarytool submit ./dist/Dangerzone.dmg --apple-id $APPLE_ID --keychain-profile "dz-notarytool-release-key" --wait && xcrun stapler staple dist/Dangerzone.dmg
|
||||
|
||||
Rename `Dangerzone.dmg` to `Dangerzone-$VERSION.dmg`.
|
||||
# Copy the .dmg to the assets folder
|
||||
ARCH=$(uname -m)
|
||||
if [ "$ARCH" = "x86_64" ]; then
|
||||
ARCH="i686"
|
||||
fi
|
||||
cp dist/Dangerzone.dmg ~dz/release-assets/$VERSION/Dangerzone-$VERSION-$ARCH.dmg
|
||||
```
|
||||
|
||||
### Windows Release
|
||||
|
||||
The Windows release is performed in a Windows 11 virtual machine as opposed to a physical one.
|
||||
The Windows release is performed in a Windows 11 virtual machine (as opposed to a physical one).
|
||||
|
||||
#### Initial Setup
|
||||
|
||||
|
@ -332,8 +197,30 @@ The Windows release is performed in a Windows 11 virtual machine as opposed to a
|
|||
|
||||
#### Releasing and Signing
|
||||
|
||||
- [ ] Verify and checkout the git tag for this release
|
||||
- [ ] Run `poetry install --sync`
|
||||
```bash
|
||||
# In case of a new Python installation or minor version upgrade, e.g., from
|
||||
# 3.11 to 3.12, reinstall Poetry
|
||||
python3 -m pip install poetry
|
||||
|
||||
# You can verify the correct Python version is used
|
||||
poetry debug info
|
||||
|
||||
# Replace with the actual version
|
||||
export DZ_VERSION=$(cat share/version.txt)
|
||||
|
||||
# Verify and checkout the git tag for this release:
|
||||
git checkout v$VERSION
|
||||
|
||||
# Clean the git repository
|
||||
git clean -df
|
||||
|
||||
# Clean up the environment
|
||||
poetry env remove --all
|
||||
|
||||
# Install the dependencies
|
||||
poetry install --sync
|
||||
```
|
||||
|
||||
- [ ] Copy the container image into the VM
|
||||
> [!IMPORTANT]
|
||||
> Instead of running `python .\install\windows\build-image.py` in the VM, run the build image script on the host (making sure to build for `linux/amd64`). Copy `share/container.tar.gz` and `share/image-id.txt` from the host into the `share` folder in the VM.
|
||||
|
@ -365,21 +252,15 @@ instructions in our build section](https://github.com/freedomofpress/dangerzone/
|
|||
or create your own locally with:
|
||||
|
||||
```sh
|
||||
# Create and run debian bookworm development environment
|
||||
./dev_scripts/env.py --distro debian --version bookworm build-dev
|
||||
./dev_scripts/env.py --distro debian --version bookworm run --dev bash
|
||||
cd dangerzone
|
||||
```
|
||||
|
||||
Build the latest container:
|
||||
# Build the latest container
|
||||
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c "cd dangerzone && poetry run ./install/common/build-image.py"
|
||||
|
||||
```sh
|
||||
python3 ./install/common/build-image.py
|
||||
```
|
||||
|
||||
Create a .deb:
|
||||
|
||||
```sh
|
||||
./install/linux/build-deb.py
|
||||
# Create a .deb
|
||||
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c "cd dangerzone && ./install/linux/build-deb.py"
|
||||
```
|
||||
|
||||
Publish the .deb under `./deb_dist` to the
|
||||
|
@ -398,22 +279,12 @@ or create your own locally with:
|
|||
|
||||
```sh
|
||||
./dev_scripts/env.py --distro fedora --version 41 build-dev
|
||||
./dev_scripts/env.py --distro fedora --version 41 run --dev bash
|
||||
cd dangerzone
|
||||
```
|
||||
|
||||
Build the latest container:
|
||||
# Build the latest container (skip if already built):
|
||||
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && poetry run ./install/common/build-image.py"
|
||||
|
||||
```sh
|
||||
python3 ./install/common/build-image.py
|
||||
```
|
||||
|
||||
Copy the container image to the assets folder on `dangerzone-$VERSION-i686.tar.gz`.
|
||||
|
||||
Create a .rpm:
|
||||
|
||||
```sh
|
||||
./install/linux/build-rpm.py
|
||||
# Create a .rpm:
|
||||
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./install/linux/build-rpm.py"
|
||||
```
|
||||
|
||||
Publish the .rpm under `./dist` to the
|
||||
|
@ -424,7 +295,7 @@ Publish the .rpm under `./dist` to the
|
|||
Create a .rpm for Qubes:
|
||||
|
||||
```sh
|
||||
./install/linux/build-rpm.py --qubes
|
||||
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./install/linux/build-rpm.py --qubes"
|
||||
```
|
||||
|
||||
and similarly publish it to the [`freedomofpress/yum-tools-prod`](https://github.com/freedomofpress/yum-tools-prod)
|
||||
|
@ -432,36 +303,37 @@ repo.
|
|||
|
||||
## Publishing the Release
|
||||
|
||||
To publish the release:
|
||||
To publish the release, you can follow these steps:
|
||||
|
||||
- [ ] Create an archive of the Dangerzone source in `tar.gz` format:
|
||||
* You can use the following command:
|
||||
|
||||
```
|
||||
export DZ_VERSION=$(cat share/version.txt)
|
||||
git archive --format=tar.gz -o dangerzone-${DZ_VERSION:?}.tar.gz --prefix=dangerzone/ v${DZ_VERSION:?}
|
||||
```
|
||||
```bash
|
||||
export VERSION=$(cat share/version.txt)
|
||||
git archive --format=tar.gz -o dangerzone-${VERSION:?}.tar.gz --prefix=dangerzone/ v${VERSION:?}
|
||||
```
|
||||
|
||||
- [ ] Run container scan on the produced container images (some time may have passed since the artifacts were built)
|
||||
```
|
||||
```bash
|
||||
gunzip --keep -c ./share/container.tar.gz > /tmp/container.tar
|
||||
docker pull anchore/grype:latest
|
||||
docker run --rm -v /tmp/container.tar:/container.tar anchore/grype:latest /container.tar
|
||||
```
|
||||
|
||||
- [ ] Collect the assets in a single directory, calculate their SHA-256 hashes, and sign them.
|
||||
* You can use `./dev_scripts/sign-assets.py`, if you want to automate this
|
||||
task.
|
||||
- [ ] Create a new **draft** release on GitHub and upload the macOS and Windows installers.
|
||||
* Copy the release notes text from the template at [`docs/templates/release-notes`](https://github.com/freedomofpress/dangerzone/tree/main/docs/templates/)
|
||||
* You can use `./dev_scripts/upload-asset.py`, if you want to upload an asset
|
||||
using an access token.
|
||||
- [ ] Upload the `container-$VERSION-i686.tar.gz` and `container-$VERSION-arm64.tar.gz` images that were created in the previous step
|
||||
There is an `./dev_scripts/sign-assets.py` script to automate this task.
|
||||
|
||||
**Important:** Make sure that it's the same container images as the ones that
|
||||
are shipped in other platforms (see our [Pre-release](#Pre-release) section)
|
||||
**Important:** Before running the script, make sure that it's the same container images as
|
||||
the ones that are shipped in other platforms (see our [Pre-release](#Pre-release) section)
|
||||
|
||||
```bash
|
||||
# Sign all the assets
|
||||
./dev_scripts/sign-assets.py ~/release-assets/$VERSION/github --version $VERSION
|
||||
```
|
||||
|
||||
- [ ] Upload all the assets to the draft release on GitHub.
|
||||
```bash
|
||||
find ~/release-assets/$VERSION/github | xargs -n1 ./dev_scripts/upload-asset.py --token ~/token --draft
|
||||
```
|
||||
|
||||
- [ ] Upload the detached signatures (.asc) and checksum file.
|
||||
- [ ] Update the [Dangerzone website](https://github.com/freedomofpress/dangerzone.rocks) to link to the new installers.
|
||||
- [ ] Update the brew cask release of Dangerzone with a [PR like this one](https://github.com/Homebrew/homebrew-cask/pull/116319)
|
||||
- [ ] Update version and download links in `README.md`
|
||||
|
|
60
dev_scripts/generate-release-tasks.py
Executable file
60
dev_scripts/generate-release-tasks.py
Executable file
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python3
|
||||
import pathlib
|
||||
import subprocess
|
||||
|
||||
RELEASE_FILE = "RELEASE.md"
|
||||
QA_FILE = "QA.md"
|
||||
|
||||
def git_root():
|
||||
"""Get the root directory of the Git repo."""
|
||||
# FIXME: Use a Git Python binding for this.
|
||||
# FIXME: Make this work if called outside the repo.
|
||||
path = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode().strip("\n")
|
||||
return pathlib.Path(path)
|
||||
|
||||
def extract_checkboxes(filename):
|
||||
headers = []
|
||||
result = []
|
||||
|
||||
with open(filename, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
current_level = 0
|
||||
for line in lines:
|
||||
line = line.rstrip()
|
||||
|
||||
# If it's a header, store it
|
||||
if line.startswith('#'):
|
||||
# Count number of # to determine header level
|
||||
level = len(line) - len(line.lstrip('#'))
|
||||
if level < current_level or not current_level:
|
||||
headers.extend(['', line, ''])
|
||||
current_level = level
|
||||
elif level > current_level:
|
||||
continue
|
||||
else:
|
||||
headers = ['', line, '']
|
||||
|
||||
# If it's a checkbox
|
||||
elif '- [ ]' in line or '- [x]' in line or '- [X]' in line:
|
||||
# Print the last header if we haven't already
|
||||
if headers:
|
||||
result.extend(headers)
|
||||
headers = []
|
||||
current_level = 0
|
||||
|
||||
# If this is the "Do the QA tasks" line, recursively get QA tasks
|
||||
if "Do the QA tasks" in line:
|
||||
result.append(line)
|
||||
qa_tasks = extract_checkboxes(git_root() / QA_FILE)
|
||||
result.append(qa_tasks)
|
||||
else:
|
||||
result.append(line)
|
||||
return '\n'.join(result)
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(extract_checkboxes(git_root() / RELEASE_FILE))
|
|
@ -3,28 +3,49 @@
|
|||
import abc
|
||||
import argparse
|
||||
import difflib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import selectors
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PYTHON_VERSION_STR = "3.12"
|
||||
PYTHON_VERSION = [int(num) for num in PYTHON_VERSION_STR.split(".")]
|
||||
EOL_PYTHON_URL = "https://endoflife.date/api/python.json"
|
||||
|
||||
CONTENT_QA = r"""## QA
|
||||
|
||||
To ensure that new releases do not introduce regressions, and support existing
|
||||
and newer platforms, we have to do the following:
|
||||
and newer platforms, we have to test that the produced packages work as expected.
|
||||
|
||||
Check the following:
|
||||
|
||||
- [ ] Make sure that the tip of the `main` branch passes the CI tests.
|
||||
- [ ] Make sure that the Apple account has a valid application password and has
|
||||
agreed to the latest Apple terms (see [macOS release](#macos-release)
|
||||
section).
|
||||
|
||||
Because it is repetitive, we wrote a script to help with the QA.
|
||||
It can run the tasks for you, pausing when it needs manual intervention.
|
||||
|
||||
You can run it with a command like:
|
||||
|
||||
```bash
|
||||
poetry run ./dev_scripts/qa.py {distro}-{version}
|
||||
```
|
||||
|
||||
### The checklist
|
||||
|
||||
- [ ] Create a test build in Windows and make sure it works:
|
||||
- [ ] Check if the suggested Python version is still supported.
|
||||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Build and run the Dangerzone .exe
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
|
@ -33,6 +54,7 @@ and newer platforms, we have to do the following:
|
|||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
|
@ -41,6 +63,7 @@ and newer platforms, we have to do the following:
|
|||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create and run an app bundle.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
|
@ -49,6 +72,7 @@ and newer platforms, we have to do the following:
|
|||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create a .deb package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
|
@ -57,6 +81,7 @@ and newer platforms, we have to do the following:
|
|||
- [ ] Create a new development environment with Poetry.
|
||||
- [ ] Build the container image and ensure the development environment uses
|
||||
the new image.
|
||||
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
|
||||
- [ ] Run the Dangerzone tests.
|
||||
- [ ] Create an .rpm package and install it system-wide.
|
||||
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
|
||||
|
@ -547,7 +572,7 @@ class Reference:
|
|||
# Convert spaces to dashes
|
||||
anchor = anchor.replace(" ", "-")
|
||||
# Remove non-alphanumeric (except dash and underscore)
|
||||
anchor = re.sub("[^a-zA-Z\-_]", "", anchor)
|
||||
anchor = re.sub("[^a-zA-Z-_]", "", anchor)
|
||||
|
||||
return anchor
|
||||
|
||||
|
@ -566,8 +591,8 @@ class QABase(abc.ABC):
|
|||
|
||||
platforms = {}
|
||||
|
||||
REF_QA = Reference("RELEASE.md", content=CONTENT_QA)
|
||||
REF_QA_SCENARIOS = Reference("RELEASE.md", content=CONTENT_QA_SCENARIOS)
|
||||
REF_QA = Reference("QA.md", content=CONTENT_QA)
|
||||
REF_QA_SCENARIOS = Reference("QA.md", content=CONTENT_QA_SCENARIOS)
|
||||
|
||||
# The following class method is available since Python 3.6. For more details, see:
|
||||
# https://docs.python.org/3.6/whatsnew/3.6.html#pep-487-simpler-customization-of-class-creation
|
||||
|
@ -802,6 +827,26 @@ class QAWindows(QABase):
|
|||
while msvcrt.kbhit():
|
||||
msvcrt.getch()
|
||||
|
||||
@QABase.task(f"Install the latest version of Python {PYTHON_VERSION_STR}", ref=REF_BUILD)
|
||||
def install_python(self):
|
||||
cur_version = list(sys.version_info[:3])
|
||||
|
||||
logger.info("Getting latest Python release")
|
||||
with urllib.request.urlopen(EOL_PYTHON_URL) as f:
|
||||
resp = f.read()
|
||||
releases = json.loads(resp)
|
||||
for release in releases:
|
||||
if release["cycle"] == PYTHON_VERSION_STR:
|
||||
latest_version = [int(num) for num in release["latest"].split(".")]
|
||||
if latest_version > cur_version:
|
||||
self.prompt(f"You need to install the latest Python version ({release['latest']})")
|
||||
elif latest_version == cur_version:
|
||||
logger.info(f"Verified that the latest Python version ({release['latest']}) is installed")
|
||||
return
|
||||
|
||||
logger.error("Could not verify that the latest Python version is installed")
|
||||
|
||||
|
||||
@QABase.task("Install and Run Docker Desktop", ref=REF_BUILD)
|
||||
def install_docker(self):
|
||||
logger.info("Checking if Docker Desktop is installed and running")
|
||||
|
@ -816,12 +861,16 @@ class QAWindows(QABase):
|
|||
)
|
||||
def install_poetry(self):
|
||||
self.run("python", "-m", "pip", "install", "poetry")
|
||||
self.run("poetry", "install")
|
||||
self.run("poetry", "install", "--sync")
|
||||
|
||||
@QABase.task("Build Dangerzone container image", ref=REF_BUILD, auto=True)
|
||||
def build_image(self):
|
||||
self.run("python", r".\install\common\build-image.py")
|
||||
|
||||
@QABase.task("Download Tesseract data", ref=REF_BUILD, auto=True)
|
||||
def download_tessdata(self):
|
||||
self.run("python", r".\install\common\download-tessdata.py")
|
||||
|
||||
@QABase.task("Run tests", ref="REF_BUILD", auto=True)
|
||||
def run_tests(self):
|
||||
# NOTE: Windows does not have Makefile by default.
|
||||
|
@ -838,9 +887,11 @@ class QAWindows(QABase):
|
|||
return "windows"
|
||||
|
||||
def start(self):
|
||||
self.install_python()
|
||||
self.install_docker()
|
||||
self.install_poetry()
|
||||
self.build_image()
|
||||
self.download_tessdata()
|
||||
self.run_tests()
|
||||
self.build_dangerzone_exe()
|
||||
|
||||
|
@ -1005,6 +1056,10 @@ class QAFedora(QALinux):
|
|||
)
|
||||
|
||||
|
||||
class QAFedora41(QAFedora):
|
||||
VERSION = "41"
|
||||
|
||||
|
||||
class QAFedora40(QAFedora):
|
||||
VERSION = "40"
|
||||
|
||||
|
|
149
poetry.lock
generated
149
poetry.lock
generated
|
@ -220,73 +220,73 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.6.4"
|
||||
version = "7.6.7"
|
||||
description = "Code coverage measurement for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"},
|
||||
{file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"},
|
||||
{file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"},
|
||||
{file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"},
|
||||
{file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"},
|
||||
{file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"},
|
||||
{file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"},
|
||||
{file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"},
|
||||
{file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"},
|
||||
{file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"},
|
||||
{file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"},
|
||||
{file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"},
|
||||
{file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"},
|
||||
{file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"},
|
||||
{file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"},
|
||||
{file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"},
|
||||
{file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -865,6 +865,21 @@ pytest = "*"
|
|||
dev = ["pre-commit", "tox"]
|
||||
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-rerunfailures"
|
||||
version = "14.0"
|
||||
description = "pytest plugin to re-run tests to eliminate flaky failures"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-rerunfailures-14.0.tar.gz", hash = "sha256:4a400bcbcd3c7a4ad151ab8afac123d90eca3abe27f98725dc4d9702887d2e92"},
|
||||
{file = "pytest_rerunfailures-14.0-py3-none-any.whl", hash = "sha256:4197bdd2eaeffdbf50b5ea6e7236f47ff0e44d1def8dae08e409f536d84e7b32"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=17.1"
|
||||
pytest = ">=7.2"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-subprocess"
|
||||
version = "1.5.2"
|
||||
|
@ -945,13 +960,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "75.4.0"
|
||||
version = "75.5.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "setuptools-75.4.0-py3-none-any.whl", hash = "sha256:b3c5d862f98500b06ffdf7cc4499b48c46c317d8d56cb30b5c8bce4d88f5c216"},
|
||||
{file = "setuptools-75.4.0.tar.gz", hash = "sha256:1dc484f5cf56fd3fe7216d7b8df820802e7246cfb534a1db2aa64f14fcb9cdcb"},
|
||||
{file = "setuptools-75.5.0-py3-none-any.whl", hash = "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829"},
|
||||
{file = "setuptools-75.5.0.tar.gz", hash = "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -1084,4 +1099,4 @@ type = ["pytest-mypy"]
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.13"
|
||||
content-hash = "c1c1f32bef21cdea01a5b4b309bc1dfdc5766259cb552c7f38fe8ea8de6e9c38"
|
||||
content-hash = "44356eaeeb3dbe23b922413ee68f8c73c6ce8ebbdee8a80afecb410e060d0382"
|
||||
|
|
|
@ -52,6 +52,7 @@ pytest-qt = "^4.2.0"
|
|||
pytest-cov = "^5.0.0"
|
||||
strip-ansi = "*"
|
||||
pytest-subprocess = "^1.5.2"
|
||||
pytest-rerunfailures = "^14.0"
|
||||
|
||||
[tool.poetry.group.container.dependencies]
|
||||
pymupdf = "1.24.11" # Last version to support python 3.8 (needed for Ubuntu Focal support)
|
||||
|
|
|
@ -335,6 +335,7 @@ class TestCliConversion(TestCliBasic):
|
|||
|
||||
class TestExtraFormats(TestCli):
|
||||
@for_each_external_doc("*hwp*")
|
||||
@pytest.mark.flaky(reruns=2)
|
||||
def test_hancom_office(self, doc: str) -> None:
|
||||
if is_qubes_native_conversion():
|
||||
pytest.skip("HWP / HWPX formats are not supported on this platform")
|
||||
|
|
Loading…
Reference in a new issue