seetapsych-attributes 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- seetapsych_attributes-0.0.2/.github/workflows/ci.yml +156 -0
- seetapsych_attributes-0.0.2/.github/workflows/publish.yml +188 -0
- seetapsych_attributes-0.0.2/.gitignore +33 -0
- seetapsych_attributes-0.0.2/.vscode/launch.json +14 -0
- seetapsych_attributes-0.0.2/.vscode/settings.json +11 -0
- seetapsych_attributes-0.0.2/DEVELOPMENT.md +96 -0
- seetapsych_attributes-0.0.2/LICENSE +15 -0
- seetapsych_attributes-0.0.2/PKG-INFO +742 -0
- seetapsych_attributes-0.0.2/README.md +707 -0
- seetapsych_attributes-0.0.2/pyproject.toml +104 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/__init__.py +13 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/_version.py +24 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/__init__.py +23 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/__init__.py +25 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/action_units.py +63 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/dense_landmarks.py +33 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/detection.py +26 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/dimensional_affect.py +41 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/expression.py +44 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/gaze_screen.py +54 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/heart_rate.py +45 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/landmarks.py +35 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/mesh.py +33 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/face/selection.py +34 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/head/__init__.py +21 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/head/detection.py +35 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/head/gaze_point.py +53 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/head/selection.py +40 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/schema/head/social_gaze.py +96 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/types/__init__.py +114 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/types/face.py +211 -0
- seetapsych_attributes-0.0.2/seetapsych_attributes/types/head.py +88 -0
- seetapsych_attributes-0.0.2/tests/__init__.py +0 -0
- seetapsych_attributes-0.0.2/tests/test_attributes.py +8 -0
- seetapsych_attributes-0.0.2/tools/generate_readme.py +141 -0
- seetapsych_attributes-0.0.2/tools/header.md +62 -0
- seetapsych_attributes-0.0.2/uv.lock +1405 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- workflows
|
|
8
|
+
- "workflows/**"
|
|
9
|
+
tags-ignore: ["r*"]
|
|
10
|
+
pull_request:
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
lint:
|
|
18
|
+
name: Lint & Type & Security
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
|
|
25
|
+
- name: Derive package directory
|
|
26
|
+
id: pkg
|
|
27
|
+
run: |
|
|
28
|
+
REPO_NAME="${{ github.event.repository.name }}"
|
|
29
|
+
PACKAGE_DIR="${REPO_NAME//-/_}"
|
|
30
|
+
echo "PACKAGE_DIR=$PACKAGE_DIR" >> "$GITHUB_OUTPUT"
|
|
31
|
+
shell: bash
|
|
32
|
+
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.12"
|
|
37
|
+
|
|
38
|
+
- name: Install uv
|
|
39
|
+
uses: astral-sh/setup-uv@v3
|
|
40
|
+
with:
|
|
41
|
+
enable-cache: true
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: uv sync --group dev
|
|
45
|
+
|
|
46
|
+
- name: Run all lint/type/security checks (collect all failures)
|
|
47
|
+
env:
|
|
48
|
+
PACKAGE_DIR: ${{ steps.pkg.outputs.PACKAGE_DIR }}
|
|
49
|
+
run: |
|
|
50
|
+
set +e
|
|
51
|
+
EXIT_CODE=0
|
|
52
|
+
|
|
53
|
+
echo "=== ruff check ==="
|
|
54
|
+
uv run ruff check .
|
|
55
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
56
|
+
|
|
57
|
+
echo ""
|
|
58
|
+
echo "=== ruff format --check ==="
|
|
59
|
+
uv run ruff format --check .
|
|
60
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
echo "=== mypy ==="
|
|
64
|
+
uv run mypy "$PACKAGE_DIR"
|
|
65
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
66
|
+
|
|
67
|
+
echo ""
|
|
68
|
+
echo "=== bandit ==="
|
|
69
|
+
uv run bandit -r "$PACKAGE_DIR" -c pyproject.toml
|
|
70
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
71
|
+
|
|
72
|
+
exit $EXIT_CODE
|
|
73
|
+
shell: bash
|
|
74
|
+
|
|
75
|
+
test:
|
|
76
|
+
name: Test (Python ${{ matrix.python-version }} on ${{ matrix.os }})
|
|
77
|
+
runs-on: ${{ matrix.os }}
|
|
78
|
+
needs: lint
|
|
79
|
+
strategy:
|
|
80
|
+
fail-fast: false
|
|
81
|
+
matrix:
|
|
82
|
+
include:
|
|
83
|
+
- python-version: "3.10"
|
|
84
|
+
os: ubuntu-latest
|
|
85
|
+
- python-version: "3.10"
|
|
86
|
+
os: windows-latest
|
|
87
|
+
- python-version: "3.11"
|
|
88
|
+
os: ubuntu-latest
|
|
89
|
+
- python-version: "3.11"
|
|
90
|
+
os: windows-latest
|
|
91
|
+
- python-version: "3.12"
|
|
92
|
+
os: ubuntu-latest
|
|
93
|
+
- python-version: "3.12"
|
|
94
|
+
os: windows-latest
|
|
95
|
+
- python-version: "3.12"
|
|
96
|
+
os: macos-latest
|
|
97
|
+
- python-version: "3.13"
|
|
98
|
+
os: ubuntu-latest
|
|
99
|
+
- python-version: "3.13"
|
|
100
|
+
os: windows-latest
|
|
101
|
+
- python-version: "3.14"
|
|
102
|
+
os: ubuntu-latest
|
|
103
|
+
- python-version: "3.14"
|
|
104
|
+
os: windows-latest
|
|
105
|
+
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v4
|
|
108
|
+
with:
|
|
109
|
+
fetch-depth: 0
|
|
110
|
+
|
|
111
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
112
|
+
uses: actions/setup-python@v5
|
|
113
|
+
with:
|
|
114
|
+
python-version: ${{ matrix.python-version }}
|
|
115
|
+
|
|
116
|
+
- name: Install uv
|
|
117
|
+
uses: astral-sh/setup-uv@v3
|
|
118
|
+
with:
|
|
119
|
+
enable-cache: true
|
|
120
|
+
|
|
121
|
+
- name: Install dependencies
|
|
122
|
+
run: uv sync --group dev
|
|
123
|
+
|
|
124
|
+
- name: Run pytest
|
|
125
|
+
run: uv run pytest
|
|
126
|
+
|
|
127
|
+
build:
|
|
128
|
+
name: Build package
|
|
129
|
+
runs-on: ubuntu-latest
|
|
130
|
+
needs: test
|
|
131
|
+
|
|
132
|
+
steps:
|
|
133
|
+
- uses: actions/checkout@v4
|
|
134
|
+
with:
|
|
135
|
+
fetch-depth: 0
|
|
136
|
+
|
|
137
|
+
- name: Set up Python
|
|
138
|
+
uses: actions/setup-python@v5
|
|
139
|
+
with:
|
|
140
|
+
python-version: "3.12"
|
|
141
|
+
|
|
142
|
+
- name: Install build tools
|
|
143
|
+
run: python -m pip install --upgrade build twine
|
|
144
|
+
|
|
145
|
+
- name: Build package
|
|
146
|
+
run: python -m build
|
|
147
|
+
|
|
148
|
+
- name: Verify built artifacts
|
|
149
|
+
run: twine check dist/*
|
|
150
|
+
|
|
151
|
+
- name: Upload dist artifacts
|
|
152
|
+
uses: actions/upload-artifact@v4
|
|
153
|
+
with:
|
|
154
|
+
name: dist-artifacts
|
|
155
|
+
path: dist/
|
|
156
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
name: Publish to PyPI & GitHub Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "r*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Pytest smoke gate
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v3
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --group dev
|
|
29
|
+
|
|
30
|
+
- name: Run pytest (release gate)
|
|
31
|
+
run: uv run pytest
|
|
32
|
+
|
|
33
|
+
github-release:
|
|
34
|
+
name: Build and create GitHub Release
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
needs: test
|
|
37
|
+
permissions:
|
|
38
|
+
contents: write
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
with:
|
|
43
|
+
fetch-depth: 0
|
|
44
|
+
|
|
45
|
+
- name: Set up Python
|
|
46
|
+
uses: actions/setup-python@v5
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.12"
|
|
49
|
+
|
|
50
|
+
- name: Install build tools
|
|
51
|
+
run: python -m pip install --upgrade build twine
|
|
52
|
+
|
|
53
|
+
- name: Build package
|
|
54
|
+
run: python -m build
|
|
55
|
+
|
|
56
|
+
- name: Verify built artifacts
|
|
57
|
+
run: twine check dist/*
|
|
58
|
+
|
|
59
|
+
- name: Extract tag name
|
|
60
|
+
id: get_tag
|
|
61
|
+
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
|
62
|
+
shell: bash
|
|
63
|
+
|
|
64
|
+
- name: Determine release type
|
|
65
|
+
id: release_type
|
|
66
|
+
run: |
|
|
67
|
+
TAG="${{ steps.get_tag.outputs.TAG }}"
|
|
68
|
+
if [[ "$TAG" == *-* ]]; then
|
|
69
|
+
echo "PYPI_PUBLISH=false" >> "$GITHUB_OUTPUT"
|
|
70
|
+
echo "PRERELEASE=true" >> "$GITHUB_OUTPUT"
|
|
71
|
+
else
|
|
72
|
+
echo "PYPI_PUBLISH=true" >> "$GITHUB_OUTPUT"
|
|
73
|
+
echo "PRERELEASE=false" >> "$GITHUB_OUTPUT"
|
|
74
|
+
fi
|
|
75
|
+
shell: bash
|
|
76
|
+
|
|
77
|
+
- name: Discover dist assets
|
|
78
|
+
id: assets
|
|
79
|
+
run: |
|
|
80
|
+
SDIST=$(ls dist/*.tar.gz | head -n1)
|
|
81
|
+
WHEEL=$(ls dist/*.whl | head -n1)
|
|
82
|
+
echo "SDIST=$SDIST" >> "$GITHUB_OUTPUT"
|
|
83
|
+
echo "WHEEL=$WHEEL" >> "$GITHUB_OUTPUT"
|
|
84
|
+
echo "SDIST_NAME=$(basename $SDIST)" >> "$GITHUB_OUTPUT"
|
|
85
|
+
echo "WHEEL_NAME=$(basename $WHEEL)" >> "$GITHUB_OUTPUT"
|
|
86
|
+
shell: bash
|
|
87
|
+
|
|
88
|
+
- name: Compose release body
|
|
89
|
+
id: release_body
|
|
90
|
+
env:
|
|
91
|
+
PYPI_PUBLISH: ${{ steps.release_type.outputs.PYPI_PUBLISH }}
|
|
92
|
+
REPO: ${{ github.repository }}
|
|
93
|
+
GITHUB_REF_NAME: ${{ github.ref_name }}
|
|
94
|
+
run: |
|
|
95
|
+
PROJ_NAME="${REPO#*/}"
|
|
96
|
+
VERSION="${GITHUB_REF_NAME#r}"
|
|
97
|
+
BODY_FILE=$(mktemp)
|
|
98
|
+
if [ "$PYPI_PUBLISH" = "true" ]; then
|
|
99
|
+
{
|
|
100
|
+
echo "Install from PyPI:"
|
|
101
|
+
echo ""
|
|
102
|
+
echo '```bash'
|
|
103
|
+
echo "pip install ${PROJ_NAME}==${VERSION}"
|
|
104
|
+
echo '```'
|
|
105
|
+
echo ""
|
|
106
|
+
echo "PyPI page: https://pypi.org/project/${PROJ_NAME}/${VERSION}/"
|
|
107
|
+
} >"$BODY_FILE"
|
|
108
|
+
else
|
|
109
|
+
{
|
|
110
|
+
echo "**Preview build** \u2014 available only from GitHub Assets."
|
|
111
|
+
echo ""
|
|
112
|
+
echo "This build is not published to PyPI."
|
|
113
|
+
echo ""
|
|
114
|
+
echo "To try it, download the wheel from the Assets section below and install:"
|
|
115
|
+
echo ""
|
|
116
|
+
echo '```bash'
|
|
117
|
+
echo "pip install ./${PROJ_NAME}-*.whl"
|
|
118
|
+
echo '```'
|
|
119
|
+
} >"$BODY_FILE"
|
|
120
|
+
fi
|
|
121
|
+
{
|
|
122
|
+
echo "BODY<<GITHUB_EOF_MARKER"
|
|
123
|
+
cat "$BODY_FILE"
|
|
124
|
+
echo "GITHUB_EOF_MARKER"
|
|
125
|
+
} >> "$GITHUB_OUTPUT"
|
|
126
|
+
rm -f "$BODY_FILE"
|
|
127
|
+
shell: bash
|
|
128
|
+
|
|
129
|
+
- name: Upload dist artifacts
|
|
130
|
+
uses: actions/upload-artifact@v4
|
|
131
|
+
with:
|
|
132
|
+
name: dist-artifacts-${{ steps.get_tag.outputs.TAG }}
|
|
133
|
+
path: dist/
|
|
134
|
+
if-no-files-found: error
|
|
135
|
+
|
|
136
|
+
- name: Create GitHub Release
|
|
137
|
+
id: create_release
|
|
138
|
+
uses: actions/create-release@v1
|
|
139
|
+
env:
|
|
140
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
141
|
+
with:
|
|
142
|
+
tag_name: ${{ steps.get_tag.outputs.TAG }}
|
|
143
|
+
release_name: Release ${{ steps.get_tag.outputs.TAG }}
|
|
144
|
+
body: ${{ steps.release_body.outputs.BODY }}
|
|
145
|
+
draft: false
|
|
146
|
+
prerelease: ${{ steps.release_type.outputs.PRERELEASE }}
|
|
147
|
+
|
|
148
|
+
- name: Upload sdist to GitHub Release
|
|
149
|
+
uses: actions/upload-release-asset@v1
|
|
150
|
+
env:
|
|
151
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
152
|
+
with:
|
|
153
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
154
|
+
asset_path: ${{ steps.assets.outputs.SDIST }}
|
|
155
|
+
asset_name: ${{ steps.assets.outputs.SDIST_NAME }}
|
|
156
|
+
asset_content_type: application/gzip
|
|
157
|
+
|
|
158
|
+
- name: Upload wheel to GitHub Release
|
|
159
|
+
uses: actions/upload-release-asset@v1
|
|
160
|
+
env:
|
|
161
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
162
|
+
with:
|
|
163
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
164
|
+
asset_path: ${{ steps.assets.outputs.WHEEL }}
|
|
165
|
+
asset_name: ${{ steps.assets.outputs.WHEEL_NAME }}
|
|
166
|
+
asset_content_type: application/zip
|
|
167
|
+
|
|
168
|
+
pypi-publish:
|
|
169
|
+
name: Publish to PyPI
|
|
170
|
+
runs-on: ubuntu-latest
|
|
171
|
+
needs: github-release
|
|
172
|
+
if: startsWith(github.ref, 'refs/tags/r') && !contains(github.ref_name, '-')
|
|
173
|
+
environment:
|
|
174
|
+
name: pypi
|
|
175
|
+
url: https://pypi.org/p/${{ github.event.repository.name }}
|
|
176
|
+
permissions:
|
|
177
|
+
id-token: write
|
|
178
|
+
contents: read
|
|
179
|
+
|
|
180
|
+
steps:
|
|
181
|
+
- name: Download dist artifacts from github-release job
|
|
182
|
+
uses: actions/download-artifact@v4
|
|
183
|
+
with:
|
|
184
|
+
name: dist-artifacts-${{ github.ref_name }}
|
|
185
|
+
path: dist
|
|
186
|
+
|
|
187
|
+
- name: Publish package distributions to PyPI
|
|
188
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# project
|
|
2
|
+
/.idea/
|
|
3
|
+
/.venv/
|
|
4
|
+
/build/
|
|
5
|
+
/dist/
|
|
6
|
+
/*.egg-info/
|
|
7
|
+
/.eggs/
|
|
8
|
+
/.pytest_cache/
|
|
9
|
+
/.mypy_cache/
|
|
10
|
+
/.ruff_cache/
|
|
11
|
+
/.tox/
|
|
12
|
+
/.nox/
|
|
13
|
+
/htmlcov/
|
|
14
|
+
/.coverage
|
|
15
|
+
/coverage.xml
|
|
16
|
+
/.hypothesis/
|
|
17
|
+
/.cache/
|
|
18
|
+
/.upload/
|
|
19
|
+
/.streamlit/
|
|
20
|
+
/.ipynb_checkpoints/
|
|
21
|
+
*.log
|
|
22
|
+
.env
|
|
23
|
+
|
|
24
|
+
# generated files
|
|
25
|
+
seetapsych_attributes/_version.py
|
|
26
|
+
|
|
27
|
+
# compiled files
|
|
28
|
+
*.pyc
|
|
29
|
+
__pycache__/
|
|
30
|
+
*.pyo
|
|
31
|
+
*.pyd
|
|
32
|
+
*.so
|
|
33
|
+
*$py.class
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Build Doc Configs",
|
|
6
|
+
"type": "debugpy",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"program": "${workspaceFolder}/tools/generate_readme.py",
|
|
9
|
+
"cwd": "${workspaceFolder}",
|
|
10
|
+
"console": "integratedTerminal",
|
|
11
|
+
"justMyCode": true
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Development Guide
|
|
2
|
+
|
|
3
|
+
## Local Verification (Before Creating a Release Tag)
|
|
4
|
+
|
|
5
|
+
Run these commands from the repository root. Make sure you have [`uv`](https://github.com/astral-sh/uv) installed.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Per-project: set PACKAGE to the top-level importable package directory
|
|
9
|
+
PACKAGE=seetapsych_attributes
|
|
10
|
+
# For any seetapsych-* project, auto-detect instead:
|
|
11
|
+
# PACKAGE="$(ls -d seetapsych_* 2>/dev/null | head -n1)"
|
|
12
|
+
|
|
13
|
+
# 1. Sync dependencies (installs the package + dev tools)
|
|
14
|
+
uv sync --group dev
|
|
15
|
+
|
|
16
|
+
# 2. Lint (ruff) (use `ruff check . --fix` to fix)
|
|
17
|
+
uv run ruff check .
|
|
18
|
+
|
|
19
|
+
# 3. Format check (ruff format -- non-destructive; use `ruff format` to apply)
|
|
20
|
+
uv run ruff format --check .
|
|
21
|
+
|
|
22
|
+
# 4. Static type check (mypy, strict mode)
|
|
23
|
+
uv run mypy "$PACKAGE"
|
|
24
|
+
|
|
25
|
+
# 5. Security scan (bandit)
|
|
26
|
+
uv run bandit -r "$PACKAGE" -c pyproject.toml
|
|
27
|
+
|
|
28
|
+
# 6. Unit tests (pytest)
|
|
29
|
+
uv run pytest
|
|
30
|
+
|
|
31
|
+
# 7. Build the distribution packages + verify metadata
|
|
32
|
+
uv run python -m build
|
|
33
|
+
uv run twine check dist/*
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If all seven steps pass, the code is ready to be tagged for release.
|
|
37
|
+
|
|
38
|
+
## Tag Naming and Release Pipeline
|
|
39
|
+
|
|
40
|
+
Tag format is managed by [`hatch-vcs`](https://github.com/ofek/hatch-vcs) with the following pattern in `pyproject.toml`:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
tag-pattern = "^r(?P<version>[^-]+)$"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This separates tags into two classes that drive the GitHub Actions pipeline in `.github/workflows/publish.yml`:
|
|
47
|
+
|
|
48
|
+
### Class A — Official Release: `r<version>` (no `-`)
|
|
49
|
+
|
|
50
|
+
**Format**: `r` + a version string that contains **no hyphen** `-`.
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
- `r0.1.0`
|
|
54
|
+
- `r2026.08.30`
|
|
55
|
+
- `r1.0.0.post1`
|
|
56
|
+
|
|
57
|
+
Pipeline behavior:
|
|
58
|
+
1. CI runs (lint + test + build).
|
|
59
|
+
2. `github-release` job builds sdist + wheel, **creates a GitHub Release** (`prerelease: false`), attaches both assets, and links to the PyPI version page.
|
|
60
|
+
3. `pypi-publish` job runs (`if: no '-' in tag`) and uploads the same sdist + wheel to PyPI via Trusted Publisher (OIDC, no API token required).
|
|
61
|
+
|
|
62
|
+
### Class B — Temporary / Pre-release: `r<version>-<suffix>`
|
|
63
|
+
|
|
64
|
+
**Format**: `r` + anything + **at least one hyphen** `-` + anything.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
- `r0.2.0-alpha`
|
|
68
|
+
- `r0.2.0-rc1`
|
|
69
|
+
- `r2026.08.30-tmp-hotfix-42`
|
|
70
|
+
- `r1.0.0-just-testing-release-flow`
|
|
71
|
+
|
|
72
|
+
Pipeline behavior:
|
|
73
|
+
1. CI still runs (same lint + test + build gates — everything must still pass).
|
|
74
|
+
2. `github-release` job builds sdist + wheel, creates a GitHub Release **marked as `prerelease: true`**, attaches both assets, and the release body clearly states "not published to PyPI".
|
|
75
|
+
3. `pypi-publish` job is **skipped** (`if:` condition fails because the tag contains `-`). Nothing is uploaded to PyPI.
|
|
76
|
+
|
|
77
|
+
### Quick Tagging Recipe
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# --- official release (PyPI + GitHub Release) ---
|
|
81
|
+
git tag r0.1.0
|
|
82
|
+
git push origin r0.1.0
|
|
83
|
+
|
|
84
|
+
# --- temp / pre-release (GitHub Release only, PyPI skipped) ---
|
|
85
|
+
git tag r0.1.0-alpha
|
|
86
|
+
git push origin r0.1.0-alpha
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Why the two classes?
|
|
90
|
+
|
|
91
|
+
Use Class B tags whenever you want to:
|
|
92
|
+
- exercise the full build + release-creation pipeline end-to-end without polluting PyPI,
|
|
93
|
+
- ship a throwaway build for QA or a staging consumer that can pull GitHub Release assets directly,
|
|
94
|
+
- share candidate wheels for a hotfix before cutting the final tag.
|
|
95
|
+
|
|
96
|
+
When the candidate is validated, re-tag without the suffix (e.g., `r0.1.0`) and push — the same CI gates run again, followed by the official PyPI publish.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) 2026, Visual Information Processing and Learning (VIPL) group,
|
|
2
|
+
Institute of Computing Technology, Chinese Academy of Sciences, Beijing, China;
|
|
3
|
+
Southeast University, China;
|
|
4
|
+
Beijing Seetatech Co., Ltd.
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|