diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74c2a7d1..ceafdc3f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: numpy-version: ['numpy<2.0', 'numpy>=2.0'] - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12'] # Skip CI if 'skip ci' is contained in latest commit message if: "!contains(github.event.head_commit.message, 'skip ci')" @@ -33,15 +33,17 @@ jobs: run: | python -m pip install --upgrade pip pip install "${{ matrix.numpy-version }}" - pip install -e . + pip install -e .[dev] pip install ray + python -c 'import setuptools;print(f"Using setuptools version: {setuptools.__version__}")' - name: Test with pytest run: | - python setup.py test + pytest - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: file: ./coverage.xml flags: unittests + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/docs/conf.py b/docs/conf.py index ccde52f8..44286e5f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,7 @@ # prolog taken nearly verbatim from https://github.com/spatialaudio/nbsphinx/blob/98005a9d6b331b7d6d14221539154df69f7ae51a/doc/conf.py#L38 nbsphinx_prolog = r""" -{% set docname = 'docs/' + env.doc2path(env.docname, base=None) %} +{% set docname = 'docs/' + env.doc2path(env.docname, base=None) | string() %} .. raw:: html diff --git a/reciprocalspaceship/VERSION b/reciprocalspaceship/VERSION index 6d7de6e6..21e8796a 100644 --- a/reciprocalspaceship/VERSION +++ b/reciprocalspaceship/VERSION @@ -1 +1 @@ -1.0.2 +1.0.3 diff --git a/reciprocalspaceship/__init__.py b/reciprocalspaceship/__init__.py index 2adc41a7..2e5df60a 100644 --- a/reciprocalspaceship/__init__.py +++ b/reciprocalspaceship/__init__.py @@ -1,8 +1,15 @@ # Version number for reciprocalspaceship def getVersionNumber(): - import pkg_resources + version = None + try: + from setuptools.version import metadata + + version = metadata.version("reciprocalspaceship") + except ImportError: + from setuptools.version import pkg_resources + + version = pkg_resources.require("reciprocalspaceship")[0].version - version = pkg_resources.require("reciprocalspaceship")[0].version return version diff --git a/reciprocalspaceship/dataset.py b/reciprocalspaceship/dataset.py index 04c56f19..aa187a49 100644 --- a/reciprocalspaceship/dataset.py +++ b/reciprocalspaceship/dataset.py @@ -1177,7 +1177,7 @@ def unstack_anomalous(self, columns=None, suffixes=("(+)", "(-)")): return result - def is_isomorphous(self, other, cell_threshold=0.05): + def is_isomorphous(self, other, cell_threshold=0.5): """ Determine whether DataSet is isomorphous to another DataSet. This method confirms isomorphism by ensuring the spacegroups are equivalent, @@ -1214,7 +1214,8 @@ def is_isomorphous(self, other, cell_threshold=0.05): for param in params: param1 = self.cell.__getattribute__(param) param2 = other.cell.__getattribute__(param) - if (np.abs((param1 - param2)) / 100.0) > cell_threshold: + diff = 200.0 * np.abs(param1 - param2) / (param1 + param2) + if diff > cell_threshold: return False return True diff --git a/reciprocalspaceship/io/crystfel.py b/reciprocalspaceship/io/crystfel.py index f57fa732..5903b53d 100644 --- a/reciprocalspaceship/io/crystfel.py +++ b/reciprocalspaceship/io/crystfel.py @@ -487,9 +487,7 @@ def read_crystfel( The type of byte-encoding (optional, 'utf-8'). columns : list (optional) Optionally specify the columns of the output by a list of strings. - The default list is: - [ "H", "K", "L", "I", "SigI", "BATCH", "s1x", "s1y", "s1z", "ewald_offset", - "angular_ewald_offset", "XDET", "YDET" ] + The default list is: [ "H", "K", "L", "I", "SigI", "BATCH", "s1x", "s1y", "s1z", "ewald_offset", "angular_ewald_offset", "XDET", "YDET" ] See `rs.io.crystfel.StreamLoader().available_column_names` for a list of available column names and *Notes* for a description of the returned columns parallel : bool (optional) diff --git a/tests/test_dataset.py b/tests/test_dataset.py index ec931d86..e0b4bf61 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -603,6 +603,48 @@ def test_is_isomorphous(data_unmerged, data_fmodel, sg1, sg2, cell1, cell2): assert not result +@pytest.mark.parametrize("threshold", [5.0, 1.0, 0.5, 0.1]) +def test_is_isomorphous_threshold(threshold): + """ + Test that DataSet.is_isorphous(self, other, cell_threshold) method's + cell_threshold operates on percent difference. + """ + epsilon = 1e-12 + cell = np.array([34.0, 45.0, 98.0, 90.0, 90.0, 90.0]) + spacegroup = 19 + + ds = rs.DataSet(cell=cell, spacegroup=spacegroup) + cell_resize_factor = (200.0 + threshold) / (200.0 - threshold) + + # Make a cell that should be exactly threshold percent bigger + other_cell = cell_resize_factor * cell + too_big_cell = other_cell + epsilon + big_cell = other_cell - epsilon + + # Make a cell that should be exactly threshold percent smaller + other_cell = cell / cell_resize_factor + too_small_cell = other_cell - epsilon + small_cell = other_cell + epsilon + + # Construct data sets + too_big = rs.DataSet(cell=too_big_cell, spacegroup=spacegroup) + big = rs.DataSet(cell=big_cell, spacegroup=spacegroup) + too_small = rs.DataSet(cell=too_small_cell, spacegroup=spacegroup) + small = rs.DataSet(cell=small_cell, spacegroup=spacegroup) + + # Cell is barely too big to be isomorphous + assert not ds.is_isomorphous(too_big, threshold) + + # Cell is barely too small to be isomorphous + assert not ds.is_isomorphous(too_small, threshold) + + # Cell is almost too big to be isomorphous + assert ds.is_isomorphous(big, threshold) + + # Cell is almost too small to be isomorphous + assert ds.is_isomorphous(small, threshold) + + def test_to_gemmi_withNans(data_merged): """ GH144: Test whether DataSet.to_gemmi() works with NaN-containing data.