From c6e4a44a9149db87a7937110cd3a8c0b3e27a751 Mon Sep 17 00:00:00 2001 From: ManonMarchand Date: Fri, 3 Mar 2023 10:47:46 +0100 Subject: [PATCH 1/5] add pytest for notebooks #85 and rm Cargo --- docs/contribute.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/contribute.rst b/docs/contribute.rst index d2f8cb2b..4188d7a6 100644 --- a/docs/contribute.rst +++ b/docs/contribute.rst @@ -83,6 +83,9 @@ Now build package This step will inform you of any issue in the rust part. +- After a new version of mocpy goes out, if a `maturin develop --release` does not actualise your `Cargo.toml` file, you might need to before executing the `maturin` command again:: + + rm Cargo.lock && cargo clean Running the python tests ------------------------ @@ -97,6 +100,11 @@ Once your environment is set up and activated you can run the tests python -m pytest -v python/mocpy --cov-report=term --cov=python/mocpy +- When contributing to the notebooks:: + + python -m pip install -r requirements/notebooks.txt + python -m pytest --nbmake -n=auto "./notebooks" + You also can have a html output of the coverage. For that set `--cov-report=html`, this will generate an `htmlcov` folder where all the static html files can be found. From e518efd46af84217ba302b50330ae78854df1936 Mon Sep 17 00:00:00 2001 From: ManonMarchand Date: Fri, 3 Mar 2023 11:06:52 +0100 Subject: [PATCH 2/5] default rotation to none in wcs --- python/mocpy/moc/moc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/mocpy/moc/moc.py b/python/mocpy/moc/moc.py index defb4058..aadb2858 100644 --- a/python/mocpy/moc/moc.py +++ b/python/mocpy/moc/moc.py @@ -1058,6 +1058,7 @@ def from_healpix_cells(cls, ipix, depth, max_depth): def from_depth29_ranges(cls, max_depth, ranges): """ Create a MOC from a set of ranges of HEALPix Nested indices at order 29. + For each range, the lower bound is inclusive and the upper bound is exclusive. The range `[0, 12*4^29[` represents the full-sky. @@ -1217,15 +1218,12 @@ def _query(self, resource_id, max_rows=100000, timeout=1000): votable.write(r.content) return parse_single_table(votable).to_table() - - # note to devs: performing function call in function definition won't bring a bug - # only because this defines a constant. ignoring BugBear warning B008 here. Do not reproduce. def wcs( self, fig, coordsys="icrs", projection="AIT", - rotation=Angle(0, u.radian), + rotation=None, ): """ Get a wcs that can be given to matplotlib to plot the MOC. @@ -1269,6 +1267,8 @@ def wcs( >>> plt.ylabel('dec') >>> plt.grid(color="black", linestyle="dotted") """ + if rotation is None: + rotation = Angle(0, u.radian) # The center is set to the barycenter of all its HEALPix cells center = self.barycenter() # The fov is computed from the largest distance between the center and any cells of it From 80faa8673fd4f85a5441199ef8b15145dd5ae9cb Mon Sep 17 00:00:00 2001 From: ManonMarchand Date: Fri, 3 Mar 2023 11:07:19 +0100 Subject: [PATCH 3/5] remove unused import --- python/mocpy/moc/boundaries.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/python/mocpy/moc/boundaries.py b/python/mocpy/moc/boundaries.py index 6b20ccee..8732f2a2 100644 --- a/python/mocpy/moc/boundaries.py +++ b/python/mocpy/moc/boundaries.py @@ -9,10 +9,8 @@ pass from astropy.coordinates import ICRS, SkyCoord -from astropy.wcs.utils import skycoord_to_pixel import astropy.units as u -from .. import mocpy class Boundaries: @@ -25,7 +23,7 @@ def get(moc, order): # Split the global MOC graph into all its non connected subgraphs. graph_boundaries = Boundaries._compute_graph_HEALPix_boundaries( - max_order, ipixels + max_order, ipixels, ) boundaries_l.extend(Boundaries._retrieve_skycoords(graph_boundaries)) @@ -34,9 +32,8 @@ def get(moc, order): @staticmethod def _compute_HEALPix_indices(m, order): moc = m - if order: - if m.max_order > order: - moc = m.degrade_to_order(order) + if order and m.max_order > order: + moc = m.degrade_to_order(order) max_order = moc.max_order ipixels = moc.flatten() @@ -44,7 +41,7 @@ def _compute_HEALPix_indices(m, order): # Take the complement if the MOC covers more than half of the sky => the perimeter(MOC) = perimeter(complement(MOC)) # but we process less hpx cells num_ipixels = 3 << (2 * (max_order + 1)) - sky_fraction = ipixels.shape[0] / float(num_ipixels) + ipixels.shape[0] / float(num_ipixels) # if sky_fraction > 0.5: # ipixels_all = np.arange(num_ipixels) @@ -111,10 +108,10 @@ def insert_edge(G, l1, l2, p1_lon, p1_lat, p2_lon, p2_lat): ipix_lat_deg = ipix_lat.to_value(u.deg) ipix_lon_repr = np.around( - np.asarray(ipix_lon.reshape((1, -1))[0]), decimals=3 + np.asarray(ipix_lon.reshape((1, -1))[0]), decimals=3, ).tolist() ipix_lat_repr = np.around( - np.asarray(ipix_lat.reshape((1, -1))[0]), decimals=3 + np.asarray(ipix_lat.reshape((1, -1))[0]), decimals=3, ).tolist() west_border = ~isin_border[0, :] From 01a835f64daca5bf24926646352204bbc6af1a15 Mon Sep 17 00:00:00 2001 From: ManonMarchand Date: Fri, 3 Mar 2023 11:24:07 +0100 Subject: [PATCH 4/5] PermissionError raised when trying to manually change order of a STMOC --- CHANGELOG.md | 6 ++++ python/mocpy/stmoc/stmoc.py | 64 +++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e08abda..7c4df87f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] + +### Added + +* `MOC.__init__` and `STMOC.__init__` raise `PermissionError` if user tries to modify order manually + ## [0.12.2] ### Added diff --git a/python/mocpy/stmoc/stmoc.py b/python/mocpy/stmoc/stmoc.py index f22942f5..6690e68f 100644 --- a/python/mocpy/stmoc/stmoc.py +++ b/python/mocpy/stmoc/stmoc.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function import numpy as np @@ -27,20 +25,21 @@ def __init__(self, create_key, store_index): create_key: Object ensure __init__ is called by super-class/class-methods only store_index: index of the ST-MOC in the rust-side storage """ - super(STMOC, self).__init__( - AbstractMOC._create_key, STMOC.__create_key, store_index + super().__init__( + AbstractMOC._create_key, STMOC.__create_key, store_index, ) - assert ( - create_key == STMOC.__create_key - ), "ST-MOC instantiation is only allowed by class or super-class methods" + if create_key != STMOC.__create_key: + raise PermissionError( + "ST-MOC instantiation is only allowed by class or super-class methods", + ) def __del__(self): """Erase STMOC.""" - super(STMOC, self).__del__() + super().__del__() def __eq__(self, other): """Assert equality between MOCs.""" - return super(STMOC, self).__eq__(other) + return super().__eq__(other) @property def max_depth(self): @@ -98,13 +97,12 @@ def from_times_positions(cls, times, time_depth, lon, lat, spatial_depth): raise ValueError("Times and positions must be 1D arrays.") index = mocpy.from_time_lonlat(times, time_depth, lon, lat, spatial_depth) - result = cls(cls.__create_key, index) - return result + return cls(cls.__create_key, index) @classmethod def from_time_ranges_positions( - cls, times_start, times_end, lon, lat, time_depth=61, spatial_depth=29 + cls, times_start, times_end, lon, lat, time_depth=61, spatial_depth=29, ): """ Create a 2D Coverage from a set of times and positions associated to each time. @@ -152,15 +150,14 @@ def from_time_ranges_positions( raise ValueError("Times and positions must be 1D arrays.") index = mocpy.from_time_ranges_lonlat( - times_start, times_end, time_depth, lon, lat, spatial_depth + times_start, times_end, time_depth, lon, lat, spatial_depth, ) - result = cls(cls.__create_key, index) - return result + return cls(cls.__create_key, index) @classmethod def from_spatial_coverages( - cls, times_start, times_end, spatial_coverages, time_depth=61 + cls, times_start, times_end, spatial_coverages, time_depth=61, ): """ Create a 2D Coverage from a set of time ranges and spatial coverages associated to them. @@ -187,10 +184,10 @@ def from_spatial_coverages( times_end = times_to_microseconds(times_end) if times_start.shape != times_end.shape or times_start.shape[0] != len( - spatial_coverages + spatial_coverages, ): raise ValueError( - "Time ranges and spatial coverages must have the same length" + "Time ranges and spatial coverages must have the same length", ) if times_start.ndim != 1: @@ -198,14 +195,13 @@ def from_spatial_coverages( spatial_coverages_indices = np.fromiter( - (arg._store_index for arg in spatial_coverages), dtype=AbstractMOC.store_index_dtype() + (arg._store_index for arg in spatial_coverages), dtype=AbstractMOC.store_index_dtype(), ) index = mocpy.from_time_ranges_spatial_coverages( - times_start, times_end, time_depth, spatial_coverages_indices + times_start, times_end, time_depth, spatial_coverages_indices, ) - result = cls(cls.__create_key, index) - return result + return cls(cls.__create_key, index) def query_by_time(self, tmoc): """ @@ -295,10 +291,11 @@ def contains(self, times, lon, lat, inside=True): if not inside: result = ~result - return result + return result # noqa: RET504 @classmethod - def load(cls, path, format="fits"): + # A002: Argument `format` is shadowing a python function + def load(cls, path, format="fits"): # noqa: A002 """ Load the Spatial MOC from a file. @@ -317,15 +314,14 @@ def load(cls, path, format="fits"): if format == "fits": index = mocpy.coverage_2d_from_fits_file(path) return cls(cls.__create_key, index) - elif format == "ascii": + if format == "ascii": index = mocpy.coverage_2d_from_ascii_file(path) return cls(cls.__create_key, index) - elif format == "json": + if format == "json": index = mocpy.coverage_2d_from_json_file(path) return cls(cls.__create_key, index) - else: - formats = ("fits", "ascii", "json") - raise ValueError("format should be one of %s" % (str(formats))) + formats = ("fits", "ascii", "json") + raise ValueError("format should be one of %s" % (str(formats))) @classmethod def _from_fits_raw_bytes(cls, raw_bytes): @@ -334,7 +330,8 @@ def _from_fits_raw_bytes(cls, raw_bytes): return cls(cls.__create_key, index) @classmethod - def from_string(cls, value, format="ascii"): + # A002: Argument `format` is shadowing a python function + def from_string(cls, value, format="ascii"): # noqa: A002 """ Deserialize the Spatial MOC from the given string. @@ -350,9 +347,8 @@ def from_string(cls, value, format="ascii"): if format == "ascii": index = mocpy.coverage_2d_from_ascii_str(value) return cls(cls.__create_key, index) - elif format == "json": + if format == "json": index = mocpy.coverage_2d_from_json_str(value) return cls(cls.__create_key, index) - else: - formats = ("ascii", "json") - raise ValueError("format should be one of %s" % (str(formats))) + formats = ("ascii", "json") + raise ValueError("format should be one of %s" % (str(formats))) From 35c03923e9bef6aba770f5d6d3ab7ae49541c0a8 Mon Sep 17 00:00:00 2001 From: fxpineau Date: Mon, 6 Mar 2023 11:50:42 +0100 Subject: [PATCH 5/5] Prepare for v0.12.3 --- .github/workflows/deploy.yml | 4 ++-- CHANGELOG.md | 6 +++++- Cargo.toml | 4 ++-- python/mocpy/version.py | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c3e496ab..1874457f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -92,8 +92,8 @@ jobs: echo "Loop on PYBIN: $PYBIN" "${PYBIN}/pip" install maturin "${PYBIN}/maturin" -V - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" --target aarch64-unknown-linux-gnu --config "net.git-fetch-with-cli = true" - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" --target aarch64-unknown-linux-gnu --config "net.git-fetch-with-cli = true" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" --target aarch64-unknown-linux-gnu --config "net.git-fetch-with-cli = true" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" --target aarch64-unknown-linux-gnu --config "net.git-fetch-with-cli = true" done' build-windows-wheels: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c4df87f..c4606627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [unreleased] +# [0.12.3] ### Added * `MOC.__init__` and `STMOC.__init__` raise `PermissionError` if user tries to modify order manually +### Fixed + +* :bug: position angle limited to PI/2 instead of PI in `MOC.from_elliptical_cone` + ## [0.12.2] ### Added diff --git a/Cargo.toml b/Cargo.toml index 9ce6b693..441b68ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "MOCPy" -version = "0.12.2" +version = "0.12.3" authors = [ "Matthieu Baumann ", "Thomas Boch ", @@ -27,7 +27,7 @@ bench = true crate-type = ["cdylib"] [dependencies] -moc = { version = "0.11", features = ["storage"] } +moc = { version = "0.11.2", features = ["storage"] } healpix = { package = "cdshealpix", version = "0.6" } # moc = { git = 'https://github.com/cds-astro/cds-moc-rust', branch = 'main', features = ["storage"] } # healpix = { package = "cdshealpix", git = 'https://github.com/cds-astro/cds-healpix-rust', branch = 'master' } diff --git a/python/mocpy/version.py b/python/mocpy/version.py index 76da4a98..8e1395bd 100644 --- a/python/mocpy/version.py +++ b/python/mocpy/version.py @@ -1 +1 @@ -__version__ = "0.12.2" +__version__ = "0.12.3"