Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a90a1c967b | ||
|
|
e2c380acbc | ||
|
|
819d74f57c | ||
|
|
47e6a4bc88 | ||
|
|
09de0f4f06 | ||
|
|
f1e0c9cdd7 | ||
|
|
72d55a2938 | ||
|
|
3abb6245c1 | ||
|
|
a352e23d95 | ||
|
|
75a2036ea3 | ||
|
|
3d7642c09e | ||
|
|
fabbff2b60 | ||
|
|
751eddc0ce | ||
|
|
8df7aea949 | ||
|
|
bbc96e14c9 | ||
|
|
5695b7f58f | ||
|
|
a1c58a92e2 | ||
|
|
886a44b102 | ||
|
|
9b91c779e5 | ||
|
|
3697b2298c | ||
|
|
e861878a22 | ||
|
|
834fd8db05 | ||
|
|
fba1713944 | ||
|
|
b143121859 | ||
|
|
132cc056f6 | ||
|
|
f6e0896278 | ||
|
|
de4f060d3b | ||
|
|
14b7f91c5c | ||
|
|
5016ed3c8a | ||
|
|
d570366fb4 | ||
|
|
95ef33a102 | ||
|
|
fc11beac78 | ||
|
|
cb1fcecaf2 | ||
|
|
afdbdc55f7 | ||
|
|
28dfc39c02 | ||
|
|
793f246ebc | ||
|
|
9aa9ef5bbe | ||
|
|
6e18804c55 | ||
|
|
bca3c60bb3 |
@@ -0,0 +1,45 @@
|
||||
# see https://docs.codecov.io/docs/codecov-yaml
|
||||
# Validation check:
|
||||
# $ curl --data-binary @.codecov.yml https://codecov.io/validate
|
||||
|
||||
# https://docs.codecov.io/docs/codecovyml-reference
|
||||
codecov:
|
||||
bot: "codecov-io"
|
||||
strict_yaml_branch: "yaml-config"
|
||||
require_ci_to_pass: yes
|
||||
notify:
|
||||
# after_n_builds: 2
|
||||
wait_for_ci: yes
|
||||
|
||||
coverage:
|
||||
precision: 0 # 2 = xx.xx%, 0 = xx%
|
||||
round: nearest # how coverage is rounded: down/up/nearest
|
||||
range: 40...100 # custom range of coverage colors from red -> yellow -> green
|
||||
status:
|
||||
# https://codecov.readme.io/v1.0/docs/commit-status
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
target: 95% # specify the target coverage for each commit status
|
||||
threshold: 10% # allow this little decrease on project
|
||||
# https://github.com/codecov/support/wiki/Filtering-Branches
|
||||
# branches: master
|
||||
if_ci_failed: error
|
||||
# https://github.com/codecov/support/wiki/Patch-Status
|
||||
patch:
|
||||
default:
|
||||
informational: true
|
||||
target: 95% # enforce same coverage target for new/changed code as the project
|
||||
threshold: 10% # allow only a small decrease on patch coverage
|
||||
changes: false
|
||||
|
||||
# https://docs.codecov.com/docs/github-checks#disabling-github-checks-patch-annotations
|
||||
github_checks:
|
||||
annotations: false
|
||||
|
||||
|
||||
comment:
|
||||
layout: header, diff
|
||||
require_changes: false
|
||||
behavior: default # update if exists else create new
|
||||
# branches: *
|
||||
@@ -1,65 +1,68 @@
|
||||
name: 🐞 Bug Report
|
||||
# title: " "
|
||||
description: Problems with Supervision
|
||||
title: "[Bug]: "
|
||||
description: Report a bug or unexpected behavior in Supervision
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for submitting a Supervision 🐞 Bug Report!
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please search the [issues](https://github.com/roboflow/supervision/issues) to see if a similar bug report already exists.
|
||||
description: Please search [issues](https://github.com/roboflow/supervision/issues) and [discussions](https://github.com/roboflow/supervision/discussions) first.
|
||||
options:
|
||||
- label: >
|
||||
I have searched the Supervision [issues](https://github.com/roboflow/supervision/issues) and found no similar bug report.
|
||||
- label: I have searched the issues and discussions and found no similar bug report.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug
|
||||
description: Provide console output with error messages and/or screenshots of the bug.
|
||||
description: Describe the bug, what you expected, and what actually happened.
|
||||
placeholder: |
|
||||
💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response.
|
||||
**What's the bug?**
|
||||
Brief description...
|
||||
|
||||
**Expected behavior:**
|
||||
What should happen...
|
||||
|
||||
**Actual behavior:**
|
||||
What actually happens...
|
||||
|
||||
**Error/Traceback (if any):**
|
||||
```python
|
||||
# Paste error messages here
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Environment
|
||||
description: Please specify the software and hardware you used to produce the bug.
|
||||
description: Your setup details
|
||||
placeholder: |
|
||||
- Supervision: 0.1.0
|
||||
- OS: Ubuntu 20.04
|
||||
- Python: 3.8.10
|
||||
- Supervision: 0.23.0
|
||||
- Python: 3.10.12
|
||||
- OS: Ubuntu 22.04
|
||||
value: |
|
||||
- Supervision:
|
||||
- Python:
|
||||
- OS:
|
||||
validations:
|
||||
required: false
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Minimal Reproducible Example
|
||||
description: >
|
||||
When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to **reproduce** the problem.
|
||||
This is referred to by community members as creating a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example).
|
||||
description: Code to reproduce the bug ([guide](https://stackoverflow.com/help/minimal-reproducible-example))
|
||||
placeholder: |
|
||||
```
|
||||
# Code to reproduce your issue here
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
# Your code here
|
||||
```
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional
|
||||
description: Anything else you would like to share?
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Are you willing to submit a PR?
|
||||
description: >
|
||||
(Optional) We encourage you to submit a [Pull Request](https://github.com/roboflow/supervision/pulls) (PR) to help improve Supervision for everyone, especially if you have a good understanding of how to implement a fix or feature.
|
||||
description: (Optional) We encourage community contributions!
|
||||
options:
|
||||
- label: Yes I'd like to help by submitting a PR!
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: ❓ Ask a Question
|
||||
url: https://github.com/roboflow/supervision/discussions/new?category=q-a
|
||||
about: Ask questions about using Supervision in GitHub Discussions
|
||||
- name: 📚 Documentation
|
||||
url: https://supervision.roboflow.com/
|
||||
about: Check the official Supervision documentation for guides and API references
|
||||
- name: 💬 GitHub Discussions
|
||||
url: https://github.com/roboflow/supervision/discussions
|
||||
about: Join community discussions, share ideas, and get help
|
||||
- name: 🌟 Show and Tell
|
||||
url: https://github.com/roboflow/supervision/discussions/categories/show-and-tell
|
||||
about: Share your projects and creations built with Supervision
|
||||
- name: 🗣️ Roboflow Discord
|
||||
url: https://discord.com/invite/GbfgXGJ8Bk
|
||||
about: Join our Discord to collaborate with other community members
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 🤩 Feature Request
|
||||
description: Suggest a Supervision idea
|
||||
# title: " "
|
||||
title: "[Feature]: "
|
||||
description: Suggest a new feature or improvement
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
@@ -11,39 +11,40 @@ body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please search the [issues](https://github.com/roboflow/supervision/issues) to see if a similar feature request already exists.
|
||||
description: Please search [issues](https://github.com/roboflow/supervision/issues) and [discussions](https://github.com/roboflow/supervision/discussions) first.
|
||||
options:
|
||||
- label: >
|
||||
I have searched the Supervision [issues](https://github.com/roboflow/supervision/issues) and found no similar feature requests.
|
||||
- label: I have searched the issues and discussions and found no similar feature request.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: A short description of your feature.
|
||||
label: Feature Description
|
||||
description: What feature would you like and why?
|
||||
placeholder: |
|
||||
What new feature would you like to see in Supervision?
|
||||
**What:** Describe the feature...
|
||||
|
||||
**Why:** What problem does it solve? Who would benefit?
|
||||
|
||||
**How (optional):** Any ideas on implementation?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Use case
|
||||
description: |
|
||||
Describe the use case of your feature request. It will help us understand and prioritize the feature request.
|
||||
label: Example Usage
|
||||
description: (Optional) Show how you'd like to use this feature
|
||||
placeholder: |
|
||||
How would this feature be used, and who would use it?
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional
|
||||
description: Anything else you would like to share?
|
||||
# Your example usage here
|
||||
```
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Are you willing to submit a PR?
|
||||
description: >
|
||||
(Optional) We encourage you to submit a [Pull Request](https://github.com/roboflow/supervision/pulls) (PR) to help improve Supervision for everyone, especially if you have a good understanding of how to implement a fix or feature.
|
||||
description: (Optional) We encourage community contributions!
|
||||
options:
|
||||
- label: Yes I'd like to help by submitting a PR!
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: ❓ Question
|
||||
description: Ask a Supervision question
|
||||
# title: " "
|
||||
labels: [question]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for asking a Supervision ❓ Question!
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please search the [issues](https://github.com/roboflow/supervision/issues) to see if a similar feature request already exists.
|
||||
options:
|
||||
- label: >
|
||||
I have searched the Supervision [issues](https://github.com/roboflow/supervision/issues) and found no similar feature requests.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Question
|
||||
description: What is your question?
|
||||
placeholder: |
|
||||
💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional
|
||||
description: Anything else you would like to share?
|
||||
@@ -0,0 +1,67 @@
|
||||
<details>
|
||||
<summary>Before submitting</summary>
|
||||
|
||||
- [ ] Self-reviewed the code
|
||||
- [ ] Updated documentation, follow [Google-style](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods)
|
||||
- [ ] Added docs entry for autogeneration (if new functions/classes)
|
||||
- [ ] Added/updated tests
|
||||
- [ ] All tests pass locally
|
||||
|
||||
</details>
|
||||
|
||||
## Description
|
||||
|
||||
<!-- Provide a clear and concise description of your changes -->
|
||||
|
||||
## Type of Change
|
||||
|
||||
<!-- Mark the relevant option with an "x" and delete the others -->
|
||||
|
||||
- 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- ✨ New feature (non-breaking change which adds functionality)
|
||||
- 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- 📝 Documentation update
|
||||
- 🧪 Test update
|
||||
- 🔨 Refactoring (no functional changes)
|
||||
- ⚡ Performance improvement
|
||||
- 🔧 Chore (dependencies, configs, etc.)
|
||||
|
||||
## Motivation and Context
|
||||
|
||||
<!-- Why is this change required? What problem does it solve? -->
|
||||
|
||||
<!-- If it fixes an open issue, please link to the issue here -->
|
||||
|
||||
Closes #(issue)
|
||||
|
||||
## Changes Made
|
||||
|
||||
<!-- List the main changes made in this PR -->
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
## Testing
|
||||
|
||||
<!-- Describe the tests you ran and how to reproduce them -->
|
||||
|
||||
- [ ] I have tested this code locally
|
||||
- [ ] I have added unit tests that prove my fix is effective or that my feature works
|
||||
- [ ] All new and existing tests pass
|
||||
|
||||
## Google Colab (optional)
|
||||
|
||||
<!-- If applicable, provide a link to a Google Colab notebook demonstrating the feature/fix -->
|
||||
|
||||
<!-- Ensure the notebook is publicly accessible -->
|
||||
|
||||
Colab link:
|
||||
|
||||
## Screenshots/Videos (optional)
|
||||
|
||||
<!-- If applicable, add screenshots or videos to demonstrate the changes -->
|
||||
|
||||
## Additional Notes
|
||||
|
||||
<!-- Any additional information that reviewers should know -->
|
||||
@@ -8,6 +8,10 @@ updates:
|
||||
commit-message:
|
||||
prefix: ⬆️
|
||||
target-branch: "develop"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
# Python
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Build Package
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
default: "3.10"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ inputs.python-version }}
|
||||
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
|
||||
- name: 📤 Upload distribution artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
@@ -1,37 +1,39 @@
|
||||
name: 🧪 Docs Test WorkFlow 📚
|
||||
name: Test Docs Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
concurrency:
|
||||
group: docs-test-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Restrict permissions by default
|
||||
permissions:
|
||||
contents: read # Required for checkout
|
||||
checks: write # Required for test reporting
|
||||
|
||||
jobs:
|
||||
docs-build-test:
|
||||
docs-build:
|
||||
name: Test docs build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🐍 Install uv and set Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
- name: 🐍 Install uv and set Python
|
||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
python-version: "3.10"
|
||||
activate-environment: true
|
||||
|
||||
- name: 🏗️ Install dependencies
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group docs
|
||||
run: uv pip install -r pyproject.toml --group docs
|
||||
|
||||
- name: 🧪 Test Docs Build
|
||||
run: uv run mkdocs build --verbose
|
||||
@@ -0,0 +1,87 @@
|
||||
name: 🔧 Pytest/Test Workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: pytest-test-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
build-pkg:
|
||||
uses: ./.github/workflows/build-package.yml
|
||||
|
||||
run-tests:
|
||||
name: Import Test and Pytest Run
|
||||
# needs: build # todo: consider using this build package for testing
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
- name: 🚀 Install Packages
|
||||
run: uv pip install -r pyproject.toml --group dev --group docs --extra metrics
|
||||
|
||||
- name: 📦 Run the Import test
|
||||
run: uv run python -c "import supervision; from supervision import assets; from supervision import metrics; print(supervision.__version__)"
|
||||
|
||||
- name: 🧪 Run the Test
|
||||
run: uv run pytest --cov=supervision --cov-report=xml
|
||||
|
||||
- name: Generate Coverage Report
|
||||
run: |
|
||||
coverage xml
|
||||
coverage report
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: "coverage.xml"
|
||||
flags: cpu,${{ runner.os }},python${{ matrix.python-version }}
|
||||
env_vars: OS,PYTHON
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
- name: Minimize uv cache
|
||||
run: uv cache prune --ci
|
||||
|
||||
|
||||
testing-guardian:
|
||||
runs-on: ubuntu-latest
|
||||
needs: run-tests
|
||||
if: always()
|
||||
steps:
|
||||
- name: 📋 Display test result
|
||||
run: echo "${{ needs.run-tests.result }}"
|
||||
- name: ❌ Fail guardian on test failure
|
||||
if: needs.run-tests.result == 'failure'
|
||||
run: exit 1
|
||||
# Ensure that cancelled or skipped test runs still cause this guardian job to fail,
|
||||
# using an explicit exit code instead of relying on timeout behavior.
|
||||
- name: ⚠️ cancelled or skipped...
|
||||
if: contains(fromJSON('["cancelled", "skipped"]'), needs.run-tests.result)
|
||||
run: |
|
||||
echo "run-tests job result is '${{ needs.run-tests.result }}'; failing explicitly."
|
||||
exit 1
|
||||
- name: ✅ tests succeeded
|
||||
if: needs.run-tests.result == 'success'
|
||||
run: echo "All tests completed successfully in job 'run-tests'."
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Combine Dependabot PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * 3" # Wednesday at 01:00
|
||||
workflow_dispatch: # allows you to manually trigger the workflow
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
checks: read
|
||||
|
||||
jobs:
|
||||
combine-prs:
|
||||
name: Combine
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: combine-prs
|
||||
id: combine-prs
|
||||
uses: github/combine-prs@2909f404763c3177a456e052bdb7f2e85d3a7cb3 # v5.2.0
|
||||
with:
|
||||
labels: combined-pr
|
||||
@@ -0,0 +1,27 @@
|
||||
name: PR Conflict Labeler
|
||||
|
||||
on:
|
||||
# So that PRs touching the same files as the push are updated
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
# So that the `dirtyLabel` is removed if conflicts are resolved
|
||||
# We recommend `pull_request_target` so that github secrets are available.
|
||||
# In `pull_request` we wouldn't be able to change labels of fork PRs
|
||||
pull_request_target:
|
||||
types: [synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: check if prs are dirty
|
||||
uses: eps1lon/actions-label-merge-conflict@v3
|
||||
with:
|
||||
dirtyLabel: "has conflicts"
|
||||
removeOnDirtyLabel: "has conflicts"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
@@ -20,53 +20,41 @@ permissions:
|
||||
pull-requests: write # Required for PR comments
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
docs-build-deploy:
|
||||
name: Publish Docs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🐍 Install uv and set Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
- name: 🐍 Install uv and set Python
|
||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
python-version: "3.10"
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🔑 Create GitHub App token (mkdocs)
|
||||
id: mkdocs_token
|
||||
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||
with:
|
||||
app-id: ${{ secrets.MKDOCS_APP_ID }}
|
||||
private-key: ${{ secrets.MKDOCS_PEM }}
|
||||
owner: roboflow
|
||||
repositories: mkdocs-material-insiders
|
||||
|
||||
- name: 🏗️ Install dependencies
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group docs
|
||||
# Install mkdocs-material-insiders using the GitHub App token
|
||||
uv pip install "git+https://roboflow:${{ steps.mkdocs_token.outputs.token }}@github.com/roboflow/mkdocs-material-insiders.git@9.5.49-insiders-4.53.14#egg=mkdocs-material[imaging]"
|
||||
run: uv pip install -r pyproject.toml --group docs
|
||||
|
||||
- name: ⚙️ Configure git for github-actions
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --global user.name "${{ github.actor }}"
|
||||
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
|
||||
|
||||
- name: 🚀 Deploy Development Docs
|
||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/develop') || github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} uv run mike deploy --push develop
|
||||
uv run mike deploy --push develop
|
||||
|
||||
- name: 🚀 Deploy Release Docs
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
env:
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY=${{ secrets.GITHUB_TOKEN }} uv run mike deploy --push --update-aliases $latest_tag latest
|
||||
uv run mike deploy --push --update-aliases $latest_tag latest
|
||||
|
||||
@@ -7,12 +7,23 @@ on:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+b[0-9]"
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]+rc[0-9]"
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- '.github/workflows/build-package.yml'
|
||||
- '.github/workflows/publish-pre-release.yml'
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/build-package.yml
|
||||
|
||||
publish-pre-release:
|
||||
name: Publish Pre-release Package
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: test
|
||||
@@ -21,27 +32,17 @@ jobs:
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
- name: 📥 Download distribution artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
name: dist
|
||||
path: dist/
|
||||
- name: List distribution artifacts
|
||||
run: ls -lh dist/
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
attestations: true
|
||||
|
||||
@@ -5,12 +5,23 @@ on:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+[0-9]+.[0-9]"
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- '.github/workflows/build-package.yml'
|
||||
- '.github/workflows/publish-release.yml'
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/build-package.yml
|
||||
|
||||
publish-release:
|
||||
name: Publish Release Package
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release
|
||||
@@ -19,27 +30,17 @@ jobs:
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
- name: 📥 Download distribution artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
name: dist
|
||||
path: dist/
|
||||
- name: List distribution artifacts
|
||||
run: ls -lh dist/
|
||||
|
||||
- name: 🚀 Publish to PyPi
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
attestations: true
|
||||
|
||||
@@ -2,12 +2,23 @@ name: Publish Supervision Releases to TestPyPI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- '.github/workflows/build-package.yml'
|
||||
- '.github/workflows/publish-testpypi.yml'
|
||||
|
||||
permissions: {} # Explicitly remove all permissions by default
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/build-package.yml
|
||||
|
||||
publish-testpypi:
|
||||
name: Publish Release Package
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release
|
||||
@@ -16,27 +27,17 @@ jobs:
|
||||
permissions:
|
||||
id-token: write # Required for PyPI publishing
|
||||
contents: read # Required for checkout
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
- name: 📥 Download distribution artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🏗️ Build source and wheel distributions
|
||||
run: |
|
||||
uv pip install -r pyproject.toml --group build
|
||||
uv build
|
||||
uv run twine check --strict dist/*
|
||||
name: dist
|
||||
path: dist/
|
||||
- name: List distribution artifacts
|
||||
run: ls -lh dist/
|
||||
|
||||
- name: 🚀 Publish to Test-PyPi
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
name: 🔧 Pytest/Test Workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
name: Import Test and Pytest Run
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 📥 Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: 🐍 Install uv and set Python version ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
activate-environment: true
|
||||
|
||||
|
||||
- name: 🚀 Install Packages
|
||||
run: uv pip install -r pyproject.toml --group dev --group docs --extra metrics
|
||||
|
||||
- name: 🧪 Run the Import test
|
||||
run: uv run python -c "import supervision; from supervision import assets; from supervision import metrics; print(supervision.__version__)"
|
||||
|
||||
- name: 🧪 Run the Test
|
||||
run: uv run pytest
|
||||
+20
-26
@@ -1,4 +1,3 @@
|
||||
|
||||
ci:
|
||||
autofix_prs: true
|
||||
autoupdate_schedule: weekly
|
||||
@@ -7,10 +6,9 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: test/.*\.py
|
||||
- id: check-yaml
|
||||
exclude: mkdocs.yml
|
||||
- id: check-executables-have-shebangs
|
||||
@@ -24,28 +22,32 @@ repos:
|
||||
- id: end-of-file-fixer
|
||||
- id: mixed-line-ending
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: '1.8.6'
|
||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||
rev: v2.6.0
|
||||
hooks:
|
||||
- id: bandit
|
||||
args: ["-c", "pyproject.toml"]
|
||||
additional_dependencies: ["bandit[toml]"]
|
||||
- id: pyproject-fmt
|
||||
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.24.1
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.12.5
|
||||
rev: v0.14.11
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
- id: ruff-check
|
||||
args: [--fix]
|
||||
- id: ruff-format
|
||||
types_or: [ python, pyi, jupyter ]
|
||||
|
||||
# - repo: https://github.com/executablebooks/mdformat
|
||||
# rev: 0.7.17
|
||||
# hooks:
|
||||
# - id: mdformat
|
||||
# additional_dependencies:
|
||||
# - "mdformat-mkdocs[recommended]>=2.1.0"
|
||||
# args: ["--number"]
|
||||
- repo: https://github.com/executablebooks/mdformat
|
||||
rev: 1.0.0
|
||||
hooks:
|
||||
- id: mdformat
|
||||
additional_dependencies:
|
||||
- "mdformat-mkdocs[recommended]>=2.1.0"
|
||||
args: ["--number"]
|
||||
exclude: ^docs/
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.4.1
|
||||
@@ -53,11 +55,3 @@ repos:
|
||||
- id: codespell
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.20.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py310-plus"]
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
||||
+5
-5
@@ -21,20 +21,20 @@ community include:
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
|
||||
+88
-27
@@ -83,18 +83,20 @@ git push -u origin <your_branch_name>
|
||||
|
||||
Use conventional commit messages to clearly describe your changes. The format is:
|
||||
|
||||
<type>\[optional scope\]: <description>
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
```
|
||||
|
||||
Common types include:
|
||||
|
||||
- feat: A new feature
|
||||
- fix: A bug fix
|
||||
- docs: Documentation only changes
|
||||
- style: Changes that do not affect the meaning of the code (white-space, formatting, etc)
|
||||
- refactor: A code change that neither fixes a bug nor adds a feature
|
||||
- perf: A code change that improves performance
|
||||
- test: Adding missing tests or correcting existing tests
|
||||
- chore: Changes to the build process or auxiliary tools and libraries
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation only changes
|
||||
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc)
|
||||
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
||||
- `perf`: A code change that improves performance
|
||||
- `test`: Adding missing tests or correcting existing tests
|
||||
- `chore`: Changes to the build process or auxiliary tools and libraries
|
||||
|
||||
Then, go back to your fork of the `supervision` repository, click "Pull Requests", and click "New Pull Request".
|
||||
|
||||
@@ -116,7 +118,7 @@ When creating new functions, please ensure you have the following:
|
||||
2. Unit tests for the function.
|
||||
3. Examples in the documentation for the function.
|
||||
4. Created an entry in our docs to autogenerate the documentation for the function.
|
||||
5. Please share a Google Colab with minimal code to test new feature or reproduce PR whenever it is possible. Please ensure that Google Colab can be accessed without any issue.
|
||||
5. Please share a Google Colab with minimal code to test a new feature or reproduce the issue whenever possible. Please ensure that Google Colab can be accessed without any restrictions.
|
||||
|
||||
When you submit your Pull Request, you will be asked to sign a Contributor License Agreement (CLA) by the `cla-assistant` GitHub bot. We can only respond to PRs from contributors who have signed the project CLA.
|
||||
|
||||
@@ -128,7 +130,7 @@ PRs must pass all tests and linting requirements before they can be merged.
|
||||
|
||||
Before starting your work on the project, set up your development environment:
|
||||
|
||||
1. Clone your fork of the project (recommended to use shallow clone of develop branch):
|
||||
1. **Clone your fork of the project:**
|
||||
|
||||
**Option A: Recommended for most contributors (shallow clone of develop branch):**
|
||||
|
||||
@@ -139,33 +141,50 @@ Before starting your work on the project, set up your development environment:
|
||||
|
||||
Replace `YOUR_USERNAME` with your GitHub username.
|
||||
|
||||
> Note: Using `--depth 1` creates a shallow clone with minimal history and `-b develop` ensures you start with the development branch. This significantly reduces download size while providing everything needed to contribute.
|
||||
> **Note**: Using `--depth 1` creates a shallow clone with minimal history and `-b develop` ensures you start with the development branch. This significantly reduces download size while providing everything needed to contribute.
|
||||
|
||||
**Option B: Full repository clone (if you need complete history):**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/supervision.git
|
||||
cd supervision
|
||||
git checkout develop
|
||||
```
|
||||
|
||||
2. Create and activate a virtual environment:
|
||||
2. **Set up the upstream remote:**
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/roboflow/supervision.git
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
3. **Create and activate a virtual environment:**
|
||||
|
||||
**On Linux/macOS:**
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
3. Install `uv`:
|
||||
**On Windows:**
|
||||
|
||||
```cmd
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate
|
||||
```
|
||||
|
||||
4. **Install `uv`:**
|
||||
|
||||
Follow the instructions on the [uv installation page](https://docs.astral.sh/uv/getting-started/installation/).
|
||||
|
||||
4. Install project dependencies:
|
||||
5. **Install project dependencies:**
|
||||
|
||||
```bash
|
||||
uv pip install -r pyproject.toml --extra dev --extra docs --extra metrics
|
||||
uv pip install -r pyproject.toml --group dev --group docs --extra metrics
|
||||
```
|
||||
|
||||
5. Run pytest to verify the setup:
|
||||
6. **Verify the setup:**
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
@@ -181,13 +200,29 @@ Furthermore, we have integrated a pre-commit GitHub Action into our workflow. Th
|
||||
|
||||
To run the pre-commit tool, follow these steps:
|
||||
|
||||
1. Install pre-commit by running the following command: `uv pip install -r pyproject.toml --extra dev`. It will not only install pre-commit but also install all the deps and dev-deps of project
|
||||
1. **Install pre-commit** (already included if you followed the installation steps above):
|
||||
|
||||
2. Once pre-commit is installed, navigate to the project's root directory.
|
||||
```bash
|
||||
uv sync --group dev
|
||||
```
|
||||
|
||||
3. Run the command `pre-commit run --all-files`. This will execute the pre-commit hooks configured for this project against the modified files. If any issues are found, the pre-commit tool will provide feedback on how to resolve them. Make the necessary changes and re-run the pre-commit command until all issues are resolved.
|
||||
2. **Navigate to the project's root directory** (if not already there).
|
||||
|
||||
4. You can also install pre-commit as a git hook by executing `pre-commit install`. Every time you do a `git commit` pre-commit run automatically for you.
|
||||
3. **Run pre-commit checks**:
|
||||
|
||||
```bash
|
||||
uv run pre-commit run --all-files
|
||||
```
|
||||
|
||||
This will execute the pre-commit hooks configured for this project. If any issues are found, the pre-commit tool will provide feedback on how to resolve them. Make the necessary changes and re-run the command until all issues are resolved.
|
||||
|
||||
4. **Install pre-commit as a git hook** (optional but recommended):
|
||||
|
||||
```bash
|
||||
uv run pre-commit install
|
||||
```
|
||||
|
||||
This will automatically run pre-commit checks every time you make a `git commit`.
|
||||
|
||||
### Docstrings
|
||||
|
||||
@@ -197,13 +232,27 @@ All new functions and classes in `supervision` should include docstrings. This i
|
||||
|
||||
### Type checking
|
||||
|
||||
So far, **there is no type checking with mypy**. See [issue](https://github.com/roboflow-ai/template-python/issues/4).
|
||||
Currently, there is no systematic type checking with mypy implemented in the project. This is a known limitation that may be addressed in future updates.
|
||||
|
||||
## 📝 Documentation
|
||||
|
||||
The `supervision` documentation is stored in a folder called `docs`. The project documentation is built using `mkdocs`.
|
||||
|
||||
To run the documentation, install the project requirements with `uv pip install -r pyproject.toml --extra dev --extra docs`. Then, run `mkdocs serve` to start the documentation server.
|
||||
To run the documentation locally:
|
||||
|
||||
1. **Install documentation dependencies** (if not already installed):
|
||||
|
||||
```bash
|
||||
uv sync --group docs
|
||||
```
|
||||
|
||||
2. **Start the documentation server**:
|
||||
|
||||
```bash
|
||||
uv run mkdocs serve
|
||||
```
|
||||
|
||||
3. **Access the documentation** at `http://127.0.0.1:8000` in your browser.
|
||||
|
||||
You can learn more about mkdocs on the [mkdocs website](https://www.mkdocs.org/).
|
||||
|
||||
@@ -216,14 +265,26 @@ submit a PR with your example. Here are some guidelines for submitting a new exa
|
||||
- Create a new notebook in the [`docs/notebooks`](https://github.com/roboflow/supervision/tree/develop/docs/notebooks) folder.
|
||||
- Add a link to the new notebook in [`docs/theme/cookbooks.html`](https://github.com/roboflow/supervision/blob/develop/docs/theme/cookbooks.html). Make sure to add the path to the new notebook, as well as a title, labels, author and supervision version.
|
||||
- Use the [Count Objects Crossing the Line](https://supervision.roboflow.com/develop/notebooks/count-objects-crossing-the-line/) example as a template for your new example.
|
||||
- Freeze the version of `supervision` you are using.
|
||||
- Place an appropriate Open in Colab button at the top of the notebook. You can find an example of such a button in the aforementioned `Count Objects Crossing the Line` cookbook.
|
||||
- Notebook should be self-contained. If you rely on external data ( videos, images, etc.) or libraries, include download and installation commands in the notebook.
|
||||
- Pin the version of `supervision` you are using in the notebook.
|
||||
- Place an appropriate "Open in Colab" button at the top of the notebook. You can find an example of such a button in the aforementioned `Count Objects Crossing the Line` cookbook.
|
||||
- **Notebook should be self-contained**. If you rely on external data (videos, images, etc.) or libraries, include download and installation commands in the notebook.
|
||||
- Annotate the code with appropriate comments, including links to the documentation describing each of the tools you have used.
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
[`pytests`](https://docs.pytest.org/en/7.1.x/) is used to run our tests.
|
||||
[`pytest`](https://docs.pytest.org/en/7.1.x/) is used to run our tests.
|
||||
|
||||
To run tests:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
To run tests with coverage:
|
||||
|
||||
```bash
|
||||
uv run pytest --cov=supervision
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
[](https://discord.gg/GbfgXGJ8Bk)
|
||||
[](https://squidfunk.github.io/mkdocs-material/)
|
||||
|
||||
<div align="center">
|
||||
<div align="center">
|
||||
<a href="https://trendshift.io/repositories/124" target="_blank"><img src="https://trendshift.io/api/badge/repositories/124" alt="roboflow%2Fsupervision | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</div>
|
||||
|
||||
@@ -70,21 +70,21 @@ len(detections)
|
||||
|
||||
- inference
|
||||
|
||||
Running with [Inference](https://github.com/roboflow/inference) requires a [Roboflow API KEY](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key).
|
||||
Running with [Inference](https://github.com/roboflow/inference) requires a [Roboflow API KEY](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key).
|
||||
|
||||
```python
|
||||
import cv2
|
||||
import supervision as sv
|
||||
from inference import get_model
|
||||
```python
|
||||
import cv2
|
||||
import supervision as sv
|
||||
from inference import get_model
|
||||
|
||||
image = cv2.imread(...)
|
||||
model = get_model(model_id="yolov8s-640", api_key=<ROBOFLOW API KEY>)
|
||||
result = model.infer(image)[0]
|
||||
detections = sv.Detections.from_inference(result)
|
||||
image = cv2.imread(...)
|
||||
model = get_model(model_id="yolov8s-640", api_key="ROBOFLOW_API_KEY")
|
||||
result = model.infer(image)[0]
|
||||
detections = sv.Detections.from_inference(result)
|
||||
|
||||
len(detections)
|
||||
# 5
|
||||
```
|
||||
len(detections)
|
||||
# 5
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -100,9 +100,7 @@ image = cv2.imread(...)
|
||||
detections = sv.Detections(...)
|
||||
|
||||
box_annotator = sv.BoxAnnotator()
|
||||
annotated_frame = box_annotator.annotate(
|
||||
scene=image.copy(),
|
||||
detections=detections)
|
||||
annotated_frame = box_annotator.annotate(scene=image.copy(), detections=detections)
|
||||
```
|
||||
|
||||
https://github.com/roboflow/supervision/assets/26109316/691e219c-0565-4403-9218-ab5644f39bce
|
||||
@@ -115,8 +113,8 @@ Supervision provides a set of [utils](https://supervision.roboflow.com/latest/da
|
||||
import supervision as sv
|
||||
from roboflow import Roboflow
|
||||
|
||||
project = Roboflow().workspace(<WORKSPACE_ID>).project(<PROJECT_ID>)
|
||||
dataset = project.version(<PROJECT_VERSION>).download("coco")
|
||||
project = Roboflow().workspace("WORKSPACE_ID").project("PROJECT_ID")
|
||||
dataset = project.version("PROJECT_VERSION").download("coco")
|
||||
|
||||
ds = sv.DetectionDataset.from_coco(
|
||||
images_directory_path=f"{dataset.location}/train",
|
||||
@@ -124,10 +122,11 @@ ds = sv.DetectionDataset.from_coco(
|
||||
)
|
||||
|
||||
path, image, annotation = ds[0]
|
||||
# loads image on demand
|
||||
# loads image on demand
|
||||
|
||||
for path, image, annotation in ds:
|
||||
# loads image on demand
|
||||
pass
|
||||
```
|
||||
|
||||
<details close>
|
||||
@@ -135,88 +134,88 @@ for path, image, annotation in ds:
|
||||
|
||||
- load
|
||||
|
||||
```python
|
||||
dataset = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...
|
||||
)
|
||||
```python
|
||||
dataset = sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...,
|
||||
)
|
||||
|
||||
dataset = sv.DetectionDataset.from_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...
|
||||
)
|
||||
dataset = sv.DetectionDataset.from_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
)
|
||||
|
||||
dataset = sv.DetectionDataset.from_coco(
|
||||
images_directory_path=...,
|
||||
annotations_path=...
|
||||
)
|
||||
```
|
||||
dataset = sv.DetectionDataset.from_coco(
|
||||
images_directory_path=...,
|
||||
annotations_path=...,
|
||||
)
|
||||
```
|
||||
|
||||
- split
|
||||
|
||||
```python
|
||||
train_dataset, test_dataset = dataset.split(split_ratio=0.7)
|
||||
test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5)
|
||||
```python
|
||||
train_dataset, test_dataset = dataset.split(split_ratio=0.7)
|
||||
test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5)
|
||||
|
||||
len(train_dataset), len(test_dataset), len(valid_dataset)
|
||||
# (700, 150, 150)
|
||||
```
|
||||
len(train_dataset), len(test_dataset), len(valid_dataset)
|
||||
# (700, 150, 150)
|
||||
```
|
||||
|
||||
- merge
|
||||
|
||||
```python
|
||||
ds_1 = sv.DetectionDataset(...)
|
||||
len(ds_1)
|
||||
# 100
|
||||
ds_1.classes
|
||||
# ['dog', 'person']
|
||||
```python
|
||||
ds_1 = sv.DetectionDataset(...)
|
||||
len(ds_1)
|
||||
# 100
|
||||
ds_1.classes
|
||||
# ['dog', 'person']
|
||||
|
||||
ds_2 = sv.DetectionDataset(...)
|
||||
len(ds_2)
|
||||
# 200
|
||||
ds_2.classes
|
||||
# ['cat']
|
||||
ds_2 = sv.DetectionDataset(...)
|
||||
len(ds_2)
|
||||
# 200
|
||||
ds_2.classes
|
||||
# ['cat']
|
||||
|
||||
ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
|
||||
len(ds_merged)
|
||||
# 300
|
||||
ds_merged.classes
|
||||
# ['cat', 'dog', 'person']
|
||||
```
|
||||
ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])
|
||||
len(ds_merged)
|
||||
# 300
|
||||
ds_merged.classes
|
||||
# ['cat', 'dog', 'person']
|
||||
```
|
||||
|
||||
- save
|
||||
|
||||
```python
|
||||
dataset.as_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...
|
||||
)
|
||||
```python
|
||||
dataset.as_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...,
|
||||
)
|
||||
|
||||
dataset.as_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...
|
||||
)
|
||||
dataset.as_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
)
|
||||
|
||||
dataset.as_coco(
|
||||
images_directory_path=...,
|
||||
annotations_path=...
|
||||
)
|
||||
```
|
||||
dataset.as_coco(
|
||||
images_directory_path=...,
|
||||
annotations_path=...,
|
||||
)
|
||||
```
|
||||
|
||||
- convert
|
||||
|
||||
```python
|
||||
sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...
|
||||
).as_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...
|
||||
)
|
||||
```
|
||||
```python
|
||||
sv.DetectionDataset.from_yolo(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
data_yaml_path=...,
|
||||
).as_pascal_voc(
|
||||
images_directory_path=...,
|
||||
annotations_directory_path=...,
|
||||
)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ https://github.com/roboflow/supervision/assets/26109316/f84db7b5-79e2-4142-a1da-
|
||||
cd supervision/examples/count_people_in_zone
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
@@ -110,7 +110,7 @@ https://github.com/roboflow/supervision/assets/26109316/f84db7b5-79e2-4142-a1da-
|
||||
|
||||
```bash
|
||||
python inference_example.py \
|
||||
--roboflow_api_key <ROBOFLOW API KEY> \
|
||||
--roboflow_api_key "ROBOFLOW_API_KEY" \
|
||||
--zone_configuration_path data/multi-zone-config.json \
|
||||
--source_video_path data/market-square.mp4 \
|
||||
--confidence_threshold 0.3 \
|
||||
|
||||
@@ -15,7 +15,7 @@ supervision package for multiple tasks such as drawing heatmap annotations, trac
|
||||
cd supervision/examples/heatmap_and_track
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
|
||||
@@ -11,7 +11,7 @@ supervision package for multiple tasks such as tracking, annotations, etc.
|
||||
|
||||
https://github.com/roboflow/supervision/assets/26109316/d50118c1-2ae4-458d-915a-5d860fd36f71
|
||||
|
||||
> \[!IMPORTANT\]
|
||||
> [!IMPORTANT]
|
||||
> Adjust the [`SOURCE`](https://github.com/roboflow/supervision/blob/e32b05a636dab2ea1f39299e529c4b22b8baa8da/examples/speed_estimation/ultralytics_example.py#L10)
|
||||
> and [`TARGET`](https://github.com/roboflow/supervision/blob/e32b05a636dab2ea1f39299e529c4b22b8baa8da/examples/speed_estimation/ultralytics_example.py#L15)
|
||||
> configuration if you plan to run a speed estimation script on your video file. Those must be adjusted separately for each camera view. You can learn more
|
||||
@@ -26,7 +26,7 @@ https://github.com/roboflow/supervision/assets/26109316/d50118c1-2ae4-458d-915a-
|
||||
cd supervision/examples/speed_estimation
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3.10 -m venv venv
|
||||
@@ -90,7 +90,7 @@ https://github.com/roboflow/supervision/assets/26109316/d50118c1-2ae4-458d-915a-
|
||||
|
||||
```bash
|
||||
python inference_example.py \
|
||||
--roboflow_api_key <ROBOFLOW API KEY> \
|
||||
--roboflow_api_key "ROBOFLOW_API_KEY" \
|
||||
--source_video_path data/vehicles.mp4 \
|
||||
--target_video_path data/vehicles-result.mp4 \
|
||||
--confidence_threshold 0.3 \
|
||||
|
||||
@@ -20,7 +20,7 @@ https://github.com/roboflow/supervision/assets/26109316/d051cc8a-dd15-41d4-aa36-
|
||||
cd supervision/examples/time_in_zone
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
|
||||
@@ -77,7 +77,7 @@ def run_command_in_thread(command: list) -> Thread:
|
||||
|
||||
|
||||
def run_command(command: list) -> int:
|
||||
process = subprocess.run(command)
|
||||
process = subprocess.run(command) # noqa: S603 # TODO: Validate command input to prevent execution of untrusted input
|
||||
return process.returncode
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ detection and Supervision for tracking and annotation.
|
||||
cd supervision/examples/tracking
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
@@ -79,7 +79,7 @@ detection and Supervision for tracking and annotation.
|
||||
|
||||
```bash
|
||||
python inference_example.py \
|
||||
--roboflow_api_key <ROBOFLOW API KEY> \
|
||||
--roboflow_api_key "ROBOFLOW_API_KEY" \
|
||||
--source_video_path input.mp4 \
|
||||
--target_video_path tracking_result.mp4
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-
|
||||
cd supervision/examples/traffic_analysis
|
||||
```
|
||||
|
||||
- setup python environment and activate it \[optional\]
|
||||
- setup python environment and activate it [optional]
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
@@ -101,7 +101,7 @@ https://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-
|
||||
|
||||
```bash
|
||||
python inference_example.py \
|
||||
--roboflow_api_key <ROBOFLOW API KEY> \
|
||||
--roboflow_api_key "ROBOFLOW_API_KEY" \
|
||||
--source_video_path data/traffic_analysis.mov \
|
||||
--confidence_threshold 0.3 \
|
||||
--iou_threshold 0.5 \
|
||||
|
||||
+151
-196
@@ -1,219 +1,184 @@
|
||||
[build-system]
|
||||
build-backend = "setuptools.build_meta"
|
||||
requires = [ "setuptools>=61" ]
|
||||
|
||||
[project]
|
||||
name = "supervision"
|
||||
version = "0.28.0rc0"
|
||||
description = "A set of easy-to-use utils that will come in handy in any Computer Vision project"
|
||||
license = { text = "MIT" }
|
||||
version = "0.27.0"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
authors = [
|
||||
{ name = "Piotr Skalski", email = "piotr.skalski92@gmail.com" }
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Piotr Skalski", email = "piotr.skalski92@gmail.com" },
|
||||
]
|
||||
keywords = [
|
||||
"machine-learning",
|
||||
"deep-learning",
|
||||
"vision",
|
||||
"ML",
|
||||
"DL",
|
||||
"AI",
|
||||
"Roboflow",
|
||||
"AI",
|
||||
"deep-learning",
|
||||
"DL",
|
||||
"machine-learning",
|
||||
"ML",
|
||||
"Roboflow",
|
||||
"vision",
|
||||
]
|
||||
license = { text = "MIT" }
|
||||
maintainers = [
|
||||
{ name = "Piotr Skalski", email = "piotr@roboflow.com" },
|
||||
]
|
||||
authors = [
|
||||
{ name = "Roboflow et al.", email = "develop@roboflow.com" },
|
||||
]
|
||||
requires-python = ">=3.9"
|
||||
classifiers = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Education',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Topic :: Software Development',
|
||||
'Topic :: Scientific/Engineering',
|
||||
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||
"Topic :: Scientific/Engineering :: Image Recognition",
|
||||
'Typing :: Typed',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: MacOS',
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: Education",
|
||||
"Intended Audience :: Science/Research",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Multimedia :: Graphics",
|
||||
"Topic :: Multimedia :: Video",
|
||||
"Topic :: Scientific/Engineering",
|
||||
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||
"Topic :: Scientific/Engineering :: Image Recognition",
|
||||
"Topic :: Software Development",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"numpy>=1.21.2",
|
||||
"scipy>=1.10.0",
|
||||
"matplotlib>=3.6.0",
|
||||
"pyyaml>=5.3",
|
||||
"defusedxml>=0.7.1",
|
||||
"pillow>=9.4",
|
||||
"requests>=2.26.0",
|
||||
"tqdm>=4.62.3",
|
||||
"opencv-python>=4.5.5.64"
|
||||
"defusedxml>=0.7.1",
|
||||
"matplotlib>=3.6",
|
||||
"numpy>=1.21.2",
|
||||
"opencv-python>=4.5.5.64",
|
||||
"pillow>=9.4",
|
||||
"pyyaml>=5.3",
|
||||
"requests>=2.26",
|
||||
"scipy>=1.10",
|
||||
"tqdm>=4.62.3",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/roboflow/supervision"
|
||||
Repository = "https://github.com/roboflow/supervision"
|
||||
Documentation = "https://supervision.roboflow.com/latest/"
|
||||
|
||||
[project.optional-dependencies]
|
||||
metrics = [
|
||||
"pandas>=2.0.0",
|
||||
optional-dependencies.metrics = [
|
||||
"pandas>=2",
|
||||
]
|
||||
urls.Documentation = "https://supervision.roboflow.com/latest/"
|
||||
urls.Homepage = "https://github.com/roboflow/supervision"
|
||||
urls.Repository = "https://github.com/roboflow/supervision"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=7.2.2,<9.0.0",
|
||||
"tox>=4.11.4",
|
||||
"notebook>=6.5.3,<8.0.0",
|
||||
"ipywidgets>=8.1.1",
|
||||
"jupytext>=1.16.1",
|
||||
"nbconvert>=7.14.2",
|
||||
"docutils!=0.21",
|
||||
"pre-commit>=3.8.0"
|
||||
"docutils!=0.21",
|
||||
"ipywidgets>=8.1.1",
|
||||
"jupytext>=1.16.1",
|
||||
"nbconvert>=7.14.2",
|
||||
"notebook>=6.5.3,<8",
|
||||
"pre-commit>=3.8",
|
||||
"pytest>=7.2.2,<9",
|
||||
"pytest-cov>=4,<8",
|
||||
"tox>=4.11.4",
|
||||
]
|
||||
docs = [
|
||||
"mkdocs-material[imaging]>=9.5.5",
|
||||
"mkdocstrings>=0.25.2,<0.31.0",
|
||||
"mkdocstrings-python>=1.10.9",
|
||||
"mike>=2.0.0",
|
||||
"mkdocs-jupyter>=0.24.3",
|
||||
"mkdocs-git-committers-plugin-2>=2.4.1; python_version >= '3.9' and python_version < '4'",
|
||||
"mkdocs-git-revision-date-localized-plugin>=1.2.4"
|
||||
"mike>=2",
|
||||
"mkdocs-git-committers-plugin-2>=2.4.1; python_version>='3.9' and python_version<'4'",
|
||||
"mkdocs-git-revision-date-localized-plugin>=1.2.4",
|
||||
"mkdocs-jupyter>=0.24.3",
|
||||
"mkdocs-material[imaging]>=9.7",
|
||||
"mkdocstrings>=0.25.2,<0.31",
|
||||
"mkdocstrings-python>=1.10.9,<2", # todo: breaking changes in 2.x
|
||||
]
|
||||
build = [
|
||||
"twine>=5.1.1,<7.0.0",
|
||||
"wheel>=0.40,<0.46",
|
||||
"build>=0.10,<1.4"
|
||||
"build>=0.10,<1.5",
|
||||
"twine>=5.1.1,<7",
|
||||
"wheel>=0.40,<0.46",
|
||||
]
|
||||
|
||||
[tool.bandit]
|
||||
target = ["test", "supervision"]
|
||||
tests = ["B201", "B301", "B318", "B314", "B303", "B413", "B412"]
|
||||
[tool.setuptools]
|
||||
include-package-data = false
|
||||
|
||||
[tool.autoflake]
|
||||
check = true
|
||||
imports = ["cv2", "supervision"]
|
||||
[tool.setuptools.packages.find]
|
||||
include = [ "supervision*" ]
|
||||
exclude = [ "docs*", "test*", "examples*" ]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
supervision = [ "py.typed" ]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py39"
|
||||
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
".eggs",
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"build",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"venv",
|
||||
"yarn-error.log",
|
||||
"yarn.lock",
|
||||
"docs",
|
||||
]
|
||||
|
||||
line-length = 88
|
||||
indent-width = 4
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
||||
select = ["E", "F", "I", "A", "Q", "W", "RUF", "UP"]
|
||||
ignore = []
|
||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
||||
fixable = [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"I",
|
||||
"N",
|
||||
"Q",
|
||||
"S",
|
||||
"T",
|
||||
"W",
|
||||
"ANN",
|
||||
"ARG",
|
||||
"BLE",
|
||||
"COM",
|
||||
"DJ",
|
||||
"DTZ",
|
||||
"EM",
|
||||
"ERA",
|
||||
"EXE",
|
||||
"FBT",
|
||||
"ICN",
|
||||
"INP",
|
||||
"ISC",
|
||||
"NPY",
|
||||
"PD",
|
||||
"PGH",
|
||||
"PIE",
|
||||
"PL",
|
||||
"PT",
|
||||
"PTH",
|
||||
"PYI",
|
||||
"RET",
|
||||
"RSE",
|
||||
"RUF",
|
||||
"SIM",
|
||||
"SLF",
|
||||
"TCH",
|
||||
"TID",
|
||||
"TRY",
|
||||
"UP",
|
||||
"YTT",
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
".eggs",
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"build",
|
||||
"dist",
|
||||
"docs",
|
||||
"node_modules",
|
||||
"venv",
|
||||
"yarn-error.log",
|
||||
"yarn.lock",
|
||||
]
|
||||
unfixable = []
|
||||
# Allow unused variables when underscore-prefixed.
|
||||
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||
pylint.max-args = 20
|
||||
|
||||
[tool.ruff.lint.flake8-quotes]
|
||||
inline-quotes = "double"
|
||||
multiline-quotes = "double"
|
||||
docstring-quotes = "double"
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"__init__.py" = ["E402", "F401"]
|
||||
|
||||
[tool.ruff.lint.mccabe]
|
||||
# Flag errors (`C901`) whenever the complexity level exceeds 5.
|
||||
max-complexity = 20
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
order-by-type = true
|
||||
no-sections = false
|
||||
|
||||
[tool.ruff.format]
|
||||
# Like Black, use double quotes for strings.
|
||||
quote-style = "double"
|
||||
|
||||
# Like Black, indent with spaces, rather than tabs.
|
||||
indent-style = "space"
|
||||
|
||||
# Like Black, respect magic trailing commas.
|
||||
skip-magic-trailing-comma = false
|
||||
|
||||
format.indent-style = "space"
|
||||
# Like Black, use double quotes for strings.
|
||||
format.quote-style = "double"
|
||||
# Like Black, automatically detect the appropriate line ending.
|
||||
line-ending = "auto"
|
||||
format.line-ending = "auto"
|
||||
# Like Black, respect magic trailing commas.
|
||||
format.skip-magic-trailing-comma = false
|
||||
# Enable linting rules for code style, imports, and best practices.
|
||||
lint.select = [
|
||||
"A", # flake8-builtins - https://docs.astral.sh/ruff/rules/#flake8-builtins-a
|
||||
"E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e
|
||||
"F", # Pyflakes - https://docs.astral.sh/ruff/rules/#pyflakes-f
|
||||
"I", # isort - https://docs.astral.sh/ruff/rules/#isort-i
|
||||
"PT", # pytest - https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
|
||||
"Q", # flake8-quotes - https://docs.astral.sh/ruff/rules/#flake8-quotes-q
|
||||
"RUF", # Ruff-specific rules - https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
|
||||
"S", # bandit - https://docs.astral.sh/ruff/rules/#flake8-bandit-s
|
||||
"UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up
|
||||
"W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#pycodestyle-w
|
||||
]
|
||||
lint.ignore = [ ]
|
||||
lint.per-file-ignores."__init__.py" = [ "E402", "F401" ]
|
||||
lint.per-file-ignores."supervision/**" = [
|
||||
"S101", # TODO: Replace asserts with proper error handling
|
||||
]
|
||||
lint.per-file-ignores."test/**" = [
|
||||
"PT011", # TODO: `pytest.raises(Exception)` is too broad, set the `match` parameter or use a more specific exception
|
||||
"S101", # Use of `assert` detected
|
||||
]
|
||||
lint.unfixable = [ ]
|
||||
# Allow unused variables when underscore-prefixed.
|
||||
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||
lint.flake8-quotes.docstring-quotes = "double"
|
||||
lint.flake8-quotes.inline-quotes = "double"
|
||||
lint.flake8-quotes.multiline-quotes = "double"
|
||||
lint.isort.no-sections = false
|
||||
lint.isort.order-by-type = true
|
||||
# Flag errors (`C901`) whenever the complexity level exceeds 5.
|
||||
lint.mccabe.max-complexity = 20
|
||||
lint.pydocstyle.convention = "google"
|
||||
lint.pylint.max-args = 20
|
||||
|
||||
[tool.codespell]
|
||||
skip = "*.ipynb"
|
||||
@@ -221,16 +186,6 @@ count = true
|
||||
quiet-level = 3
|
||||
ignore-words-list = "STrack,sTrack,strack"
|
||||
|
||||
[tool.setuptools]
|
||||
include-package-data = false
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["supervision*"]
|
||||
exclude = ["docs*", "test*", "examples*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
supervision = ["py.typed"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools >= 61.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
[tool.autoflake]
|
||||
check = true
|
||||
imports = [ "cv2", "supervision" ]
|
||||
|
||||
@@ -764,7 +764,7 @@ class EllipseAnnotator(BaseAnnotator):
|
||||
"""
|
||||
assert isinstance(scene, np.ndarray)
|
||||
for detection_idx in range(len(detections)):
|
||||
x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
|
||||
x1, _y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
|
||||
color = resolve_color(
|
||||
color=self.color,
|
||||
detections=detections,
|
||||
@@ -1621,7 +1621,7 @@ class RichLabelAnnotator(_BaseLabelAnnotator):
|
||||
)
|
||||
|
||||
# Move to the next line position
|
||||
left, top, right, bottom = draw.textbbox((0, 0), line, font=self.font)
|
||||
_left, top, _right, bottom = draw.textbbox((0, 0), line, font=self.font)
|
||||
line_height = bottom - top
|
||||
y_position += line_height + self.text_padding
|
||||
|
||||
@@ -1917,7 +1917,7 @@ class TraceAnnotator(BaseAnnotator):
|
||||
|
||||
if len(xy) > 3 and self.smooth:
|
||||
x, y = xy[:, 0], xy[:, 1]
|
||||
tck, u = splprep([x, y], s=20)
|
||||
tck, _u = splprep([x, y], s=20)
|
||||
x_new, y_new = splev(np.linspace(0, 1, 100), tck)
|
||||
spline_points = np.stack([x_new, y_new], axis=1).astype(np.int32)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from hashlib import new as hash_new
|
||||
from hashlib import md5
|
||||
from pathlib import Path
|
||||
from shutil import copyfileobj
|
||||
|
||||
@@ -15,6 +15,9 @@ def is_md5_hash_matching(filename: str, original_md5_hash: str) -> bool:
|
||||
"""
|
||||
Check if the MD5 hash of a file matches the original hash.
|
||||
|
||||
Note: MD5 is used here for file integrity checking (detecting corruption),
|
||||
not for cryptographic security purposes.
|
||||
|
||||
Parameters:
|
||||
filename (str): The path to the file to be checked as a string.
|
||||
original_md5_hash (str): The original MD5 hash to compare against.
|
||||
@@ -27,8 +30,7 @@ def is_md5_hash_matching(filename: str, original_md5_hash: str) -> bool:
|
||||
|
||||
with open(filename, "rb") as file:
|
||||
file_contents = file.read()
|
||||
computed_md5_hash = hash_new(name="MD5")
|
||||
computed_md5_hash.update(file_contents)
|
||||
computed_md5_hash = md5(file_contents, usedforsecurity=False)
|
||||
|
||||
return computed_md5_hash.hexdigest() == original_md5_hash
|
||||
|
||||
@@ -57,7 +59,9 @@ def download_assets(asset_name: VideoAssets | str) -> str:
|
||||
|
||||
if not Path(filename).exists() and filename in VIDEO_ASSETS:
|
||||
print(f"Downloading {filename} assets \n")
|
||||
response = get(VIDEO_ASSETS[filename][0], stream=True, allow_redirects=True)
|
||||
response = get(
|
||||
VIDEO_ASSETS[filename][0], stream=True, allow_redirects=True, timeout=30
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
file_size = int(response.headers.get("Content-Length", 0))
|
||||
|
||||
@@ -100,7 +100,7 @@ def calculate_masks_centroids(masks: np.ndarray) -> np.ndarray:
|
||||
A 2D NumPy array of shape (num_masks, 2), where each row contains the x and y
|
||||
coordinates (in that order) of the centroid of the corresponding mask.
|
||||
"""
|
||||
num_masks, height, width = masks.shape
|
||||
_num_masks, height, width = masks.shape
|
||||
total_pixels = masks.sum(axis=(1, 2))
|
||||
|
||||
# offset for 1-based indexing
|
||||
|
||||
@@ -575,7 +575,7 @@ def from_florence_2(
|
||||
labels = np.array([result_string])
|
||||
return xyxy, labels, None, None
|
||||
|
||||
assert False, f"Unimplemented task: {task}"
|
||||
raise RuntimeError(f"Unimplemented task: {task}")
|
||||
|
||||
|
||||
def from_google_gemini_2_0(
|
||||
|
||||
@@ -247,7 +247,7 @@ class ByteTrack:
|
||||
if strack_pool[i].state == TrackState.Tracked
|
||||
]
|
||||
dists = matching.iou_distance(r_tracked_stracks, detections_second)
|
||||
matches, u_track, u_detection_second = matching.linear_assignment(
|
||||
matches, u_track, _u_detection_second = matching.linear_assignment(
|
||||
dists, thresh=0.5
|
||||
)
|
||||
for itracked, idet in matches:
|
||||
|
||||
@@ -98,7 +98,7 @@ def plot_images_grid(
|
||||
" or reduce the number of images."
|
||||
)
|
||||
|
||||
fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=size)
|
||||
_fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=size)
|
||||
|
||||
for idx, ax in enumerate(axes.flat):
|
||||
if idx < len(images):
|
||||
|
||||
@@ -11,7 +11,7 @@ from test.test_utils import mock_detections
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, detection_idx, color_lookup, expected_result, exception",
|
||||
("detections", "detection_idx", "color_lookup", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
mock_detections(
|
||||
@@ -111,7 +111,7 @@ def test_resolve_color_idx(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"text, max_line_length, expected_result, exception",
|
||||
("text", "max_line_length", "expected_result", "exception"),
|
||||
[
|
||||
(None, None, [""], DoesNotRaise()), # text is None
|
||||
("", None, [""], DoesNotRaise()), # empty string
|
||||
|
||||
@@ -9,7 +9,7 @@ from supervision.classification.core import Classifications
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"class_id, confidence, k, expected_result, exception",
|
||||
("class_id", "confidence", "k", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([0, 1, 2, 3, 4]),
|
||||
|
||||
@@ -39,7 +39,7 @@ def mock_coco_annotation(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"coco_categories, expected_result, exception",
|
||||
("coco_categories", "expected_result", "exception"),
|
||||
[
|
||||
([], [], DoesNotRaise()), # empty coco categories
|
||||
(
|
||||
@@ -87,7 +87,7 @@ def test_coco_categories_to_classes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"classes, exception",
|
||||
("classes", "exception"),
|
||||
[
|
||||
([], DoesNotRaise()), # empty classes
|
||||
(["baseball cap"], DoesNotRaise()), # single class
|
||||
@@ -104,7 +104,7 @@ def test_classes_to_coco_categories_and_back_to_classes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"coco_annotations, expected_result, exception",
|
||||
("coco_annotations", "expected_result", "exception"),
|
||||
[
|
||||
([], {}, DoesNotRaise()), # empty coco annotations
|
||||
(
|
||||
@@ -163,8 +163,14 @@ def test_group_coco_annotations_by_image_id(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_annotations, resolution_wh, with_masks, use_iscrowd, "
|
||||
"expected_result, exception",
|
||||
(
|
||||
"image_annotations",
|
||||
"resolution_wh",
|
||||
"with_masks",
|
||||
"use_iscrowd",
|
||||
"expected_result",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
(
|
||||
[],
|
||||
@@ -601,7 +607,7 @@ def test_coco_annotations_to_detections(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"coco_categories, target_classes, expected_result, exception",
|
||||
("coco_categories", "target_classes", "expected_result", "exception"),
|
||||
[
|
||||
([], [], {}, DoesNotRaise()), # empty coco categories
|
||||
(
|
||||
@@ -660,7 +666,7 @@ def test_build_coco_class_index_mapping(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, image_id, annotation_id, expected_result, exception",
|
||||
("detections", "image_id", "annotation_id", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
Detections(
|
||||
|
||||
@@ -31,7 +31,7 @@ def are_xml_elements_equal(elem1, elem2):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, name, polygon, expected_result, exception",
|
||||
("xyxy", "name", "polygon", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([0, 0, 10, 10]),
|
||||
@@ -71,7 +71,7 @@ def test_object_to_pascal_voc(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"polygon_element, expected_result, exception",
|
||||
("polygon_element", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
ElementTree.fromstring(
|
||||
@@ -116,7 +116,14 @@ NO_DETECTIONS = """<annotation></annotation>"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xml_string, classes, resolution_wh, force_masks, expected_result, exception",
|
||||
(
|
||||
"xml_string",
|
||||
"classes",
|
||||
"resolution_wh",
|
||||
"force_masks",
|
||||
"expected_result",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
(
|
||||
ONE_CLASS_ONE_BBOX,
|
||||
|
||||
@@ -31,7 +31,7 @@ def _arrays_almost_equal(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"lines, expected_result, exception",
|
||||
("lines", "expected_result", "exception"),
|
||||
[
|
||||
([], False, DoesNotRaise()), # empty yolo annotation file
|
||||
(
|
||||
@@ -44,7 +44,6 @@ def _arrays_almost_equal(
|
||||
False,
|
||||
DoesNotRaise(),
|
||||
), # yolo annotation file with two lines with box
|
||||
(["0 0.5 0.5 0.2 0.2"], False, DoesNotRaise()),
|
||||
(
|
||||
["0 0.4 0.4 0.6 0.4 0.6 0.6 0.4 0.6"],
|
||||
True,
|
||||
@@ -66,7 +65,7 @@ def test_with_mask(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"lines, resolution_wh, with_masks, expected_result, exception",
|
||||
("lines", "resolution_wh", "with_masks", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
[],
|
||||
@@ -190,7 +189,7 @@ def test_yolo_annotations_to_detections(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_name, expected_result, exception",
|
||||
("image_name", "expected_result", "exception"),
|
||||
[
|
||||
("image.png", "image.txt", DoesNotRaise()), # simple png image
|
||||
("image.jpeg", "image.txt", DoesNotRaise()), # simple jpeg image
|
||||
@@ -211,7 +210,7 @@ def test_image_name_to_annotation_name(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, class_id, image_shape, polygon, expected_result, exception",
|
||||
("xyxy", "class_id", "image_shape", "polygon", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([100, 100, 200, 200], dtype=np.float32),
|
||||
|
||||
@@ -9,7 +9,7 @@ from test.test_utils import mock_detections
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dataset_list, expected_result, exception",
|
||||
("dataset_list", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
[],
|
||||
|
||||
@@ -22,7 +22,7 @@ T = TypeVar("T")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data, train_ratio, random_state, shuffle, expected_result, exception",
|
||||
("data", "train_ratio", "random_state", "shuffle", "expected_result", "exception"),
|
||||
[
|
||||
([], 0.5, None, False, ([], []), DoesNotRaise()), # empty data
|
||||
(
|
||||
@@ -94,7 +94,7 @@ def test_train_test_split(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"class_lists, expected_result, exception",
|
||||
("class_lists", "expected_result", "exception"),
|
||||
[
|
||||
([], [], DoesNotRaise()), # empty class lists
|
||||
(
|
||||
@@ -128,7 +128,7 @@ def test_merge_class_maps(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source_classes, target_classes, expected_result, exception",
|
||||
("source_classes", "target_classes", "expected_result", "exception"),
|
||||
[
|
||||
([], [], {}, DoesNotRaise()), # empty class lists
|
||||
([], ["dog", "person"], {}, DoesNotRaise()), # empty source class list
|
||||
@@ -178,7 +178,7 @@ def test_build_class_index_mapping(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source_to_target_mapping, detections, expected_result, exception",
|
||||
("source_to_target_mapping", "detections", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
{},
|
||||
@@ -238,7 +238,7 @@ def test_map_detections_class_id(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mask, expected_rle, exception",
|
||||
("mask", "expected_rle", "exception"),
|
||||
[
|
||||
(
|
||||
np.zeros((3, 3)).astype(bool),
|
||||
@@ -297,7 +297,7 @@ def test_mask_to_rle(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"rle, resolution_wh, expected_mask, exception",
|
||||
("rle", "resolution_wh", "expected_mask", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([9]),
|
||||
|
||||
@@ -130,7 +130,7 @@ TEST_DET_DIFFERENT_METADATA = Detections(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, index, expected_result, exception",
|
||||
("detections", "index", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
DETECTIONS,
|
||||
@@ -244,7 +244,7 @@ def test_getitem(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections_list, expected_result, exception",
|
||||
("detections_list", "expected_result", "exception"),
|
||||
[
|
||||
([], Detections.empty(), DoesNotRaise()), # empty detections list
|
||||
(
|
||||
@@ -516,7 +516,7 @@ def test_merge(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, anchor, expected_result, exception",
|
||||
("detections", "anchor", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
Detections.empty(),
|
||||
@@ -598,7 +598,7 @@ def test_get_anchor_coordinates(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections_a, detections_b, expected_result",
|
||||
("detections_a", "detections_b", "expected_result"),
|
||||
[
|
||||
(
|
||||
Detections.empty(),
|
||||
@@ -649,7 +649,7 @@ def test_equal(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detection_1, detection_2, expected_result, exception",
|
||||
("detection_1", "detection_2", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
mock_detections(
|
||||
|
||||
@@ -9,9 +9,14 @@ from test.test_utils import mock_detections
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, custom_data, "
|
||||
"second_detections, second_custom_data, "
|
||||
"file_name, expected_result",
|
||||
(
|
||||
"detections",
|
||||
"custom_data",
|
||||
"second_detections",
|
||||
"second_custom_data",
|
||||
"file_name",
|
||||
"expected_result",
|
||||
),
|
||||
[
|
||||
(
|
||||
mock_detections(
|
||||
@@ -206,9 +211,14 @@ def test_csv_sink(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, custom_data, "
|
||||
"second_detections, second_custom_data, "
|
||||
"file_name, expected_result",
|
||||
(
|
||||
"detections",
|
||||
"custom_data",
|
||||
"second_detections",
|
||||
"second_custom_data",
|
||||
"file_name",
|
||||
"expected_result",
|
||||
),
|
||||
[
|
||||
(
|
||||
mock_detections(
|
||||
|
||||
@@ -9,9 +9,14 @@ from test.test_utils import mock_detections
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, custom_data, "
|
||||
"second_detections, second_custom_data, "
|
||||
"file_name, expected_result",
|
||||
(
|
||||
"detections",
|
||||
"custom_data",
|
||||
"second_detections",
|
||||
"second_custom_data",
|
||||
"file_name",
|
||||
"expected_result",
|
||||
),
|
||||
[
|
||||
(
|
||||
mock_detections(
|
||||
|
||||
@@ -10,7 +10,7 @@ from test.test_utils import mock_detections
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, expected_result, exception",
|
||||
("vector", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
Vector(start=Point(x=0.0, y=0.0), end=Point(x=0.0, y=0.0)),
|
||||
@@ -75,7 +75,7 @@ def test_calculate_region_of_interest_limits(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, xyxy_sequence, expected_crossed_in, expected_crossed_out",
|
||||
("vector", "xyxy_sequence", "expected_crossed_in", "expected_crossed_out"),
|
||||
[
|
||||
( # Vertical line, simple crossing
|
||||
Vector(Point(0, 0), Point(0, 10)),
|
||||
@@ -260,8 +260,13 @@ def test_line_zone_one_detection_default_anchors(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, xyxy_sequence, triggering_anchors, expected_crossed_in, "
|
||||
"expected_crossed_out",
|
||||
(
|
||||
"vector",
|
||||
"xyxy_sequence",
|
||||
"triggering_anchors",
|
||||
"expected_crossed_in",
|
||||
"expected_crossed_out",
|
||||
),
|
||||
[
|
||||
( # Scrape line, left side, corner anchors
|
||||
Vector(Point(0, 0), Point(10, 0)),
|
||||
@@ -425,8 +430,14 @@ def test_line_zone_one_detection(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, xyxy_sequence, anchors, expected_crossed_in, "
|
||||
"expected_crossed_out, exception",
|
||||
(
|
||||
"vector",
|
||||
"xyxy_sequence",
|
||||
"anchors",
|
||||
"expected_crossed_in",
|
||||
"expected_crossed_out",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
( # One stays, one crosses
|
||||
Vector(Point(0, 0), Point(10, 0)),
|
||||
@@ -494,8 +505,14 @@ def test_line_zone_multiple_detections(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, xyxy_sequence, triggering_anchors, minimum_crossing_threshold, "
|
||||
"expected_crossed_in, expected_crossed_out",
|
||||
(
|
||||
"vector",
|
||||
"xyxy_sequence",
|
||||
"triggering_anchors",
|
||||
"minimum_crossing_threshold",
|
||||
"expected_crossed_in",
|
||||
"expected_crossed_out",
|
||||
),
|
||||
[
|
||||
( # Detection lingers around line, all crosses counted
|
||||
Vector(Point(0, 0), Point(10, 0)),
|
||||
@@ -610,9 +627,17 @@ def test_line_zone_one_detection_long_horizon(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, xyxy_sequence, anchors, minimum_crossing_threshold, "
|
||||
"expected_crossed_in, expected_crossed_out, expected_count_in, "
|
||||
"expected_count_out, exception",
|
||||
(
|
||||
"vector",
|
||||
"xyxy_sequence",
|
||||
"anchors",
|
||||
"minimum_crossing_threshold",
|
||||
"expected_crossed_in",
|
||||
"expected_crossed_out",
|
||||
"expected_count_in",
|
||||
"expected_count_out",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
( # One stays, one crosses, one disappears before crossing
|
||||
Vector(Point(0, 0), Point(10, 0)),
|
||||
|
||||
@@ -22,7 +22,7 @@ ANNOTATED_SCENE_0_5_OPACITY = sv.draw_filled_polygon(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"scene, polygon_zone_annotator, expected_results",
|
||||
("scene", "polygon_zone_annotator", "expected_results"),
|
||||
[
|
||||
(
|
||||
SCENE,
|
||||
|
||||
@@ -29,7 +29,7 @@ POLYGON = np.array([[100, 100], [200, 100], [200, 200], [100, 200]])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, polygon_zone, expected_results, exception",
|
||||
("detections", "polygon_zone", "expected_results", "exception"),
|
||||
[
|
||||
(
|
||||
DETECTIONS,
|
||||
@@ -90,7 +90,7 @@ def test_polygon_zone_trigger(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"polygon, triggering_anchors, exception",
|
||||
("polygon", "triggering_anchors", "exception"),
|
||||
[
|
||||
(POLYGON, [sv.Position.CENTER], DoesNotRaise()),
|
||||
(
|
||||
|
||||
@@ -20,7 +20,7 @@ from supervision.detection.vlm import (
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, resolution_wh, classes, expected_results",
|
||||
("exception", "result", "resolution_wh", "classes", "expected_results"),
|
||||
[
|
||||
(
|
||||
does_not_raise(),
|
||||
@@ -202,7 +202,7 @@ def test_from_paligemma(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, input_wh, resolution_wh, classes, expected_results",
|
||||
("exception", "result", "input_wh", "resolution_wh", "classes", "expected_results"),
|
||||
[
|
||||
(
|
||||
does_not_raise(),
|
||||
@@ -405,7 +405,7 @@ def test_from_qwen_2_5_vl(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, resolution_wh, classes, expected_results",
|
||||
("exception", "result", "resolution_wh", "classes", "expected_results"),
|
||||
[
|
||||
(
|
||||
does_not_raise(),
|
||||
@@ -544,7 +544,7 @@ def test_from_google_gemini(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, resolution_wh, expected_results",
|
||||
("exception", "result", "resolution_wh", "expected_results"),
|
||||
[
|
||||
(
|
||||
does_not_raise(),
|
||||
@@ -644,7 +644,7 @@ def test_from_moondream(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"florence_result, resolution_wh, expected_results, exception",
|
||||
("florence_result", "resolution_wh", "expected_results", "exception"),
|
||||
[
|
||||
( # Object detection: empty
|
||||
{"<OD>": {"bboxes": [], "labels": []}},
|
||||
@@ -792,38 +792,6 @@ def test_from_moondream(
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
( # Referring Expression Segmentation
|
||||
{
|
||||
"<REFERRING_EXPRESSION_SEGMENTATION>": {
|
||||
"polygons": [[[1, 1, 2, 1, 2, 2, 1, 2]]],
|
||||
"labels": [""],
|
||||
}
|
||||
},
|
||||
(10, 10),
|
||||
(
|
||||
np.array([[1.0, 1.0, 2.0, 2.0]], dtype=np.float32),
|
||||
None,
|
||||
np.array(
|
||||
[
|
||||
[
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
]
|
||||
],
|
||||
dtype=bool,
|
||||
),
|
||||
None,
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
( # OCR: unsupported
|
||||
{"<OCR>": "A"},
|
||||
(10, 10),
|
||||
@@ -928,7 +896,7 @@ def test_florence_2(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, resolution_wh, classes, expected_results",
|
||||
("exception", "result", "resolution_wh", "classes", "expected_results"),
|
||||
[
|
||||
(
|
||||
does_not_raise(),
|
||||
@@ -1165,7 +1133,7 @@ def test_from_google_gemini_2_5(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, result, resolution_wh, classes, expected_detections",
|
||||
("exception", "result", "resolution_wh", "classes", "expected_detections"),
|
||||
[
|
||||
(
|
||||
pytest.raises(ValueError),
|
||||
|
||||
@@ -18,7 +18,7 @@ def mock_callback():
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"resolution_wh, slice_wh, overlap_wh, expected_offsets",
|
||||
("resolution_wh", "slice_wh", "overlap_wh", "expected_offsets"),
|
||||
[
|
||||
# Case 1: Square image, square slices, no overlap
|
||||
(
|
||||
|
||||
@@ -14,7 +14,7 @@ from supervision.detection.utils.boxes import (
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, resolution_wh, expected_result",
|
||||
("xyxy", "resolution_wh", "expected_result"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 4)),
|
||||
@@ -58,7 +58,7 @@ def test_clip_boxes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, offset, expected_result, exception",
|
||||
("xyxy", "offset", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 4)),
|
||||
@@ -104,7 +104,7 @@ def test_move_boxes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, factor, expected_result, exception",
|
||||
("xyxy", "factor", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 4)),
|
||||
@@ -150,7 +150,7 @@ def test_scale_boxes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, resolution_wh, normalization_factor, expected_result, exception",
|
||||
("xyxy", "resolution_wh", "normalization_factor", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 4)),
|
||||
|
||||
@@ -13,7 +13,7 @@ from supervision.detection.utils.converters import (
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xywh, expected_result",
|
||||
("xywh", "expected_result"),
|
||||
[
|
||||
(np.array([[10, 20, 30, 40]]), np.array([[10, 20, 40, 60]])), # standard case
|
||||
(np.array([[0, 0, 0, 0]]), np.array([[0, 0, 0, 0]])), # zero size bounding box
|
||||
@@ -36,7 +36,7 @@ def test_xywh_to_xyxy(xywh: np.ndarray, expected_result: np.ndarray) -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, expected_result",
|
||||
("xyxy", "expected_result"),
|
||||
[
|
||||
(np.array([[10, 20, 40, 60]]), np.array([[10, 20, 30, 40]])), # standard case
|
||||
(np.array([[0, 0, 0, 0]]), np.array([[0, 0, 0, 0]])), # zero size bounding box
|
||||
@@ -59,7 +59,7 @@ def test_xyxy_to_xywh(xyxy: np.ndarray, expected_result: np.ndarray) -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, expected_result",
|
||||
("xyxy", "expected_result"),
|
||||
[
|
||||
# Empty and zero cases
|
||||
(np.array([]).reshape(0, 4), np.array([]).reshape(0, 4)), # empty array
|
||||
@@ -110,7 +110,7 @@ def test_xyxy_to_xcycarh(xyxy: np.ndarray, expected_result: np.ndarray) -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xcycwh, expected_result",
|
||||
("xcycwh", "expected_result"),
|
||||
[
|
||||
(np.array([[50, 50, 20, 30]]), np.array([[40, 35, 60, 65]])), # standard case
|
||||
(np.array([[0, 0, 0, 0]]), np.array([[0, 0, 0, 0]])), # zero size bounding box
|
||||
@@ -133,7 +133,7 @@ def test_xcycwh_to_xyxy(xcycwh: np.ndarray, expected_result: np.ndarray) -> None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"boxes,resolution_wh,expected",
|
||||
("boxes", "resolution_wh", "expected"),
|
||||
[
|
||||
# 0) Empty input
|
||||
(
|
||||
|
||||
@@ -19,7 +19,7 @@ TEST_MASK[:, 300:351, 200:251] = True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"roboflow_result, expected_result, exception",
|
||||
("roboflow_result", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
{"predictions": [], "image": {"width": 1000, "height": 1000}},
|
||||
@@ -251,7 +251,7 @@ def test_process_roboflow_result(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data_list, expected_result, exception",
|
||||
("data_list", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
[],
|
||||
@@ -445,7 +445,7 @@ def test_merge_data(
|
||||
with exception:
|
||||
result = merge_data(data_list=data_list)
|
||||
if expected_result is None:
|
||||
assert False, f"Expected an error, but got result {result}"
|
||||
pytest.fail(f"Expected an error, but got result {result}")
|
||||
|
||||
for key in result:
|
||||
if isinstance(result[key], np.ndarray):
|
||||
@@ -459,7 +459,7 @@ def test_merge_data(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data, index, expected_result, exception",
|
||||
("data", "index", "expected_result", "exception"),
|
||||
[
|
||||
({}, 0, {}, DoesNotRaise()), # empty data dict
|
||||
(
|
||||
@@ -632,7 +632,7 @@ def test_get_data_item(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"metadata_list, expected_result, exception",
|
||||
("metadata_list", "expected_result", "exception"),
|
||||
[
|
||||
# Identical metadata with a single key
|
||||
([{"key1": "value1"}, {"key1": "value1"}], {"key1": "value1"}, DoesNotRaise()),
|
||||
|
||||
@@ -18,7 +18,7 @@ from test.test_utils import random_boxes
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, iou_threshold, expected_result, exception",
|
||||
("predictions", "iou_threshold", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 5), dtype=float),
|
||||
@@ -145,7 +145,7 @@ def test_group_overlapping_boxes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, iou_threshold, expected_result, exception",
|
||||
("predictions", "iou_threshold", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty(shape=(0, 5)),
|
||||
@@ -250,7 +250,7 @@ def test_box_non_max_suppression(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, masks, iou_threshold, expected_result, exception",
|
||||
("predictions", "masks", "iou_threshold", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty((0, 6)),
|
||||
@@ -456,7 +456,7 @@ def test_mask_non_max_suppression(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, masks, iou_threshold, expected_result, exception",
|
||||
("predictions", "masks", "iou_threshold", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.empty((0, 6)),
|
||||
@@ -638,7 +638,7 @@ def test_mask_non_max_merge(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"box_true, box_detection, overlap_metric, expected_overlap, exception",
|
||||
("box_true", "box_detection", "overlap_metric", "expected_overlap", "exception"),
|
||||
[
|
||||
(
|
||||
[100.0, 100.0, 200.0, 200.0],
|
||||
@@ -689,13 +689,6 @@ def test_mask_non_max_merge(
|
||||
1.0,
|
||||
DoesNotRaise(),
|
||||
), # identical boxes, both boxes are arrays, IOU as uppercase string
|
||||
(
|
||||
[0.0, 0.0, 10.0, 10.0],
|
||||
[0.0, 0.0, 10.0, 10.0],
|
||||
"IOU",
|
||||
1.0,
|
||||
DoesNotRaise(),
|
||||
), # identical boxes, both boxes are arrays, IOS as uppercase string
|
||||
(
|
||||
[0.0, 0.0, 10.0, 10.0],
|
||||
[20.0, 20.0, 30.0, 30.0],
|
||||
@@ -813,7 +806,13 @@ def test_box_iou(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"boxes_true, boxes_detection, overlap_metric, expected_overlap, exception",
|
||||
(
|
||||
"boxes_true",
|
||||
"boxes_detection",
|
||||
"overlap_metric",
|
||||
"expected_overlap",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
# both inputs empty
|
||||
(
|
||||
@@ -1086,7 +1085,7 @@ def test_box_iou_batch(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_true, num_det",
|
||||
("num_true", "num_det"),
|
||||
[
|
||||
(5, 5),
|
||||
(5, 10),
|
||||
|
||||
@@ -16,7 +16,7 @@ from supervision.detection.utils.masks import (
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"masks, offset, resolution_wh, expected_result, exception",
|
||||
("masks", "offset", "resolution_wh", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array(
|
||||
@@ -278,7 +278,7 @@ def test_move_masks(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"masks, expected_result, exception",
|
||||
("masks", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array(
|
||||
@@ -369,7 +369,7 @@ def test_calculate_masks_centroids(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mask, expected_result, exception",
|
||||
("mask", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 1, 0]]).astype(
|
||||
@@ -424,7 +424,7 @@ def test_contains_holes(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mask, connectivity, expected_result, exception",
|
||||
("mask", "connectivity", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 1, 0]]).astype(
|
||||
@@ -504,7 +504,15 @@ def test_contains_multiple_segments(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mask, connectivity, mode, absolute_distance, relative_distance, expected_result, exception", # noqa: E501
|
||||
(
|
||||
"mask",
|
||||
"connectivity",
|
||||
"mode",
|
||||
"absolute_distance",
|
||||
"relative_distance",
|
||||
"expected_result",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
# single component, unchanged
|
||||
(
|
||||
|
||||
@@ -9,7 +9,7 @@ from supervision.detection.utils.polygons import filter_polygons_by_area
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"polygons, min_area, max_area, expected_result, exception",
|
||||
("polygons", "min_area", "max_area", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
[np.array([[0, 0], [0, 10], [10, 10], [10, 0]])],
|
||||
|
||||
@@ -4,7 +4,7 @@ from supervision.detection.utils.vlms import edit_distance, fuzzy_match_index
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"string_1, string_2, case_sensitive, expected_result",
|
||||
("string_1", "string_2", "case_sensitive", "expected_result"),
|
||||
[
|
||||
# identical strings, various cases
|
||||
("hello", "hello", True, 0),
|
||||
@@ -68,7 +68,7 @@ def test_edit_distance(string_1, string_2, case_sensitive, expected_result):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"candidates, query, threshold, case_sensitive, expected_result",
|
||||
("candidates", "query", "threshold", "case_sensitive", "expected_result"),
|
||||
[
|
||||
# exact match at index 0
|
||||
(["cat", "dog", "rat"], "cat", 0, True, 0),
|
||||
|
||||
@@ -8,7 +8,7 @@ from supervision.draw.color import Color
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"color_hex, expected_result, exception",
|
||||
("color_hex", "expected_result", "exception"),
|
||||
[
|
||||
("fff", Color.WHITE, DoesNotRaise()),
|
||||
("#fff", Color.WHITE, DoesNotRaise()),
|
||||
@@ -34,7 +34,7 @@ def test_color_from_hex(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"color, expected_result, exception",
|
||||
("color", "expected_result", "exception"),
|
||||
[
|
||||
(Color.WHITE, "#ffffff", DoesNotRaise()),
|
||||
(Color.BLACK, "#000000", DoesNotRaise()),
|
||||
|
||||
@@ -4,7 +4,7 @@ from supervision.geometry.core import Point, Vector
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, point, expected_result",
|
||||
("vector", "point", "expected_result"),
|
||||
[
|
||||
(Vector(start=Point(x=0, y=0), end=Point(x=5, y=5)), Point(x=-1, y=1), 10.0),
|
||||
(Vector(start=Point(x=0, y=0), end=Point(x=5, y=5)), Point(x=6, y=6), 0.0),
|
||||
@@ -34,7 +34,7 @@ def test_vector_cross_product(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vector, expected_result",
|
||||
("vector", "expected_result"),
|
||||
[
|
||||
(Vector(start=Point(x=0, y=0), end=Point(x=0, y=0)), 0.0),
|
||||
(Vector(start=Point(x=1, y=0), end=Point(x=0, y=0)), 1.0),
|
||||
|
||||
@@ -35,7 +35,7 @@ def generate_test_polygon(n: int) -> np.ndarray:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"polygon, expected_result",
|
||||
("polygon", "expected_result"),
|
||||
[
|
||||
(generate_test_polygon(10), Point(x=5.0, y=12.0)),
|
||||
(generate_test_polygon(50), Point(x=25.0, y=61.0)),
|
||||
|
||||
@@ -22,7 +22,7 @@ KEY_POINTS = mock_key_points(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"key_points, index, expected_result, exception",
|
||||
("key_points", "index", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
KeyPoints.empty(),
|
||||
|
||||
@@ -123,7 +123,7 @@ BAD_CONF_MATRIX = worsen_ideal_conf_matrix(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, with_confidence, expected_result, exception",
|
||||
("detections", "with_confidence", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
Detections.empty(),
|
||||
@@ -187,8 +187,15 @@ def test_detections_to_tensor(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, targets, classes, conf_threshold, iou_threshold, expected_result,"
|
||||
" exception",
|
||||
(
|
||||
"predictions",
|
||||
"targets",
|
||||
"classes",
|
||||
"conf_threshold",
|
||||
"iou_threshold",
|
||||
"expected_result",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
(
|
||||
DETECTION_TENSORS,
|
||||
@@ -359,8 +366,15 @@ def test_from_tensors(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"predictions, targets, num_classes, conf_threshold, iou_threshold, expected_result,"
|
||||
" exception",
|
||||
(
|
||||
"predictions",
|
||||
"targets",
|
||||
"num_classes",
|
||||
"conf_threshold",
|
||||
"iou_threshold",
|
||||
"expected_result",
|
||||
"exception",
|
||||
),
|
||||
[
|
||||
(
|
||||
DETECTION_TENSORS[0],
|
||||
@@ -396,7 +410,7 @@ def test_evaluate_detection_batch(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"matches, expected_result, exception",
|
||||
("matches", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
IDEAL_MATCHES,
|
||||
@@ -417,7 +431,7 @@ def test_drop_extra_matches(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"recall, precision, expected_result, exception",
|
||||
("recall", "precision", "expected_result", "exception"),
|
||||
[
|
||||
(
|
||||
np.array([1.0]),
|
||||
|
||||
@@ -11,7 +11,7 @@ class TestMeanAveragePrecisionArea:
|
||||
"""Test area calculation in MeanAveragePrecision."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xyxy, expected_areas, expected_size_maps",
|
||||
("xyxy", "expected_areas", "expected_size_maps"),
|
||||
[
|
||||
(
|
||||
np.array(
|
||||
|
||||
+5
-7
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
@@ -77,18 +76,17 @@ def random_boxes(
|
||||
(`numpy.ndarray`): Array of shape `(count, 4)` with bounding boxes as
|
||||
`(x_min, y_min, x_max, y_max)`.
|
||||
"""
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
img_w, img_h = image_size
|
||||
out = np.zeros((count, 4), dtype=np.float32)
|
||||
|
||||
for i in range(count):
|
||||
w = random.uniform(min_box_size, max_box_size)
|
||||
h = random.uniform(min_box_size, max_box_size)
|
||||
w = rng.uniform(min_box_size, max_box_size)
|
||||
h = rng.uniform(min_box_size, max_box_size)
|
||||
|
||||
x_min = random.uniform(0, img_w - w)
|
||||
y_min = random.uniform(0, img_h - h)
|
||||
x_min = rng.uniform(0, img_w - w)
|
||||
y_min = rng.uniform(0, img_h - h)
|
||||
x_max = x_min + w
|
||||
y_max = y_min + h
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import supervision as sv
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"detections, expected_results",
|
||||
("detections", "expected_results"),
|
||||
[
|
||||
(
|
||||
[
|
||||
|
||||
@@ -12,12 +12,11 @@ Line 2
|
||||
Line 3
|
||||
"""
|
||||
|
||||
FILE_2_CONTENT = """
|
||||
Line 2
|
||||
FILE_2_CONTENT = """ \nLine 2
|
||||
|
||||
Line 4
|
||||
|
||||
""" # noqa
|
||||
"""
|
||||
|
||||
FILE_3_CONTENT = """
|
||||
Line 2
|
||||
@@ -44,7 +43,7 @@ def setup_and_teardown_files():
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name, skip_empty, expected_result, exception",
|
||||
("file_name", "skip_empty", "expected_result", "exception"),
|
||||
[
|
||||
("file_1.txt", False, ["Line 1", "Line 2", "Line 3"], DoesNotRaise()),
|
||||
("file_2.txt", True, ["Line 2", "Line 4"], DoesNotRaise()),
|
||||
|
||||
@@ -103,7 +103,7 @@ def test_letterbox_image_for_pillow_image() -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image, xyxy, expected_size",
|
||||
("image", "xyxy", "expected_size"),
|
||||
[
|
||||
# NumPy RGB
|
||||
(
|
||||
@@ -143,7 +143,7 @@ def test_crop_image(image, xyxy, expected_size):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image, expected",
|
||||
("image", "expected"),
|
||||
[
|
||||
# NumPy RGB
|
||||
(np.zeros((4, 6, 3), dtype=np.uint8), (6, 4)),
|
||||
|
||||
@@ -74,7 +74,7 @@ class MockDataclass:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_instance, include_properties, expected, exception",
|
||||
("input_instance", "include_properties", "expected", "exception"),
|
||||
[
|
||||
(
|
||||
MockClass,
|
||||
@@ -184,20 +184,6 @@ class MockDataclass:
|
||||
},
|
||||
DoesNotRaise(),
|
||||
),
|
||||
(
|
||||
Detections.empty(),
|
||||
False,
|
||||
{
|
||||
"xyxy",
|
||||
"class_id",
|
||||
"confidence",
|
||||
"mask",
|
||||
"tracker_id",
|
||||
"data",
|
||||
"metadata",
|
||||
},
|
||||
DoesNotRaise(),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_instance_variables(
|
||||
|
||||
@@ -4,7 +4,7 @@ from supervision.utils.iterables import create_batches, fill
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, batch_size, expected",
|
||||
("sequence", "batch_size", "expected"),
|
||||
[
|
||||
# Empty sequence, non-zero batch size. Expect empty list.
|
||||
([], 4, []),
|
||||
@@ -24,7 +24,7 @@ def test_create_batches(sequence, batch_size, expected) -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, desired_size, content, expected",
|
||||
("sequence", "desired_size", "content", "expected"),
|
||||
[
|
||||
# Empty sequence, desired size 0. Expect empty list.
|
||||
([], 0, 1, []),
|
||||
|
||||
Reference in New Issue
Block a user