Skip to content

Commit 8ea392b

Browse files
authored
Adds to "pyproject.toml" to enable setup of uv environment (#182)
* Adds code to enable setup of uv environment * Fixes linting errors * Sorts dependencies into groups * Moves dev dependencies into optional requirements * Adds conflicts for uv * Updates submodule with empty layers bug fix * Fixes code hanging bug * Reverts typing change
1 parent 929b714 commit 8ea392b

28 files changed

+189
-166
lines changed

.github/workflows/run_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,5 @@ jobs:
6363
- name: Install and Test with pytest
6464
run: |
6565
export PATH="$pythonLocation:$PATH"
66-
python -m pip install -e .[Dev,Orso]
66+
python -m pip install -e .[dev,orso]
6767
pytest tests/ --cov=ratapi --cov-report=term

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ dist/*
4040

4141
# Jupyter notebook checkpoints
4242
.ipynb_checkpoints/*
43+
44+
# Lock file for uv env
45+
uv.lock

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ To install in local directory:
1212

1313
matlabengine is an optional dependency only required for Matlab custom functions. The version of matlabengine should match the version of Matlab installed on the machine. This can be installed as shown below:
1414

15-
pip install -e .[Matlab-2023a]
15+
pip install -e .[matlab-2023a]
1616

1717
Development dependencies can be installed as shown below
1818

19-
pip install -e .[Dev]
19+
pip install -e .[dev]
2020

2121
To build wheel:
2222

cpp/RAT

pyproject.toml

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,53 @@ requires = [
66
]
77
build-backend = 'setuptools.build_meta'
88

9+
[project]
10+
name = "ratapi"
11+
version = "0.0.0.dev8"
12+
description = "Python extension for the Reflectivity Analysis Toolbox (RAT)"
13+
readme = "README.md"
14+
requires-python = ">=3.10"
15+
dependencies = [
16+
"matplotlib>=3.8.3",
17+
"numpy>=1.20",
18+
"prettytable>=3.9.0",
19+
"pydantic>=2.7.2",
20+
"scipy>=1.13.1",
21+
"strenum>=0.4.15 ; python_full_version < '3.11'",
22+
"tqdm>=4.66.5",
23+
]
24+
25+
[project.optional-dependencies]
26+
dev = [
27+
"pytest>=7.4.0",
28+
"pytest-cov>=4.1.0",
29+
"ruff>=0.4.10"
30+
]
31+
orso = [
32+
"orsopy>=1.2.1",
33+
"pint>=0.24.4"
34+
]
35+
matlab_latest = ["matlabengine"]
36+
matlab_2025b = ["matlabengine == 25.2.*"]
37+
matlab_2025a = ["matlabengine == 25.1.2"]
38+
matlab_2024b = ["matlabengine == 24.2.2"]
39+
matlab_2024a = ["matlabengine == 24.1.4"]
40+
matlab_2023b = ["matlabengine == 23.2.3"]
41+
matlab_2023a = ["matlabengine == 9.14.3"]
42+
43+
[tool.uv]
44+
conflicts = [
45+
[
46+
{ extra = "matlab_latest" },
47+
{ extra = "matlab_2025b" },
48+
{ extra = "matlab_2025a" },
49+
{ extra = "matlab_2024b" },
50+
{ extra = "matlab_2024a" },
51+
{ extra = "matlab_2023b" },
52+
{ extra = "matlab_2023a" },
53+
],
54+
]
55+
956
[tool.ruff]
1057
line-length = 120
1158
extend-exclude = ["*.ipynb"]
@@ -24,7 +71,8 @@ ignore = ["SIM103", # needless bool
2471
"D105", # undocumented __init__
2572
"D107", # undocumented magic method
2673
"D203", # blank line before class docstring
27-
"D213"] # multi line summary should start at second line
74+
"D213", # multi line summary should start at second line
75+
"UP038"] # non pep604 isinstance - to be removed
2876

2977
# ignore docstring lints in the tests and install script
3078
[tool.ruff.lint.per-file-ignores]

ratapi/classlist.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import importlib
66
import warnings
77
from collections.abc import Sequence
8-
from typing import Any, Generic, TypeVar, Union
8+
from typing import Any, Generic, TypeVar
99

1010
import numpy as np
1111
import prettytable
@@ -38,7 +38,7 @@ class ClassList(collections.UserList, Generic[T]):
3838
3939
"""
4040

41-
def __init__(self, init_list: Union[Sequence[T], T] = None, name_field: str = "name") -> None:
41+
def __init__(self, init_list: Sequence[T] | T = None, name_field: str = "name") -> None:
4242
self.name_field = name_field
4343

4444
# Set input as list if necessary
@@ -114,7 +114,7 @@ def __str__(self):
114114
output = str(self.data)
115115
return output
116116

117-
def __getitem__(self, index: Union[int, slice, str, T]) -> T:
117+
def __getitem__(self, index: int | slice | str | T) -> T:
118118
"""Get an item by its index, name, a slice, or the object itself."""
119119
if isinstance(index, (int, slice)):
120120
return self.data[index]
@@ -262,12 +262,12 @@ def insert(self, index: int, obj: T = None, **kwargs) -> None:
262262
self._validate_name_field(kwargs)
263263
self.data.insert(index, self._class_handle(**kwargs))
264264

265-
def remove(self, item: Union[T, str]) -> None:
265+
def remove(self, item: T | str) -> None:
266266
"""Remove an object from the ClassList using either the object itself or its ``name_field`` value."""
267267
item = self._get_item_from_name_field(item)
268268
self.data.remove(item)
269269

270-
def count(self, item: Union[T, str]) -> int:
270+
def count(self, item: T | str) -> int:
271271
"""Return the number of times an object appears in the ClassList.
272272
273273
This method can use either the object itself or its ``name_field`` value.
@@ -276,7 +276,7 @@ def count(self, item: Union[T, str]) -> int:
276276
item = self._get_item_from_name_field(item)
277277
return self.data.count(item)
278278

279-
def index(self, item: Union[T, str], offset: bool = False, *args) -> int:
279+
def index(self, item: T | str, offset: bool = False, *args) -> int:
280280
"""Return the index of a particular object in the ClassList.
281281
282282
This method can use either the object itself or its ``name_field`` value.
@@ -309,7 +309,7 @@ def union(self, other: Sequence[T]) -> None:
309309
]
310310
)
311311

312-
def set_fields(self, index: Union[int, slice, str, T], **kwargs) -> None:
312+
def set_fields(self, index: int | slice | str | T, **kwargs) -> None:
313313
"""Assign the values of an existing object's attributes using keyword arguments."""
314314
self._validate_name_field(kwargs)
315315
pydantic_object = False
@@ -519,7 +519,7 @@ def _check_classes(self, input_list: Sequence[T]) -> None:
519519
f"In the input list:\n{newline.join(error for error in error_list)}\n"
520520
)
521521

522-
def _get_item_from_name_field(self, value: Union[T, str]) -> Union[T, str]:
522+
def _get_item_from_name_field(self, value: T | str) -> T | str:
523523
"""Return the object with the given value of the ``name_field`` attribute in the ClassList.
524524
525525
Parameters
@@ -577,11 +577,12 @@ def _determine_class_handle(input_list: Sequence[T]):
577577
@classmethod
578578
def __get_pydantic_core_schema__(cls, source: Any, handler):
579579
# import here so that the ClassList can be instantiated and used without Pydantic installed
580+
from typing import get_args, get_origin
581+
580582
from pydantic import ValidatorFunctionWrapHandler
581583
from pydantic.types import (
582584
core_schema, # import core_schema through here rather than making pydantic_core a dependency
583585
)
584-
from typing_extensions import get_args, get_origin
585586

586587
# if annotated with a class, get the item type of that class
587588
origin = get_origin(source)

ratapi/controls.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import tempfile
66
import warnings
77
from pathlib import Path
8-
from typing import Union
98

109
import prettytable
1110
from pydantic import (
@@ -233,7 +232,7 @@ def delete_IPC(self):
233232
os.remove(self._IPCFilePath)
234233
return None
235234

236-
def save(self, filepath: Union[str, Path] = "./controls.json"):
235+
def save(self, filepath: str | Path = "./controls.json"):
237236
"""Save a controls object to a JSON file.
238237
239238
Parameters
@@ -245,7 +244,7 @@ def save(self, filepath: Union[str, Path] = "./controls.json"):
245244
filepath.write_text(self.model_dump_json())
246245

247246
@classmethod
248-
def load(cls, path: Union[str, Path]) -> "Controls":
247+
def load(cls, path: str | Path) -> "Controls":
249248
"""Load a controls object from file.
250249
251250
Parameters

ratapi/events.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""Hooks for connecting to run callback events."""
22

33
import os
4-
from typing import Callable, Union
4+
from collections.abc import Callable
55

66
from ratapi.rat_core import EventBridge, EventTypes, PlotEventData, ProgressEventData
77

88

9-
def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEventData]) -> None:
9+
def notify(event_type: EventTypes, data: str | PlotEventData | ProgressEventData) -> None:
1010
"""Call registered callbacks with data when event type has been triggered.
1111
1212
Parameters
@@ -22,7 +22,7 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEvent
2222
callback(data)
2323

2424

25-
def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, PlotEventData, ProgressEventData]], None]]:
25+
def get_event_callback(event_type: EventTypes) -> list[Callable[[str | PlotEventData | ProgressEventData], None]]:
2626
"""Return all callbacks registered for the given event type.
2727
2828
Parameters
@@ -39,7 +39,7 @@ def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, Plot
3939
return list(__event_callbacks[event_type])
4040

4141

42-
def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData, ProgressEventData]], None]) -> None:
42+
def register(event_type: EventTypes, callback: Callable[[str | PlotEventData | ProgressEventData], None]) -> None:
4343
"""Register a new callback for the event type.
4444
4545
Parameters

ratapi/inputs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import importlib
44
import os
55
import pathlib
6-
from typing import Callable, Union
6+
from collections.abc import Callable
77

88
import numpy as np
99

@@ -23,7 +23,7 @@
2323
}
2424

2525

26-
def get_python_handle(file_name: str, function_name: str, path: Union[str, pathlib.Path] = "") -> Callable:
26+
def get_python_handle(file_name: str, function_name: str, path: str | pathlib.Path = "") -> Callable:
2727
"""Get the function handle from a function defined in a python module located anywhere within the filesystem.
2828
2929
Parameters

ratapi/outputs.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44
from dataclasses import dataclass
55
from pathlib import Path
6-
from typing import Any, Optional, Union
6+
from typing import Any, Union
77

88
import numpy as np
99

@@ -244,7 +244,7 @@ def __str__(self):
244244
output += get_field_string(key, value, 100)
245245
return output
246246

247-
def save(self, filepath: Union[str, Path] = "./results.json"):
247+
def save(self, filepath: str | Path = "./results.json"):
248248
"""Save the Results object to a JSON file.
249249
250250
Parameters
@@ -258,7 +258,7 @@ def save(self, filepath: Union[str, Path] = "./results.json"):
258258
filepath.write_text(json.dumps(json_dict))
259259

260260
@classmethod
261-
def load(cls, path: Union[str, Path]) -> Union["Results", "BayesResults"]:
261+
def load(cls, path: str | Path) -> Union["Results", "BayesResults"]:
262262
"""Load a Results object from file.
263263
264264
Parameters
@@ -538,7 +538,7 @@ class BayesResults(Results):
538538
nestedSamplerOutput: NestedSamplerOutput
539539
chain: np.ndarray
540540

541-
def save(self, filepath: Union[str, Path] = "./results.json"):
541+
def save(self, filepath: str | Path = "./results.json"):
542542
"""Save the BayesResults object to a JSON file.
543543
544544
Parameters
@@ -574,7 +574,7 @@ def save(self, filepath: Union[str, Path] = "./results.json"):
574574
filepath.write_text(json.dumps(json_dict))
575575

576576

577-
def write_core_results_fields(results: Union[Results, BayesResults], json_dict: Optional[dict] = None) -> dict:
577+
def write_core_results_fields(results: Results | BayesResults, json_dict: dict | None = None) -> dict:
578578
"""Modify the values of the fields that appear in both Results and BayesResults when saving to a json file.
579579
580580
Parameters
@@ -684,8 +684,8 @@ def read_bayes_results_fields(results_dict: dict) -> dict:
684684
def make_results(
685685
procedure: Procedures,
686686
output_results: ratapi.rat_core.OutputResult,
687-
bayes_results: Optional[ratapi.rat_core.OutputBayesResult] = None,
688-
) -> Union[Results, BayesResults]:
687+
bayes_results: ratapi.rat_core.OutputBayesResult | None = None,
688+
) -> Results | BayesResults:
689689
"""Initialise a python Results or BayesResults object using the outputs from a RAT calculation.
690690
691691
Parameters

0 commit comments

Comments
 (0)