Skip to content

Commit 2bc1429

Browse files
authored
Raise minimum Python to 3.10 (#207)
* Raise minimum Python to 3.10 Python 3.9 reached end-of-life in October 2025. This bumps the floor to 3.10 and extends CI coverage through 3.14 to match the currently supported CPython versions. * Apply ruff upgrades * Leave off 3.14 for now * Remove `target-version` from Ruff Ruff will infer a missing target-version from the requires-python field in a pyproject.toml * Remove Ruff format config Redundant with defaults.
1 parent 06bf923 commit 2bc1429

7 files changed

Lines changed: 126 additions & 1333 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
runs-on: ubuntu-latest
3131
strategy:
3232
matrix:
33-
python-version: ["3.8", "3.9", "3.10", "3.11"]
33+
python-version: ["3.10", "3.11", "3.12", "3.13"]
3434
steps:
3535
- uses: actions/checkout@v6
3636
- uses: astral-sh/setup-uv@v7

examples/Plugin.ipynb

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"cell_type": "code",
55
"execution_count": null,
6-
"id": "74b20970",
6+
"id": "ea68ab39",
77
"metadata": {},
88
"outputs": [],
99
"source": [
@@ -13,7 +13,7 @@
1313
{
1414
"cell_type": "code",
1515
"execution_count": null,
16-
"id": "4b1a1665",
16+
"id": "22ce47f6",
1717
"metadata": {},
1818
"outputs": [],
1919
"source": [
@@ -62,7 +62,7 @@
6262
},
6363
{
6464
"cell_type": "markdown",
65-
"id": "06263c4c",
65+
"id": "019c7c7e",
6666
"metadata": {},
6767
"source": [
6868
"The above config contains an unknown track type to `hg`, so we get a validation error because we don't know how to render the track!"
@@ -71,7 +71,7 @@
7171
{
7272
"cell_type": "code",
7373
"execution_count": null,
74-
"id": "8c4a4b38",
74+
"id": "8f5f4294",
7575
"metadata": {},
7676
"outputs": [],
7777
"source": [
@@ -82,7 +82,7 @@
8282
},
8383
{
8484
"cell_type": "markdown",
85-
"id": "d20a1b24",
85+
"id": "5cc74c65",
8686
"metadata": {},
8787
"source": [
8888
"# `hg.PluginTrack`\n",
@@ -93,13 +93,11 @@
9393
{
9494
"cell_type": "code",
9595
"execution_count": null,
96-
"id": "4d6149f1",
96+
"id": "26813410",
9797
"metadata": {},
9898
"outputs": [],
9999
"source": [
100-
"from typing import ClassVar, Union\n",
101-
"\n",
102-
"from typing_extensions import Literal\n",
100+
"from typing import ClassVar, Literal\n",
103101
"\n",
104102
"\n",
105103
"class PileupTrack(hg.PluginTrack):\n",
@@ -109,17 +107,17 @@
109107
" )\n",
110108
"\n",
111109
"\n",
112-
"hg.Viewconf[Union[PileupTrack, hg.Track]](**config) # works!"
110+
"hg.Viewconf[PileupTrack | hg.Track](**config) # works!"
113111
]
114112
},
115113
{
116114
"cell_type": "markdown",
117-
"id": "66e046ce",
115+
"id": "ec287f3e",
118116
"metadata": {},
119117
"source": [
120118
"How does this work? The `hg.Viewconf` is a `pydantic.GenericModel` which is _generic_ over the track type. By default, only HiGlass's builtin track types are recognized, so `hg.Viewconf(**data)` will throw an error when a configuration contains an unknown track.\n",
121119
"\n",
122-
"By supplying a our plugin track as a type parameter explicity, `hg.Viewconf[Union[PileupTrack, hg.Track]]`, we extend the model to recognize the `PileupTrack` in our config.\n",
120+
"By supplying a our plugin track as a type parameter explicity, `hg.Viewconf[PileupTrack | hg.Track]`, we extend the model to recognize the `PileupTrack` in our config.\n",
123121
"\n",
124122
"This can seem a bit verbose, but supplying the type parameter explicitly is only necessary when deserializing an unknown config, e.g.\n",
125123
"\n",
@@ -134,21 +132,19 @@
134132
{
135133
"cell_type": "code",
136134
"execution_count": null,
137-
"id": "4fde003f",
135+
"id": "736146c8",
138136
"metadata": {},
139137
"outputs": [],
140138
"source": [
141-
"from typing import ClassVar\n",
142-
"\n",
143-
"from typing_extensions import Literal\n",
139+
"from typing import ClassVar, Literal\n",
144140
"\n",
145141
"import higlass as hg"
146142
]
147143
},
148144
{
149145
"cell_type": "code",
150146
"execution_count": null,
151-
"id": "1210c425",
147+
"id": "c178a248",
152148
"metadata": {},
153149
"outputs": [],
154150
"source": [
@@ -166,13 +162,11 @@
166162
{
167163
"cell_type": "code",
168164
"execution_count": null,
169-
"id": "76a67f86",
165+
"id": "d86e35fc",
170166
"metadata": {},
171167
"outputs": [],
172168
"source": [
173-
"from typing import ClassVar\n",
174-
"\n",
175-
"from typing_extensions import Literal\n",
169+
"from typing import ClassVar, Literal\n",
176170
"\n",
177171
"import higlass as hg\n",
178172
"\n",
@@ -218,7 +212,7 @@
218212
},
219213
{
220214
"cell_type": "markdown",
221-
"id": "bb20c39e",
215+
"id": "0a28bebf",
222216
"metadata": {},
223217
"source": [
224218
"## Extending plugins with `pydantic`\n",
@@ -231,12 +225,10 @@
231225
{
232226
"cell_type": "code",
233227
"execution_count": null,
234-
"id": "35355968",
228+
"id": "6e397bed",
235229
"metadata": {},
236230
"outputs": [],
237231
"source": [
238-
"from typing import Optional\n",
239-
"\n",
240232
"from pydantic import BaseModel\n",
241233
"\n",
242234
"\n",
@@ -252,7 +244,7 @@
252244
"\n",
253245
"class SequenceTrack(hg.PluginTrack):\n",
254246
" type: Literal[\"horizontal-sequence\"]\n",
255-
" data: Optional[SeqeuenceTrackData] = None\n",
247+
" data: SeqeuenceTrackData | None = None\n",
256248
" plugin_url: ClassVar[str] = (\n",
257249
" \"https://unpkg.com/higlass-sequence/dist/higlass-sequence.js\"\n",
258250
" )\n",
@@ -279,7 +271,7 @@
279271
{
280272
"cell_type": "code",
281273
"execution_count": null,
282-
"id": "1328f1d6",
274+
"id": "98794dcf",
283275
"metadata": {},
284276
"outputs": [],
285277
"source": [
@@ -289,7 +281,7 @@
289281
{
290282
"cell_type": "code",
291283
"execution_count": null,
292-
"id": "27f99ea4",
284+
"id": "9776449b",
293285
"metadata": {},
294286
"outputs": [],
295287
"source": [
@@ -298,7 +290,7 @@
298290
},
299291
{
300292
"cell_type": "markdown",
301-
"id": "35965609",
293+
"id": "93fb6b03",
302294
"metadata": {},
303295
"source": [
304296
"And the track is faithfully rendered by HiGlass"
@@ -307,7 +299,7 @@
307299
{
308300
"cell_type": "code",
309301
"execution_count": null,
310-
"id": "7948b163",
302+
"id": "aa4d7519",
311303
"metadata": {},
312304
"outputs": [],
313305
"source": [
@@ -317,7 +309,7 @@
317309
{
318310
"cell_type": "code",
319311
"execution_count": null,
320-
"id": "ad082d7f",
312+
"id": "62543d11",
321313
"metadata": {},
322314
"outputs": [],
323315
"source": []
@@ -344,4 +336,4 @@
344336
},
345337
"nbformat": 4,
346338
"nbformat_minor": 5
347-
}
339+
}

pyproject.toml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,19 @@ classifiers = [
1616
"Intended Audience :: Developers",
1717
"Programming Language :: Python",
1818
"Programming Language :: Python :: 3",
19-
"Programming Language :: Python :: 3.8",
20-
"Programming Language :: Python :: 3.9",
2119
"Programming Language :: Python :: 3.10",
2220
"Programming Language :: Python :: 3.11",
21+
"Programming Language :: Python :: 3.12",
22+
"Programming Language :: Python :: 3.13",
2323
"Operating System :: OS Independent",
2424
]
25-
license = { text = "MIT" }
2625
dynamic = ["version"]
2726
readme = "README.md"
2827
dependencies = [
2928
"higlass-schema>=0.2.0",
3029
"anywidget>=0.9.0",
31-
"typing-extensions ; python_version<'3.9'",
3230
]
33-
requires-python = ">=3.8"
31+
requires-python = ">=3.10"
3432
urls = { homepage = "https://github.com/higlass/higlass-python" }
3533

3634
[dependency-groups]
@@ -50,10 +48,6 @@ packages = ["src/higlass"]
5048
[tool.hatch.version]
5149
source = "vcs"
5250

53-
[tool.ruff]
54-
line-length = 88
55-
target-version = "py38"
56-
5751
[tool.ruff.lint]
5852
extend-select = [
5953
"E", # style errors

src/higlass/_scale.py

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

33
import itertools
44
from bisect import bisect_right
5-
from typing import Iterable, Tuple
5+
from collections.abc import Iterable
66

7-
GenomicPosition = Tuple[str, int]
7+
GenomicPosition = tuple[str, int]
88

99

1010
class Scale:

src/higlass/_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

33
import uuid
4-
from typing import Literal, TypeVar, Union
4+
from typing import Literal, TypeVar
55

66
import higlass_schema as hgs
77
from pydantic import BaseModel
88

9-
TrackType = Union[hgs.EnumTrackType, Literal["heatmap"]]
9+
TrackType = hgs.EnumTrackType | Literal["heatmap"]
1010
TrackPosition = Literal["center", "top", "left", "bottom", "center", "whole", "gallery"]
1111

1212
track_default_position: dict[str, TrackPosition] = {

src/higlass/api.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
Generic,
88
Literal,
99
TypeVar,
10-
Union,
1110
cast,
1211
overload,
1312
)
@@ -158,13 +157,13 @@ class PluginTrack(hgs.BaseTrack, _OptionsMixin, _PropertiesMixin):
158157
plugin_url: ClassVar[str]
159158

160159

161-
Track = Union[
162-
HeatmapTrack,
163-
IndependentViewportProjectionTrack,
164-
EnumTrack,
165-
CombinedTrack,
166-
PluginTrack,
167-
]
160+
Track = (
161+
HeatmapTrack
162+
| IndependentViewportProjectionTrack
163+
| EnumTrack
164+
| CombinedTrack
165+
| PluginTrack
166+
)
168167

169168
TrackT = TypeVar("TrackT", bound=Track)
170169

@@ -588,7 +587,7 @@ def mapper(view):
588587
getattr(a, lockattr).locksByViewUid.update(locks.locksByViewUid)
589588
getattr(a, lockattr).locksDict.update(locks.locksDict)
590589

591-
return cast(Viewconf[Union[TrackTA, TrackTB]], a)
590+
return cast(Viewconf[TrackTA | TrackTB], a)
592591

593592

594593
hconcat = functools.partial(concat, "horizontal")
@@ -787,7 +786,7 @@ def combine(t1: Track, t2: Track, uid: str | None = None, **kwargs) -> CombinedT
787786
)
788787

789788

790-
T = TypeVar("T", bound=Union[EnumTrack, HeatmapTrack])
789+
T = TypeVar("T", bound=EnumTrack | HeatmapTrack)
791790

792791

793792
def divide(t1: T, t2: T, **kwargs) -> T:

0 commit comments

Comments
 (0)