Skip to content

Commit cbe2372

Browse files
Numpy2 (#93)
Added support for Numpy 2, dropped support for Python 3.9, added support for Python 3.13
1 parent 2117739 commit cbe2372

File tree

7 files changed

+44
-39
lines changed

7 files changed

+44
-39
lines changed

.github/workflows/documentation-build.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- name: Set up Python
3333
uses: actions/setup-python@v5
3434
with:
35-
python-version: 3.9
35+
python-version: 3.10
3636
- name: Install Pandoc, repo and dependencies
3737
run: |
3838
sudo apt install pandoc

.github/workflows/python-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
strategy:
3131
max-parallel: 4
3232
matrix:
33-
python-version: ['3.9', '3.10', '3.11', '3.12']
33+
python-version: ['3.10', '3.11', '3.12', '3.13']
3434
os: [ubuntu-latest, macos-latest, windows-latest]
3535

3636
runs-on: ${{ matrix.os }}

.github/workflows/python-package.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
runs-on: ubuntu-latest
2222
strategy:
2323
matrix:
24-
python-version: ['3.9', '3.10', '3.11']
24+
python-version: ['3.10', '3.11', '3.12', '3.13']
2525
if: "!contains(github.event.head_commit.message, '[ci skip]')"
2626

2727
steps:

.github/workflows/python-publish.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828

2929
- uses: actions/setup-python@v5
3030
with:
31-
python-version: 3.9
31+
python-version: 3.10
3232

3333
- name: Install dependencies and build
3434
run: |

pyproject.toml

+6-6
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@ classifiers = [
2121
"Topic :: Scientific/Engineering",
2222
"Programming Language :: Python :: 3",
2323
"Programming Language :: Python :: 3 :: Only",
24-
"Programming Language :: Python :: 3.9",
2524
"Programming Language :: Python :: 3.10",
2625
"Programming Language :: Python :: 3.11",
2726
"Programming Language :: Python :: 3.12",
27+
"Programming Language :: Python :: 3.13",
2828
"Development Status :: 3 - Alpha"
2929
]
30-
requires-python = ">=3.9,<3.13"
30+
requires-python = ">=3.10"
3131
dependencies = [
3232
"asteval",
3333
"bumps",
3434
"DFO-LS",
3535
"lmfit",
36-
"numpy==1.26", # Should be updated to numpy 2.0
36+
"numpy",
3737
"uncertainties",
3838
"xarray",
39-
"pint==0.23", # Only to ensure that unit is reported as dimensionless rather than empty string
39+
"pint", # Only to ensure that unit is reported as dimensionless rather than empty string
4040
"scipp"
4141
]
4242

@@ -128,13 +128,13 @@ force-single-line = true
128128
legacy_tox_ini = """
129129
[tox]
130130
isolated_build = True
131-
envlist = py{3.9,3.10,3.11,3.12}
131+
envlist = py{3.10,3.11,3.12,3.13}
132132
[gh-actions]
133133
python =
134-
3.9: py39
135134
3.10: py310
136135
3.11: py311
137136
3.12: py312
137+
3.13: py313
138138
[gh-actions:env]
139139
PLATFORM =
140140
ubuntu-latest: linux

src/easyscience/Objects/new_variable/parameter.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ def __repr__(self) -> str:
418418
if self.fixed:
419419
super_str += ' (fixed)'
420420
s.append(super_str)
421-
s.append('bounds=[%s:%s]' % (repr(self.min), repr(self.max)))
421+
s.append('bounds=[%s:%s]' % (repr(float(self.min)), repr(float(self.max))))
422422
return '%s>' % ', '.join(s)
423423

424424
# Seems redundant

tests/unit_tests/Objects/new_variable/test_parameter.py

+33-28
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ def test_min(self, parameter: Parameter):
101101

102102
def test_set_min(self, parameter: Parameter):
103103
# When Then
104+
self.mock_callback.fget.return_value = 1.0 # Ensure fget returns a scalar value
105+
104106
parameter.min = 0.1
105107

106108
# Expect
@@ -189,6 +191,7 @@ def test_bounds(self, parameter: Parameter):
189191

190192
def test_set_bounds(self, parameter: Parameter):
191193
# When
194+
self.mock_callback.fget.return_value = 1.0 # Ensure fget returns a scalar value
192195
parameter._enabled = False
193196
parameter._fixed = True
194197

@@ -298,6 +301,7 @@ def test_set_full_value(self, parameter: Parameter):
298301

299302
def test_copy(self, parameter: Parameter):
300303
# When Then
304+
self.mock_callback.fget.return_value = 1.0 # Ensure fget returns a scalar value
301305
parameter_copy = parameter.__copy__()
302306

303307
# Expect
@@ -317,6 +321,7 @@ def test_copy(self, parameter: Parameter):
317321

318322
def test_as_data_dict(self, clear, parameter: Parameter):
319323
# When Then
324+
self.mock_callback.fget.return_value = 1.0 # Ensure fget returns a scalar value
320325
parameter_dict = parameter.as_data_dict()
321326

322327
# Expect
@@ -337,7 +342,7 @@ def test_as_data_dict(self, clear, parameter: Parameter):
337342

338343
@pytest.mark.parametrize("test, expected, expected_reverse", [
339344
(Parameter("test", 2, "m", 0.01, -10, 20), Parameter("name + test", 3, "m", 0.02, -10, 30), Parameter("test + name", 3, "m", 0.02, -10, 30)),
340-
(Parameter("test", 2, "m", 0.01), Parameter("name + test", 3, "m", 0.02, min=-np.Inf, max=np.Inf),Parameter("test + name", 3, "m", 0.02, min=-np.Inf, max=np.Inf)),
345+
(Parameter("test", 2, "m", 0.01), Parameter("name + test", 3, "m", 0.02, min=-np.inf, max=np.inf),Parameter("test + name", 3, "m", 0.02, min=-np.inf, max=np.inf)),
341346
(Parameter("test", 2, "cm", 0.01, -10, 10), Parameter("name + test", 1.02, "m", 0.010001, -0.1, 10.1), Parameter("test + name", 102, "cm", 100.01, -10, 1010))],
342347
ids=["regular", "no_bounds", "unit_conversion"])
343348
def test_addition_with_parameter(self, parameter : Parameter, test : Parameter, expected : Parameter, expected_reverse : Parameter):
@@ -427,7 +432,7 @@ def test_addition_exception(self, parameter : Parameter, test):
427432

428433
@pytest.mark.parametrize("test, expected, expected_reverse", [
429434
(Parameter("test", 2, "m", 0.01, -20, 20), Parameter("name - test", -1, "m", 0.02, -20, 30), Parameter("test - name", 1, "m", 0.02, -30, 20)),
430-
(Parameter("test", 2, "m", 0.01), Parameter("name - test", -1, "m", 0.02, min=-np.Inf, max=np.Inf),Parameter("test - name", 1, "m", 0.02, min=-np.Inf, max=np.Inf)),
435+
(Parameter("test", 2, "m", 0.01), Parameter("name - test", -1, "m", 0.02, min=-np.inf, max=np.inf),Parameter("test - name", 1, "m", 0.02, min=-np.inf, max=np.inf)),
431436
(Parameter("test", 2, "cm", 0.01, -10, 10), Parameter("name - test", 0.98, "m", 0.010001, -0.1, 10.1), Parameter("test - name", -98, "cm", 100.01, -1010, 10))],
432437
ids=["regular", "no_bounds", "unit_conversion"])
433438
def test_subtraction_with_parameter(self, parameter : Parameter, test : Parameter, expected : Parameter, expected_reverse : Parameter):
@@ -457,8 +462,8 @@ def test_subtraction_with_parameter(self, parameter : Parameter, test : Paramete
457462

458463
def test_subtraction_with_parameter_nan_cases(self):
459464
# When
460-
parameter = Parameter(name="name", value=1, variance=0.01, min=-np.Inf, max=np.Inf)
461-
test = Parameter(name="test", value=2, variance=0.01, min=-np.Inf, max=np.Inf)
465+
parameter = Parameter(name="name", value=1, variance=0.01, min=-np.inf, max=np.inf)
466+
test = Parameter(name="test", value=2, variance=0.01, min=-np.inf, max=np.inf)
462467

463468
# Then
464469
result = parameter - test
@@ -469,15 +474,15 @@ def test_subtraction_with_parameter_nan_cases(self):
469474
assert result.value == -1.0
470475
assert result.unit == "dimensionless"
471476
assert result.variance == 0.02
472-
assert result.min == -np.Inf
473-
assert result.max == np.Inf
477+
assert result.min == -np.inf
478+
assert result.max == np.inf
474479

475480
assert result_reverse.name == result_reverse.unique_name
476481
assert result_reverse.value == 1.0
477482
assert result_reverse.unit == "dimensionless"
478483
assert result_reverse.variance == 0.02
479-
assert result_reverse.min == -np.Inf
480-
assert result_reverse.max == np.Inf
484+
assert result_reverse.min == -np.inf
485+
assert result_reverse.max == np.inf
481486

482487
def test_subtraction_with_scalar(self):
483488
# When
@@ -541,7 +546,7 @@ def test_subtraction_exception(self, parameter : Parameter, test):
541546

542547
@pytest.mark.parametrize("test, expected, expected_reverse", [
543548
(Parameter("test", 2, "m", 0.01, -10, 20), Parameter("name * test", 2, "m^2", 0.05, -100, 200), Parameter("test * name", 2, "m^2", 0.05, -100, 200)),
544-
(Parameter("test", 2, "m", 0.01), Parameter("name * test", 2, "m^2", 0.05, min=-np.Inf, max=np.Inf), Parameter("test * name", 2, "m^2", 0.05, min=-np.Inf, max=np.Inf)),
549+
(Parameter("test", 2, "m", 0.01), Parameter("name * test", 2, "m^2", 0.05, min=-np.inf, max=np.inf), Parameter("test * name", 2, "m^2", 0.05, min=-np.inf, max=np.inf)),
545550
(Parameter("test", 2, "dm", 0.01, -10, 20), Parameter("name * test", 0.2, "m^2", 0.0005, -10, 20), Parameter("test * name", 0.2, "m^2", 0.0005, -10, 20))],
546551
ids=["regular", "no_bounds", "base_unit_conversion"])
547552
def test_multiplication_with_parameter(self, parameter : Parameter, test : Parameter, expected : Parameter, expected_reverse : Parameter):
@@ -568,12 +573,12 @@ def test_multiplication_with_parameter(self, parameter : Parameter, test : Param
568573
assert result_reverse.max == expected_reverse.max
569574

570575
@pytest.mark.parametrize("test, expected, expected_reverse", [
571-
(Parameter("test", 0, "", 0.01, -10, 0), Parameter("name * test", 0.0, "dimensionless", 0.01, -np.Inf, 0), Parameter("test * name", 0, "dimensionless", 0.01, -np.Inf, 0)),
572-
(Parameter("test", 0, "", 0.01, 0, 10), Parameter("name * test", 0.0, "dimensionless", 0.01, 0, np.Inf), Parameter("test * name", 0, "dimensionless", 0.01, 0, np.Inf))],
576+
(Parameter("test", 0, "", 0.01, -10, 0), Parameter("name * test", 0.0, "dimensionless", 0.01, -np.inf, 0), Parameter("test * name", 0, "dimensionless", 0.01, -np.inf, 0)),
577+
(Parameter("test", 0, "", 0.01, 0, 10), Parameter("name * test", 0.0, "dimensionless", 0.01, 0, np.inf), Parameter("test * name", 0, "dimensionless", 0.01, 0, np.inf))],
573578
ids=["zero_min", "zero_max"])
574579
def test_multiplication_with_parameter_nan_cases(self, test, expected, expected_reverse):
575580
# When
576-
parameter = Parameter(name="name", value=1, variance=0.01, min=1, max=np.Inf)
581+
parameter = Parameter(name="name", value=1, variance=0.01, min=1, max=np.inf)
577582

578583
# Then
579584
result = parameter * test
@@ -656,9 +661,9 @@ def test_multiplication_with_scalar(self, parameter : Parameter, test, expected,
656661
assert result_reverse.max == expected_reverse.max
657662

658663
@pytest.mark.parametrize("test, expected, expected_reverse", [
659-
(Parameter("test", 2, "s", 0.01, -10, 20), Parameter("name / test", 0.5, "m/s", 0.003125, -np.Inf, np.Inf), Parameter("test / name", 2, "s/m", 0.05, -np.Inf, np.Inf)),
660-
(Parameter("test", 2, "s", 0.01, 0, 20), Parameter("name / test", 0.5, "m/s", 0.003125, 0.0, np.Inf), Parameter("test / name", 2, "s/m", 0.05, 0.0, np.Inf)),
661-
(Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", -0.5, "m/s", 0.003125, -np.Inf, 0.0), Parameter("test / name", -2, "s/m", 0.05, -np.Inf, 0.0))],
664+
(Parameter("test", 2, "s", 0.01, -10, 20), Parameter("name / test", 0.5, "m/s", 0.003125, -np.inf, np.inf), Parameter("test / name", 2, "s/m", 0.05, -np.inf, np.inf)),
665+
(Parameter("test", 2, "s", 0.01, 0, 20), Parameter("name / test", 0.5, "m/s", 0.003125, 0.0, np.inf), Parameter("test / name", 2, "s/m", 0.05, 0.0, np.inf)),
666+
(Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", -0.5, "m/s", 0.003125, -np.inf, 0.0), Parameter("test / name", -2, "s/m", 0.05, -np.inf, 0.0))],
662667
ids=["crossing_zero", "only_positive", "only_negative"])
663668
def test_division_with_parameter(self, parameter : Parameter, test, expected, expected_reverse):
664669
# When
@@ -686,8 +691,8 @@ def test_division_with_parameter(self, parameter : Parameter, test, expected, ex
686691
assert result_reverse.max == expected_reverse.max
687692

688693
@pytest.mark.parametrize("first, second, expected", [
689-
(Parameter("name", 1, "m", 0.01, -10, 20), Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", -0.5, "m/s", 0.003125, -np.Inf, np.Inf)),
690-
(Parameter("name", -10, "m", 0.01, -20, -10), Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", 5.0, "m/s", 0.065, 1, np.Inf)),
694+
(Parameter("name", 1, "m", 0.01, -10, 20), Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", -0.5, "m/s", 0.003125, -np.inf, np.inf)),
695+
(Parameter("name", -10, "m", 0.01, -20, -10), Parameter("test", -2, "s", 0.01, -10, 0), Parameter("name / test", 5.0, "m/s", 0.065, 1, np.inf)),
691696
(Parameter("name", 10, "m", 0.01, 10, 20), Parameter("test", -20, "s", 0.01, -20, -10), Parameter("name / test", -0.5, "m/s", 3.125e-5, -2, -0.5))],
692697
ids=["first_crossing_zero_second_negative_0", "both_negative_second_negative_0", "finite_limits"])
693698
def test_division_with_parameter_remaining_cases(self, first, second, expected):
@@ -703,8 +708,8 @@ def test_division_with_parameter_remaining_cases(self, first, second, expected):
703708
assert result.max == expected.max
704709

705710
@pytest.mark.parametrize("test, expected, expected_reverse", [
706-
(DescriptorNumber(name="test", value=2, variance=0.1, unit="s"), Parameter("name / test", 0.5, "m/s", 0.00875, 0, 5), Parameter("test / name", 2, "s/m", 0.14, 0.2, np.Inf)),
707-
(2, Parameter("name / 2", 0.5, "m", 0.0025, 0, 5), Parameter("2 / name", 2, "m**-1", 0.04, 0.2, np.Inf))],
711+
(DescriptorNumber(name="test", value=2, variance=0.1, unit="s"), Parameter("name / test", 0.5, "m/s", 0.00875, 0, 5), Parameter("test / name", 2, "s/m", 0.14, 0.2, np.inf)),
712+
(2, Parameter("name / 2", 0.5, "m", 0.0025, 0, 5), Parameter("2 / name", 2, "m**-1", 0.04, 0.2, np.inf))],
708713
ids=["descriptor_number", "number"])
709714
def test_division_with_descriptor_number_and_number(self, parameter : Parameter, test, expected, expected_reverse):
710715
# When
@@ -750,10 +755,10 @@ def test_zero_value_divided_by_parameter(self, parameter : Parameter, test, expe
750755
assert result.variance == expected.variance
751756

752757
@pytest.mark.parametrize("first, second, expected", [
753-
(DescriptorNumber("name", 1, "m", 0.01), Parameter("test", 2, "s", 0.1, -10, 10), Parameter("name / test", 0.5, "m/s", 0.00875, -np.Inf, np.Inf)),
754-
(DescriptorNumber("name", -1, "m", 0.01), Parameter("test", 2, "s", 0.1, 0, 10), Parameter("name / test", -0.5, "m/s", 0.00875, -np.Inf, -0.1)),
755-
(DescriptorNumber("name", 1, "m", 0.01), Parameter("test", -2, "s", 0.1, -10, 0), Parameter("name / test", -0.5, "m/s", 0.00875, -np.Inf, -0.1)),
756-
(DescriptorNumber("name", -1, "m", 0.01), Parameter("test", -2, "s", 0.1, -10, 0), Parameter("name / test", 0.5, "m/s", 0.00875, 0.1, np.Inf)),
758+
(DescriptorNumber("name", 1, "m", 0.01), Parameter("test", 2, "s", 0.1, -10, 10), Parameter("name / test", 0.5, "m/s", 0.00875, -np.inf, np.inf)),
759+
(DescriptorNumber("name", -1, "m", 0.01), Parameter("test", 2, "s", 0.1, 0, 10), Parameter("name / test", -0.5, "m/s", 0.00875, -np.inf, -0.1)),
760+
(DescriptorNumber("name", 1, "m", 0.01), Parameter("test", -2, "s", 0.1, -10, 0), Parameter("name / test", -0.5, "m/s", 0.00875, -np.inf, -0.1)),
761+
(DescriptorNumber("name", -1, "m", 0.01), Parameter("test", -2, "s", 0.1, -10, 0), Parameter("name / test", 0.5, "m/s", 0.00875, 0.1, np.inf)),
757762
(DescriptorNumber("name", 1, "m", 0.01), Parameter("test", 2, "s", 0.1, 1, 10), Parameter("name / test", 0.5, "m/s", 0.00875, 0.1, 1))],
758763
ids=["crossing_zero", "positive_0_with_negative", "negative_0_with_positive", "negative_0_with_negative", "finite_limits"])
759764
def test_division_with_descriptor_number_missing_cases(self, first, second, expected):
@@ -789,8 +794,8 @@ def test_divide_by_zero_value_parameter(self):
789794
@pytest.mark.parametrize("test, expected", [
790795
(3, Parameter("name ** 3", 125, "m^3", 281.25, -125, 1000)),
791796
(2, Parameter("name ** 2", 25, "m^2", 5.0, 0, 100)),
792-
(-1, Parameter("name ** -1", 0.2, "1/m", 8e-5, -np.Inf, np.Inf)),
793-
(-2, Parameter("name ** -2", 0.04, "1/m^2", 1.28e-5, 0, np.Inf)),
797+
(-1, Parameter("name ** -1", 0.2, "1/m", 8e-5, -np.inf, np.inf)),
798+
(-2, Parameter("name ** -2", 0.04, "1/m^2", 1.28e-5, 0, np.inf)),
794799
(0, DescriptorNumber("name ** 0", 1, "dimensionless", 0)),
795800
(DescriptorNumber("test", 2), Parameter("name ** test", 25, "m^2", 5.0, 0, 100))],
796801
ids=["power_3", "power_2", "power_-1", "power_-2", "power_0", "power_descriptor_number"])
@@ -812,13 +817,13 @@ def test_power_of_parameter(self, test, expected):
812817
assert result.max == expected.max
813818

814819
@pytest.mark.parametrize("test, exponent, expected", [
815-
(Parameter("name", 5, "m", 0.05, 0, 10), -1, Parameter("name ** -1", 0.2, "1/m", 8e-5, 0.1, np.Inf)),
816-
(Parameter("name", -5, "m", 0.05, -5, 0), -1, Parameter("name ** -1", -0.2, "1/m", 8e-5, -np.Inf, -0.2)),
820+
(Parameter("name", 5, "m", 0.05, 0, 10), -1, Parameter("name ** -1", 0.2, "1/m", 8e-5, 0.1, np.inf)),
821+
(Parameter("name", -5, "m", 0.05, -5, 0), -1, Parameter("name ** -1", -0.2, "1/m", 8e-5, -np.inf, -0.2)),
817822
(Parameter("name", 5, "m", 0.05, 5, 10), -1, Parameter("name ** -1", 0.2, "1/m", 8e-5, 0.1, 0.2)),
818823
(Parameter("name", -5, "m", 0.05, -10, -5), -1, Parameter("name ** -1", -0.2, "1/m", 8e-5, -0.2, -0.1)),
819824
(Parameter("name", -5, "m", 0.05, -10, -5), -2, Parameter("name ** -2", 0.04, "1/m^2", 1.28e-5, 0.01, 0.04)),
820825
(Parameter("name", 5, "", 0.1, 1, 10), 0.3, Parameter("name ** 0.3", 1.6206565966927624, "", 0.0009455500095853564, 1, 1.9952623149688795)),
821-
(Parameter("name", 5, "", 0.1), 0.5, Parameter("name ** 0.5", 2.23606797749979, "", 0.005, 0, np.Inf))],
826+
(Parameter("name", 5, "", 0.1), 0.5, Parameter("name ** 0.5", 2.23606797749979, "", 0.005, 0, np.inf))],
822827
ids=["0_positive", "negative_0", "both_positive", "both_negative_invert", "both_negative_invert_square", "fractional", "fractional_negative_limit"])
823828
def test_power_of_diffent_parameters(self, test, exponent, expected):
824829
# When Then

0 commit comments

Comments
 (0)