Skip to content

Commit 7089f36

Browse files
authored
Updates to align with OTE v1 changes (#295)
* Add markdownlint-cli2 pre-commit hook Update pyupgrade args to drop Python 3.9. Update code base accordingly. * New workflow to add 'skip_changelog' label to Bot PRs Remove safety ignore statements. Use OTEAPI_PLUGIN_PACKAGES instead of overriding entrypoint in CI job. Try running pytest for Python 3.13. * Don't get stuck trying to run oteapi service * Update Docker Compose file * Change extra name to testing * Explicitly support Python 3.13
1 parent 6d11637 commit 7089f36

14 files changed

Lines changed: 130 additions & 83 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI - Update [bot] PR
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened]
6+
branches:
7+
- 'main'
8+
9+
jobs:
10+
add_skip_changelog_label:
11+
name: Add 'skip_changelog' label
12+
runs-on: ubuntu-latest
13+
14+
if: github.event.pull_request.user.type == 'Bot'
15+
16+
permissions:
17+
contents: read
18+
issues: write
19+
pull-requests: write
20+
21+
steps:
22+
- name: Add 'skip_changelog' label
23+
uses: actions/github-script@v7
24+
with:
25+
script: |
26+
const labels = await github.rest.issues.listLabelsOnIssue({
27+
owner: context.repo.owner,
28+
repo: context.repo.repo,
29+
issue_number: context.issue.number
30+
})
31+
32+
for (const label of labels.data) {
33+
if (label.name === 'skip_changelog') {
34+
console.log("Label 'skip_changelog' already exists 👌")
35+
return // Skip adding the label if it already exists
36+
}
37+
}
38+
39+
await github.rest.issues.addLabels({
40+
owner: context.repo.owner,
41+
repo: context.repo.repo,
42+
issue_number: context.issue.number,
43+
labels: ['skip_changelog']
44+
})
45+
console.log("Label 'skip_changelog' added 🎉")

.github/workflows/ci_tests.yml

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ jobs:
2323
run_pylint: false
2424

2525
run_safety: true
26-
# ID: 70612
27-
# Package: Jinja2
28-
# Has been disputed by the maintainer and multiple third parties.
29-
# For more information see: https://github.com/advisories/GHSA-f6pv-j8mr-w6rr
30-
safety_options: |
31-
--ignore=70612
3226

3327
# Build dist
3428
python_version_package: "3.10"
@@ -47,7 +41,7 @@ jobs:
4741
strategy:
4842
fail-fast: false
4943
matrix:
50-
python-version: ["3.10", "3.11", "3.12"]
44+
python-version: ["3.10", "3.11", "3.12", "3.13"]
5145
os:
5246
- ["ubuntu-latest", "linux"]
5347
- ["windows-latest", "windows"]
@@ -67,7 +61,7 @@ jobs:
6761
run: |
6862
python -m pip install -U pip
6963
pip install -U setuptools wheel flit
70-
pip install -e .[test]
64+
pip install -e .[testing]
7165
7266
- name: Test with pytest
7367
run: pytest -vvv --cov-report=xml
@@ -129,12 +123,11 @@ jobs:
129123
--env "OTEAPI_REDIS_TYPE=redis" \
130124
--env "OTEAPI_REDIS_HOST=localhost" \
131125
--env "OTEAPI_REDIS_PORT=6379" \
132-
--env "OTEAPI_PREFIX=${OTEAPI_PREFIX}" \
126+
--env OTEAPI_PREFIX \
127+
--env "OTEAPI_PLUGIN_PACKAGES=-v -e /oteapi-optimade" \
133128
--network "host" \
134129
--volume "${PWD}:/oteapi-optimade" \
135-
--entrypoint "" \
136-
ghcr.io/emmc-asbl/oteapi:${DOCKER_OTEAPI_VERSION} \
137-
/bin/bash -c "pip install -v -e /oteapi-optimade && ./entrypoint.sh" &
130+
ghcr.io/emmc-asbl/oteapi:${DOCKER_OTEAPI_VERSION} &
138131
139132
.github/utils/wait_for_it.sh localhost:${OTEAPI_PORT} -t 240
140133
sleep 5

.markdownlint.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Default state for all rules
2+
default: true
3+
4+
# MD013/line-length - Line length
5+
MD013:
6+
# Number of characters
7+
# Set very long to support 1-sentence-per-line style.
8+
line_length: 999
9+
# Number of characters for headings (match that of black's default)
10+
heading_line_length: 88
11+
# Number of characters for code blocks (match that of black's default)
12+
code_block_line_length: 88

.pre-commit-config.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ repos:
1616
- repo: https://github.com/pre-commit/pre-commit-hooks
1717
rev: v5.0.0
1818
hooks:
19+
- id: check-json
20+
name: Check JSON
1921
- id: check-toml
2022
name: Check TOML
2123
- id: check-yaml
@@ -29,11 +31,21 @@ repos:
2931
- id: trailing-whitespace
3032
args: [--markdown-linebreak-ext=md]
3133

34+
- repo: https://github.com/DavidAnson/markdownlint-cli2
35+
rev: v0.17.2
36+
hooks:
37+
- id: markdownlint-cli2
38+
name: markdownlint
39+
exclude: ^(docs/)?(index|LICENSE|CHANGELOG).md$
40+
args:
41+
- --fix
42+
- --config=.markdownlint.yaml
43+
3244
- repo: https://github.com/asottile/pyupgrade
3345
rev: v3.19.1
3446
hooks:
3547
- id: pyupgrade
36-
args: [--py39-plus, --keep-runtime-typing]
48+
args: [--py310-plus]
3749

3850
- repo: https://github.com/psf/black
3951
rev: 25.1.0

compose.yaml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
services:
22
oteapi:
3-
image: ghcr.io/emmc-asbl/oteapi:${DOCKER_OTEAPI_VERSION:-latest}
3+
image: ghcr.io/emmc-asbl/oteapi:${DOCKER_OTEAPI_VERSION:-latest-dev}
44
ports:
55
- "${OTEAPI_PORT:-8080}:8080"
66
environment:
77
OTEAPI_REDIS_TYPE: redis
88
OTEAPI_REDIS_HOST: redis
99
OTEAPI_REDIS_PORT: 6379
1010
OTEAPI_PREFIX: "${OTEAPI_PREFIX:-/api/v1}"
11-
PATH_TO_OTEAPI_CORE:
1211
OTEAPI_PLUGIN_PACKAGES: "-v -e /oteapi-optimade"
1312
depends_on:
1413
- redis
1514
networks:
1615
- otenet
1716
volumes:
18-
- "${PATH_TO_OTEAPI_CORE:-/dev/null}:/oteapi-core"
1917
- "${PWD}:/oteapi-optimade"
20-
entrypoint: |
21-
/bin/bash -c "if [ \"${PATH_TO_OTEAPI_CORE}\" != \"/dev/null\" ] && [ -n \"${PATH_TO_OTEAPI_CORE}\" ]; then \
22-
pip install -U --force-reinstall -e /oteapi-core; fi && ./entrypoint.sh --reload --debug --log-level debug"
2318
stop_grace_period: 1s
2419

2520
redis:

oteapi_optimade/_utils.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@
99
import dlite
1010

1111
if TYPE_CHECKING: # pragma: no cover
12-
import sys
13-
from typing import Any
14-
15-
if sys.version_info >= (3, 9, 1):
16-
from typing import Literal
17-
else:
18-
from typing_extensions import Literal # type: ignore[assignment]
12+
from typing import Any, Literal
1913

2014
LOGGER = logging.getLogger(__name__)
2115

oteapi_optimade/models/config.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import Annotated, Literal, Optional
5+
from typing import Annotated, Literal
66

77
from oteapi.models import AttrDict, DataCacheConfig
88
from pydantic import BeforeValidator, Field, field_validator
@@ -22,12 +22,12 @@ class OPTIMADEConfig(AttrDict):
2222

2323
# OTEAPI-specific attributes
2424
downloadUrl: Annotated[
25-
Optional[OPTIMADEUrl],
25+
OPTIMADEUrl | None,
2626
Field(description="Either a base OPTIMADE URL or a full OPTIMADE URL."),
2727
] = None
2828

2929
mediaType: Annotated[
30-
Optional[Literal["application/vnd.optimade+json", "application/vnd.optimade"]],
30+
Literal["application/vnd.optimade+json", "application/vnd.optimade"] | None,
3131
BeforeValidator(lambda x: x.lower() if isinstance(x, str) else x),
3232
Field(
3333
description="The registered strategy name for OPTIMADEParseStrategy.",
@@ -36,7 +36,7 @@ class OPTIMADEConfig(AttrDict):
3636

3737
# OPTIMADE parse result attributes
3838
optimade_config: Annotated[
39-
Optional[OPTIMADEConfig],
39+
OPTIMADEConfig | None,
4040
Field(description="A pre-existing instance of this OPTIMADE configuration."),
4141
] = None
4242

@@ -57,7 +57,7 @@ class OPTIMADEConfig(AttrDict):
5757
] = "structures"
5858

5959
query_parameters: Annotated[
60-
Optional[OPTIMADEQueryParameters],
60+
OPTIMADEQueryParameters | None,
6161
Field(
6262
description="URL query parameters to be used in the OPTIMADE query.",
6363
),
@@ -108,7 +108,7 @@ class OPTIMADEDLiteConfig(OPTIMADEConfig):
108108

109109
# OTEAPI-specific attributes
110110
mediaType: Annotated[
111-
Optional[Literal["application/vnd.optimade+dlite"]],
111+
Literal["application/vnd.optimade+dlite"] | None,
112112
BeforeValidator(lambda x: x.lower() if isinstance(x, str) else x),
113113
Field(
114114
description="The registered strategy name for OPTIMADEDLiteParseStrategy.",
@@ -117,6 +117,6 @@ class OPTIMADEDLiteConfig(OPTIMADEConfig):
117117

118118
# Dlite specific attributes
119119
collection_id: Annotated[
120-
Optional[str],
120+
str | None,
121121
Field(description="A reference to a DLite Collection."),
122122
] = None

oteapi_optimade/models/custom_types.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from pydantic_core import Url, core_schema
2323

2424
if TYPE_CHECKING: # pragma: no cover
25-
from typing import Any, Optional, TypedDict, Union
25+
from typing import Any, TypedDict
2626

2727
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
2828
from pydantic.json_schema import JsonSchemaValue
@@ -91,10 +91,10 @@ def __init__(
9191
self,
9292
url: str,
9393
*,
94-
base_url: Optional[str] = None,
95-
version: Optional[str] = None,
96-
endpoint: Optional[str] = None,
97-
query: Optional[str] = None,
94+
base_url: str | None = None,
95+
version: str | None = None,
96+
endpoint: str | None = None,
97+
query: str | None = None,
9898
) -> None:
9999
str.__init__(url)
100100

@@ -115,7 +115,7 @@ def __init__(
115115
pydantic_url = None
116116

117117
# Build OPTIMADE URL parts
118-
optimade_parts: Union[OPTIMADEParts, dict[str, Any]] = {}
118+
optimade_parts: OPTIMADEParts | dict[str, Any] = {}
119119
if pydantic_url:
120120
optimade_parts = self._build_optimade_parts(pydantic_url)
121121

@@ -145,9 +145,9 @@ def __repr__(self) -> str:
145145
def _build(
146146
*,
147147
base_url: str,
148-
version: Optional[str] = None,
149-
endpoint: Optional[str] = None,
150-
query: Optional[str] = None,
148+
version: str | None = None,
149+
endpoint: str | None = None,
150+
query: str | None = None,
151151
) -> str:
152152
"""Build complete OPTIMADE URL from URL parts."""
153153
url = base_url.rstrip("/")
@@ -176,21 +176,21 @@ def base_url(self) -> str:
176176
return self._base_url
177177

178178
@property
179-
def version(self) -> Optional[str]:
179+
def version(self) -> str | None:
180180
"""The version part of the OPTIMADE URL."""
181181
return self._version
182182

183183
@property
184-
def endpoint(self) -> Optional[str]:
184+
def endpoint(self) -> str | None:
185185
"""The endpoint part of the OPTIMADE URL."""
186186
return self._endpoint
187187

188188
@property
189-
def query(self) -> Optional[str]:
189+
def query(self) -> str | None:
190190
"""The query part of the OPTIMADE URL."""
191191
return self._query
192192

193-
def response_model(self) -> Union[tuple[Success, Success], Success, None]:
193+
def response_model(self) -> tuple[Success, Success] | Success | None:
194194
"""Return the endpoint's corresponding response model(s) (from OPT)."""
195195
if not self.endpoint or self.endpoint == "versions":
196196
return None
@@ -265,7 +265,7 @@ def __get_pydantic_json_schema__(
265265
)
266266

267267
@classmethod
268-
def _validate_from_str_or_url(cls, value: Union[Url, str]) -> OPTIMADEUrl:
268+
def _validate_from_str_or_url(cls, value: Url | str) -> OPTIMADEUrl:
269269
"""Pydantic validation of an OPTIMADE URL."""
270270
# Parse as URL
271271
url = AnyHttpUrl(str(value))

0 commit comments

Comments
 (0)