Skip to content

Commit 6025da0

Browse files
authored
Merge pull request #199 from IIIF/refactor-2026
Refactoring and using uv
2 parents 6fe43b8 + e8c2f3a commit 6025da0

30 files changed

Lines changed: 3343 additions & 716 deletions

.github/workflows/TestPyPi.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Publish Python 🐍 distributions 📦 to TestPyPI on Tag creation
2+
3+
on:
4+
release:
5+
types: [prereleased]
6+
7+
jobs:
8+
build-n-publish:
9+
name: Build and publish Python 🐍 distributions 📦 to TestPyPI
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v6
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Set up Python 3.12
18+
uses: actions/setup-python@v6
19+
with:
20+
python-version: "3.12"
21+
22+
- name: Set up uv
23+
uses: astral-sh/setup-uv@v7
24+
with:
25+
enable-cache: true
26+
27+
- name: Build library
28+
run: uv build
29+
30+
- name: Publish distribution 📦 to Test PyPI
31+
uses: pypa/gh-action-pypi-publish@v1.13.0
32+
with:
33+
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
34+
repository_url: https://test.pypi.org/legacy/

.github/workflows/test.yml

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,56 @@
1-
# This is a basic workflow to help you get started with Actions
2-
31
name: Run-tests
42

5-
# Controls when the action will run. Triggers the workflow on push or pull request
6-
# events but only for the master branch
7-
on: [push]
3+
on:
4+
push:
5+
pull_request:
86

97
jobs:
108
build:
119
runs-on: ubuntu-latest
1210
strategy:
11+
fail-fast: false
1312
matrix:
14-
python-version: [ '3.10', '3.11', '3.12', '3.13']
15-
name: Python ${{ matrix.python-version }} sample
13+
python-version: ["3.10", "3.11", "3.12", "3.13"]
14+
15+
name: Python ${{ matrix.python-version }}
16+
1617
steps:
17-
- uses: actions/checkout@v4
18-
- name: Setup python
18+
- uses: actions/checkout@v5
19+
20+
- name: Set up Python
1921
uses: actions/setup-python@v5
2022
with:
2123
python-version: ${{ matrix.python-version }}
22-
architecture: x64
2324

24-
- uses: actions/cache@v4
25+
- name: Set up uv
26+
uses: astral-sh/setup-uv@v6
2527
with:
26-
path: ${{ env.pythonLocation }}
27-
key: ${{ env.pythonLocation }}-${{ hashFiles('setup.py') }}-${{ hashFiles('dev-requirements.txt') }}
28+
enable-cache: true
2829

29-
- name: Install tox
30-
run: python -m pip install -U tox
30+
- name: Sync dependencies
31+
run: uv sync --all-extras --dev
3132

32-
- name: Test
33-
run: tox
33+
- name: Run tests
34+
run: uv run pytest
35+
36+
- name: Run coverage
37+
run: uv run coverage run -m pytest
38+
39+
- name: Create coverage reports
40+
run: |
41+
uv run coverage xml -o coverage.xml
42+
uv run coverage report
43+
uv run coverage html
3444
3545
- name: Upload coverage to Coveralls
3646
uses: coverallsapp/github-action@v2
3747
with:
3848
github-token: ${{ secrets.GITHUB_TOKEN }}
3949
format: cobertura
4050
file: coverage.xml
41-
flag-name: ${{ matrix.python-version }}
51+
flag-name: py${{ matrix.python-version }}
4252
parallel: true
43-
53+
4454
coveralls-finish:
4555
needs: build
4656
runs-on: ubuntu-latest
@@ -50,5 +60,4 @@ jobs:
5060
uses: coverallsapp/github-action@v2
5161
with:
5262
github-token: ${{ secrets.GITHUB_TOKEN }}
53-
parallel-finished: true
54-
63+
parallel-finished: true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ __pycache__
99
htmlcov
1010
*.pyc
1111
*.swp
12+
.venv
13+
dist
14+
_version.py

Dockerfile

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
ARG version=3.9
1+
ARG version=3.12
22
FROM python:${version}-slim
33

4-
54
WORKDIR /app
6-
ADD . /app
75

8-
RUN pip install --trusted-host pypi.python.org -r requirements.txt
6+
# Copy project files
7+
COPY . /app
8+
9+
# Install the project (uses pyproject.toml)
10+
RUN pip install --no-cache-dir .
911

12+
# Expose port (match your CLI default or override)
1013
EXPOSE 8080
11-
CMD ["/usr/local/bin/python", "/app/iiif-presentation-validator.py", "--hostname", "0.0.0.0"]
14+
15+
# Run the new CLI
16+
CMD ["iiif-validator", "serve", "--host", "0.0.0.0", "--port", "8080"]

README.md

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,52 @@ error | The text of the breaking error | sc:Manifest['thumbnail'] has brok
2727
okay | Did the manifest parse properly? | 1 *or* 0
2828
warnings | An array of warning messages | "WARNING: Resource type 'sc:Manifest' should have 'description' set\n"
2929

30-
## Local Installation
30+
## Installing localy
3131

32+
### Option 1: Using uv (recommended)
3233

33-
**Step one: Install dependencies**
34+
```
35+
uv sync
36+
```
37+
38+
### Option 2: Using pip
3439

35-
```bash
36-
python setup.py install
3740
```
41+
pip install .
42+
```
43+
44+
Either option will install the `iiif-validator` command. This command allows you to run the validator server or validate local or remote files from the command line.
3845

39-
**Step two: Run the application**
46+
## Command line validation
47+
48+
To validate a manifest from the command line:
49+
```
50+
# Using uv
51+
uv run iiif-validator validate --version <version> <url-or-file>
52+
53+
# Using pip install
54+
iiif-validator validate --version <version> <url-or-file>
55+
```
56+
57+
It is also possible to validate a directory and any sub directories:
58+
59+
```
60+
# Using uv
61+
uv run iiif-validator validate-dir --version <version> --extension <extension> <directory>
62+
63+
# Using pip install
64+
iiif-validator validate-dir --version <version> --extension <extension> <directory>
65+
```
66+
67+
## Server
68+
69+
To run the server:
70+
```
71+
# Using uv
72+
uv run iiif-validator serve
4073
41-
```bash
42-
python iiif-presentation-validator.py
74+
# Using pip install
75+
iiif-validator serve
4376
```
4477

4578
This should start up a local server, running at <localhost:8080>. To test it, try [this url](http://localhost:8080/validate?url=http://iiif.io/api/presentation/2.1/example/fixtures/1/manifest.json) and see if you get a JSON response that looks like this:

action.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: "IIIF Presentation Validator"
2+
description: "Validate IIIF JSON files in a directory using iiif-validator validate-dir"
3+
4+
inputs:
5+
directory:
6+
description: "Directory to search recursively for files"
7+
required: true
8+
version:
9+
description: "IIIF Presentation version to validate against, e.g. 2.1 or 3.0. If this isn't supplied then the version will be determined by the @context in the manifest"
10+
required: false
11+
default: ""
12+
13+
extension:
14+
description: "File extension or glob pattern to match (e.g. .json, .jsonld)"
15+
required: false
16+
default: ".json"
17+
18+
runs:
19+
using: "composite"
20+
steps:
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: 3.12
25+
26+
- name: Install validator
27+
shell: bash
28+
run: |
29+
python -m pip install --upgrade pip
30+
python -m pip install "${{ github.action_path }}"
31+
32+
- name: Validate directory
33+
shell: bash
34+
run: |
35+
set -euo pipefail
36+
37+
CMD="iiif-validator validate-dir \"${{ inputs.directory }}\""
38+
39+
if [ -n "${{ inputs.version }}" ]; then
40+
CMD="$CMD --version \"${{ inputs.version }}\""
41+
fi
42+
43+
if [ -n "${{ inputs.extension }}" ]; then
44+
CMD="$CMD --extension \"${{ inputs.extension }}\""
45+
fi
46+
47+
echo "Running: $CMD"
48+
eval $CMD

fixtures/3/content_state.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"@context": "http://iiif.io/api/presentation/3/context.json",
3+
"id": "https://iiif.io/api/cookbook/recipe/0540-link-for-opening-multiple-canvases/annotation.json",
4+
"type": "Annotation",
5+
"motivation": [
6+
"contentState"
7+
],
8+
"target": [
9+
{
10+
"id": "https://iiif.io/api/cookbook/recipe/0540-link-for-opening-multiple-canvases/canvas/2",
11+
"type": "Canvas",
12+
"partOf": [
13+
{
14+
"id": "https://iiif.io/api/cookbook/recipe/0540-link-for-opening-multiple-canvases/manifest-2.json",
15+
"type": "Manifest"
16+
}
17+
]
18+
},
19+
{
20+
"id": "https://iiif.io/api/cookbook/recipe/0540-link-for-opening-multiple-canvases/canvas/p2",
21+
"type": "Canvas",
22+
"partOf": [
23+
{
24+
"id": "https://iiif.io/api/cookbook/recipe/0540-link-for-opening-multiple-canvases/manifest.json",
25+
"type": "Manifest"
26+
}
27+
]
28+
}
29+
]
30+
}

0 commit comments

Comments
 (0)