astropop 0.9.5.dev11__tar.gz → 0.9.5.dev30__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astropop-0.9.5.dev30/.agents/AGENTS.md +27 -0
- astropop-0.9.5.dev30/.agents/rules/development.md +32 -0
- astropop-0.9.5.dev30/.agents/skills/astropop-catalogs/SKILL.md +35 -0
- astropop-0.9.5.dev30/.agents/skills/astropop-ci/SKILL.md +40 -0
- astropop-0.9.5.dev30/.agents/skills/astropop-docs/SKILL.md +30 -0
- astropop-0.9.5.dev30/.agents/skills/astropop-scientific-code/SKILL.md +22 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.github/workflows/build-n-publish.yml +4 -4
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.github/workflows/ci_devdeps.yml +12 -11
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.github/workflows/ci_workflows.yml +21 -14
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/PKG-INFO +9 -7
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/_online_tools.py +5 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/gaia.py +112 -13
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/simbad.py +66 -11
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier.py +10 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/apass9.yml +7 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/twomass.yml +2 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/ucac4.yml +3 -3
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/ucac5.yml +2 -2
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/imcombine.py +6 -6
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/photometry/aperture.py +6 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/photometry/detection.py +3 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/py_utils.py +2 -2
- astropop-0.9.5.dev30/astropop/version.py +24 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop.egg-info/PKG-INFO +9 -7
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop.egg-info/SOURCES.txt +22 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop.egg-info/requires.txt +6 -4
- astropop-0.9.5.dev30/astropop.egg-info/scm_file_list.json +157 -0
- astropop-0.9.5.dev30/astropop.egg-info/scm_version.json +8 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/conf.py +1 -2
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/astrometry.rst +6 -6
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/imarith.rst +3 -3
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/catalog/gaia.rst +29 -8
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/catalog/simbad.rst +5 -5
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/catalog/vizier.rst +12 -13
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/files.rst +2 -2
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/pyproject.toml +13 -6
- astropop-0.9.5.dev30/tests/conftest.py +220 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/README.md +68 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/allwise.yaml +3167 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/apass9.yaml +1079 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/gaia.yaml +10871 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/gsc242.yaml +4830 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/simbad.yaml +6668 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/skymapper.yaml +835 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/twomass.yaml +2306 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/tycho2.yaml +982 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/ucac4.yaml +1376 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/ucac5.yaml +160 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/vsx.yaml +679 -0
- astropop-0.9.5.dev30/tests/data/catalog_responses/wise.yaml +3600 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_aperture.py +14 -2
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_astrometry.py +4 -5
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_catalogs.py +2 -2
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_catalogs_online.py +384 -55
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_detection.py +3 -3
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_filecollection.py +1 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata.py +4 -4
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_cachemanager.py +42 -26
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_compat.py +1 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_tools.py +5 -4
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_image_imcombine.py +7 -7
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_math.py +0 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_physical_numpyfuncs.py +1 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_polarimetry.py +10 -10
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_pyutils.py +26 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tox.ini +24 -7
- astropop-0.9.5.dev11/astropop/version.py +0 -16
- astropop-0.9.5.dev11/tests/conftest.py +0 -1
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.codacy.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.github/workflows/code_quality_analysis.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.gitignore +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/.readthedocs.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/MANIFEST.in +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/README.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/_unit_property.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/astrometry/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/astrometry/astrometrynet.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/astrometry/coords_utils.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/astrometry/manual_wcs.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/_sources_catalog.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/allwise.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/denis.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/gsc242.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/hip.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/skymapper.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/tycho2.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/vsx.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/catalogs/vizier_catalogs/wise.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/file_collection.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/fits_utils.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/flags.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/_compat.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/_memmap.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/cache_manager.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/framedata.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/framedata/util.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/_tools.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/imarith.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/processing.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/image/register.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/logger.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/_deriv.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/array.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/hasher.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/models.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/math/physical.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/photometry/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/photometry/background.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/polarimetry/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop/testing.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop.egg-info/dependency_links.txt +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/astropop.egg-info/top_level.txt +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/codecov.yml +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/Makefile +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/_static/le2pol.jpeg +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/data_structures/framedata.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/data_structures/physical.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/data_structures.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/dev/pixel_convention.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/index.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/ipynb/astrometry_example.ipynb +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/ipynb/diy_reduction_script.ipynb +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/ipynb/online_catalogs.ipynb +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/make.bat +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reducing.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/ccdprocessing.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/photometry.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/pipelines.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/polarimetry.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/reduction/registering.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/references.txt +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/catalogs.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/fits_utils.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/logger.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/py_utils.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools/testing.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/tools.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/docs/user_guide.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/licenses/LICENSE.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/licenses/TEMPLATE_LICENCE.rst +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/scripts/fitsheader_set +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/setup.cfg +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/setup.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/__init__.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_fits_utils.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_flags.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_getset.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_io.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_memmap.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_meta.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_framedata_utils.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_image_imarith.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_image_mergers.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_image_processing.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_image_register.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_logger.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_math_models.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_physical.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_testing.py +0 -0
- {astropop-0.9.5.dev11 → astropop-0.9.5.dev30}/tests/test_unit_property.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Working on Astropop
|
|
2
|
+
|
|
3
|
+
Read [.agents/rules/development.md](rules/development.md) before changing this repository. These instructions apply throughout the checkout; explicit user instructions take precedence.
|
|
4
|
+
|
|
5
|
+
## Commit messages
|
|
6
|
+
|
|
7
|
+
Begin every commit subject with the module or area being changed, followed by a colon and a short description. Prefer a space after the colon:
|
|
8
|
+
|
|
9
|
+
- `catalogs: handle empty SIMBAD responses`
|
|
10
|
+
- `framedata: isolate cache shutdown tests`
|
|
11
|
+
- `image: exclude rejected samples from summed errors`
|
|
12
|
+
- `docs: explain FrameData conversion`
|
|
13
|
+
- `ci: run live catalog checks in a separate job`
|
|
14
|
+
- `agents: add repository skills`
|
|
15
|
+
|
|
16
|
+
Make small, coherent commits. Use the affected module for its tests too; reserve `ci:` for workflows, environments, dependencies, and cross-cutting test infrastructure. Split unrelated changes rather than hiding them behind a broad prefix. Do not rewrite existing commits solely to enforce this convention unless asked.
|
|
17
|
+
|
|
18
|
+
## Repository skills
|
|
19
|
+
|
|
20
|
+
Read the relevant skill when its workflow applies. Ordinary small edits do not require loading every skill.
|
|
21
|
+
|
|
22
|
+
| Skill | Use when |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| [astropop-ci](skills/astropop-ci/SKILL.md) | Diagnosing test, coverage, dependency, or GitHub Actions failures. |
|
|
25
|
+
| [astropop-catalogs](skills/astropop-catalogs/SKILL.md) | Changing SIMBAD, VizieR, Gaia, or recorded/live catalog tests. |
|
|
26
|
+
| [astropop-scientific-code](skills/astropop-scientific-code/SKILL.md) | Changing image reduction, FrameData, units, uncertainties, photometry, or polarimetry. |
|
|
27
|
+
| [astropop-docs](skills/astropop-docs/SKILL.md) | Editing API docs, scientific examples, or fixing Sphinx builds. |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Development rules
|
|
2
|
+
|
|
3
|
+
## Scope and branches
|
|
4
|
+
|
|
5
|
+
- Inspect `git status`, the current branch, and nearby code/tests before editing. Preserve unrelated work.
|
|
6
|
+
- Keep independent fixes and features separate. A CI repair is not permission to redesign cache ownership, uncertainty semantics, or registration algorithms.
|
|
7
|
+
- When asked for a new independent branch, use the requested base; otherwise prefer local `main` and state the choice. Use a feature branch as a base only when the work depends on it. Do not silently reset, discard work, or rewrite history.
|
|
8
|
+
- Complete authorized local work without repeated confirmation. Local edits or commits do not themselves authorize a push, PR publication, merge, or release.
|
|
9
|
+
|
|
10
|
+
## Implementation
|
|
11
|
+
|
|
12
|
+
- Follow neighboring Python conventions and NumPy-style docstrings. Prefer the smallest change that fixes the cause while preserving public behavior.
|
|
13
|
+
- Preserve physical units, coordinate frames/epochs, masks, uncertainties, shapes, and in-place semantics unless the task explicitly changes them.
|
|
14
|
+
- Add regression coverage for behavioral fixes. Do not delete operations from exception or nonmutation tests just because their return values are unused.
|
|
15
|
+
- Use `tmp_path` for disposable files/directories. Never hand a shared directory such as the system temporary root to an object that deletes its cache directory.
|
|
16
|
+
- Test interpreter shutdown in a child process. Never call `atexit._run_exitfuncs()` inside pytest: it can stop coverage measurement and execute unrelated handlers.
|
|
17
|
+
- Keep helpers inside their owning test classes where practical. Put genuinely shared fixtures in `conftest.py`; avoid one-off test files when an existing module fits.
|
|
18
|
+
|
|
19
|
+
## Validation
|
|
20
|
+
|
|
21
|
+
- Treat `pyproject.toml`, `tox.ini`, and `.github/workflows/` in this checkout as authoritative. Do not assume a test option or feature from another branch exists here.
|
|
22
|
+
- Use an isolated Python environment with the appropriate test/docs extras. If using `XDG_CACHE_HOME` or `XDG_CONFIG_HOME`, create the directories first; Astropy may ignore nonexistent paths.
|
|
23
|
+
- Start with the affected tests and broaden to the relevant integration checks. Once checks pass, repeat them only for new changes, failures, or unresolved concerns.
|
|
24
|
+
- Keep ordinary CI offline and live catalog conformance in one explicit job when that infrastructure is present. Never make missing recorded responses silently fall through to the network.
|
|
25
|
+
- Report commands/results, skips, and outstanding checks accurately. A local Linux pass does not prove Windows, macOS, oldest dependencies, development dependencies, or remote CI passed.
|
|
26
|
+
- Do not globally suppress warnings or weaken tolerances to hide a failure. Expect deliberate warnings locally and fix unintended behavior at its source.
|
|
27
|
+
|
|
28
|
+
## Commits and handoff
|
|
29
|
+
|
|
30
|
+
Follow the module-prefix convention in [AGENTS.md](../AGENTS.md). Review the staged diff and commit in small batches, grouping implementation with its applicable tests. Stage named paths or hunks so unrelated changes are not included.
|
|
31
|
+
|
|
32
|
+
PR descriptions should explain the concrete failure and resulting behavior, then give relevant validation and known limitations. Distinguish implemented fixes from future work and verified service behavior from recordings or historical observations.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: astropop-catalogs
|
|
3
|
+
description: Maintain Astropop SIMBAD, VizieR, and Gaia queries and their shared recorded/live tests, including schema changes, timeouts, and complete query results.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Astropop catalogs
|
|
7
|
+
|
|
8
|
+
Read the affected implementation in `astropop/catalogs/`, the corresponding tests in `tests/test_catalogs_online.py`, and the applicable VizieR YAML. Verify the installed Astroquery API and actual response shape before changing an endpoint or column name.
|
|
9
|
+
|
|
10
|
+
## Compatibility invariants
|
|
11
|
+
|
|
12
|
+
- SIMBAD can return degree-valued lowercase coordinates or legacy sexagesimal uppercase coordinates. Never infer hour-angle units from the semantic name RA alone. Handle both `None` and empty tables before indexing.
|
|
13
|
+
- TAP photometry may have multiple rows per source/filter. Preserve source identity, band case, masks, proper motions, and bibliographic information when normalizing it.
|
|
14
|
+
- Choose cone-search matches by separation rather than trusting response order. Identifier priority and prefix boundaries matter; substring matching can select a different catalog designation.
|
|
15
|
+
- VizieR column aliases must work in outgoing column selection and incoming response normalization without renaming an already normalized column twice. Check sort-column names and epoch values against the configured time format.
|
|
16
|
+
- Gaia asynchronous queue delays do not establish that a URL changed. Preserve the requested query mode and document timeout limitations honestly.
|
|
17
|
+
- Where synchronous Gaia pagination is implemented, preserve integer source IDs, magnitude/cone filters on every page, exact column matching, final angular-distance ordering, and failure rather than partial results. Include page boundaries and IDs above `2**53` in deterministic coverage.
|
|
18
|
+
- Keep timeout changes scoped to the client's connections, restore patched methods, close connections, and share a deadline across retries/pages. A socket timeout is not a hard deadline covering every DNS, streaming, or parsing step.
|
|
19
|
+
|
|
20
|
+
## Recorded and live tests
|
|
21
|
+
|
|
22
|
+
First check whether `tests/data/catalog_responses/README.md` and replay options exist on this branch. Read that README before recording. On branches without replay infrastructure, do not report skipped remote tests as offline conformance.
|
|
23
|
+
|
|
24
|
+
Where supported:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
python -m pytest tests/test_catalogs_online.py --remote-data=none
|
|
28
|
+
python -m pytest tests/test_catalogs_online.py --remote-data=any
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Keep assertions and collected test IDs shared between modes. Mock at the HTTP layer so Astroquery still builds queries and parses responses. Store compact fixtures per catalog, not per test. Offline mode must fail for unknown requests; live mode must bypass replay and result caches. Account for VizieR's explicit cache argument and import-time Gaia announcements.
|
|
32
|
+
|
|
33
|
+
Refresh fixtures only when needed, using the documented explicit recording mode in one process. Preserve strict matching of query criteria, coordinates, filters, and pagination cursors. Normalize ordering only where semantically harmless, such as simple SELECT column lists. Review recordings for credentials/cookies and unrelated changes; rerun offline after recording.
|
|
34
|
+
|
|
35
|
+
Keep deterministic edge-case tests alongside the catalog tests, with class-owned helpers where practical. Assert intentional no-result or proper-motion warnings around the precise call instead of suppressing them globally. A live Gaia skip option, if present, must leave offline and deterministic Gaia tests enabled and must not disable the dedicated conformance job's Gaia checks.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: astropop-ci
|
|
3
|
+
description: Diagnose and fix Astropop test, coverage, dependency, tox, and GitHub Actions failures while keeping ordinary CI independent of live catalogs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Astropop CI
|
|
7
|
+
|
|
8
|
+
Inspect the failing job, current configuration, and failing test before choosing a fix. Separate a collection/import failure, assertion failure, service outage, dependency incompatibility, and coverage-measurement failure; they need different remedies.
|
|
9
|
+
|
|
10
|
+
## Sources and checks
|
|
11
|
+
|
|
12
|
+
- Dependency bounds and pytest/coverage settings: `pyproject.toml`.
|
|
13
|
+
- Environment factors, extras, and commands: `tox.ini`.
|
|
14
|
+
- Runner/platform and live/offline topology: `.github/workflows/`.
|
|
15
|
+
- Catalog replay and custom options, if implemented: `tests/conftest.py` and `tests/data/catalog_responses/README.md`.
|
|
16
|
+
|
|
17
|
+
Use the environment actually named in the failing job. Inspect `tox list` and `tox config -e <environment>` before assuming factors expand correctly. Check Python support and oldest dependency compatibility together. A version pin should explain the concrete incompatible API; it is not a substitute for claiming a migration is complete.
|
|
18
|
+
|
|
19
|
+
Typical checks, adjusted to the installed tooling and changed files:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
python -m pytest tests/test_affected_module.py
|
|
23
|
+
python -m pytest tests docs --remote-data=none --cov=astropop --cov-report=term-missing
|
|
24
|
+
python -m ruff check astropop tests
|
|
25
|
+
git diff --check
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The first path is a placeholder for the actual test module. If Ruff is not configured/installed in this checkout, inspect the repository's lint configuration first.
|
|
29
|
+
|
|
30
|
+
## Coverage and resources
|
|
31
|
+
|
|
32
|
+
For a coverage collapse, inspect collection/skips and whether any test executes process-wide shutdown handlers. Preserve the existing cache API while repairing harness isolation unless cache redesign is explicitly in scope. Test exit behavior with a subprocess, not pytest's own exit handlers. Use per-test cache directories and close file handles, including on Windows.
|
|
33
|
+
|
|
34
|
+
## Catalog topology
|
|
35
|
+
|
|
36
|
+
When the replay infrastructure exists, regular Python/platform/dependency jobs and coverage use recordings. Keep exactly one separate live catalog conformance job, including Gaia; a fast/offline Python job must still exist alongside it. Inspect the YAML embedded inside reusable-workflow `envs` strings as well as the outer workflow.
|
|
37
|
+
|
|
38
|
+
Do not hide conformance failures by switching the live job to replay or silently skipping a service. Record an outage separately from a deterministic code failure. Use the catalog skill for query/schema and fixture changes.
|
|
39
|
+
|
|
40
|
+
Validate relevant local checks, then report which remote/platform jobs remain unrun. Check the staged diff for unrelated feature code before making a module-prefixed commit.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: astropop-docs
|
|
3
|
+
description: Write or repair Astropop reStructuredText guides, NumPy-style API docstrings, and Sphinx examples using the behavior implemented on the current branch.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Astropop documentation
|
|
7
|
+
|
|
8
|
+
Read the implementation, nearby tests, and the relevant guide under `docs/`. Keep constructor APIs distinct from conversion helpers and describe actual defaults, mutation behavior, units, masks, and uncertainty semantics.
|
|
9
|
+
|
|
10
|
+
Use runnable examples for deterministic local behavior where the existing documentation tooling supports them. Use static Python blocks for live catalog examples so documentation builds do not depend on external catalog queries. Remove IPython-only options when converting a directive to `code-block`.
|
|
11
|
+
|
|
12
|
+
For FrameData guides, check shape/dtype constraints, copying and array sharing, metadata/WCS, FITS extension selection, overwrite defaults, and whether interchange preserves Boolean masks or full flag bits. Document only storage/configuration features available on this branch.
|
|
13
|
+
|
|
14
|
+
For build failures:
|
|
15
|
+
|
|
16
|
+
- Check reStructuredText section hierarchy, blank lines before lists, indentation, and balanced inline markup.
|
|
17
|
+
- Keep the local checkout first on the documentation import path so autodoc describes the changed source.
|
|
18
|
+
- Inspect `docs/conf.py` and docs extras rather than installing arbitrary extensions. Notebook rendering may require the Pandoc executable in addition to a Python package.
|
|
19
|
+
- Distinguish rendering/autodoc errors, external inventory/network failures, and existing warnings. Do not suppress warnings globally to produce a green build.
|
|
20
|
+
|
|
21
|
+
Validation depends on the change:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
python -m pytest docs/path/to/changed-guide.rst
|
|
25
|
+
python -m sphinx -b html docs /tmp/astropop-docs-build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Replace the guide path with the actual file. Use the configured tox docs environment when reproducing CI. For a warning audit, add `-W --keep-going` and report its result separately from the ordinary build. Inspect relevant rendered examples when layout or generated API content changes.
|
|
29
|
+
|
|
30
|
+
Keep generated HTML, temporary images, and build caches out of commits. Use `docs:` for documentation commits and name the affected module when docstring updates are part of its implementation fix.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: astropop-scientific-code
|
|
3
|
+
description: Implement and test Astropop scientific behavior in FrameData, image reduction, units and uncertainties, photometry, or polarimetry while preserving numerical and storage contracts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Astropop scientific code
|
|
7
|
+
|
|
8
|
+
Locate the affected code in `astropop/framedata/`, `astropop/image/`, `astropop/math/`, `astropop/photometry/`, or `astropop/polarimetry/` and its existing tests. Read the current API and documentation; do not assume optional uncertainties, cache redesigns, or registration windows exist because they were discussed on another branch.
|
|
9
|
+
|
|
10
|
+
## Define observable behavior
|
|
11
|
+
|
|
12
|
+
Identify the expected data, units, shape/dtype, mask, uncertainty, metadata, and input-mutation behavior. Add a small numerical regression case with an independently derived result. Include compatible unit conversion and incompatible-unit errors when relevant.
|
|
13
|
+
|
|
14
|
+
- Missing uncertainty and zero uncertainty are different storage states. If an operation promises to skip uncertainty work, test that conversion/propagation helpers are not invoked, not merely that the final array is absent.
|
|
15
|
+
- In combining, apply rejection consistently to data and propagated errors. Check valid-sample counts and any normalization factor, including masked/all-rejected pixels. Preserve the existing estimator unless a statistical change is requested.
|
|
16
|
+
- Test in-place and copying paths when affected; non-inplace calls must preserve source arrays and metadata. Exercise RAM/memmap paths for storage changes, including cleanup after exceptions.
|
|
17
|
+
- Registration uses array row/column conventions and transform coordinate conventions that may differ. For a requested window feature, estimate from the window but test application to the full image and any necessary origin translation. Use sparse, deterministic synthetic sources to avoid ambiguous matches.
|
|
18
|
+
- Photometry fixtures should use seeded noise when noise is necessary. Verify scalar and array-valued parameters against each other when both are supported. Do not simply loosen a numerical tolerance to hide nondeterminism.
|
|
19
|
+
|
|
20
|
+
Use the existing test module for the affected subsystem. Restore global configuration changes with fixtures/monkeypatch. Keep regression cases small enough to diagnose and run routinely; use broader integration tests when the change crosses subsystem boundaries.
|
|
21
|
+
|
|
22
|
+
Document changed scientific assumptions and API behavior, and distinguish numerical correctness checks from performance measurements. Do not claim speed or memory improvements without measurements when those claims matter to the task.
|
|
@@ -12,13 +12,13 @@ jobs:
|
|
|
12
12
|
name: Build and publish to PyPi
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
16
|
with:
|
|
17
17
|
fetch-depth: 0
|
|
18
|
-
- name: Set up Python 3.
|
|
19
|
-
uses: actions/setup-python@
|
|
18
|
+
- name: Set up Python 3.13
|
|
19
|
+
uses: actions/setup-python@v6
|
|
20
20
|
with:
|
|
21
|
-
python-version: 3.
|
|
21
|
+
python-version: '3.13'
|
|
22
22
|
- name: Install pypa/build
|
|
23
23
|
run: >-
|
|
24
24
|
python -m
|
|
@@ -23,19 +23,20 @@ jobs:
|
|
|
23
23
|
libraries: |
|
|
24
24
|
apt:
|
|
25
25
|
- tzdata
|
|
26
|
-
- libopenblas-base
|
|
27
26
|
- libopenblas-dev
|
|
28
27
|
envs: |
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
python-version: 3.13-dev
|
|
32
|
-
|
|
28
|
+
# Live service compatibility is checked in CI's online conformance job.
|
|
29
|
+
# These environments exercise dependency/platform changes with mocks.
|
|
33
30
|
- name: (Allowed Failure) Python 3.13 with dev version of deps
|
|
34
|
-
linux: py313-test-devdeps
|
|
35
|
-
python-version: 3.
|
|
31
|
+
linux: py313-test-devdeps
|
|
32
|
+
python-version: '3.13'
|
|
33
|
+
|
|
34
|
+
- name: (Allowed Failure) Python 3.14 with dev version of deps
|
|
35
|
+
linux: py314-test-devdeps
|
|
36
|
+
python-version: '3.14'
|
|
36
37
|
|
|
37
|
-
- macos:
|
|
38
|
-
cache-key: ${{ github.ref }}-
|
|
38
|
+
- macos: py313-test
|
|
39
|
+
cache-key: ${{ github.ref }}-py313mac-astropycache
|
|
39
40
|
|
|
40
|
-
- windows:
|
|
41
|
-
cache-key: ${{ github.ref }}-
|
|
41
|
+
- windows: py313-test
|
|
42
|
+
cache-key: ${{ github.ref }}-py313win-astropycache
|
|
@@ -20,16 +20,25 @@ jobs:
|
|
|
20
20
|
with:
|
|
21
21
|
cache-path: ~/.astropy
|
|
22
22
|
envs: |
|
|
23
|
-
- linux:
|
|
24
|
-
cache-key: ${{ github.ref }}-py38lin-astropycache
|
|
25
|
-
- linux: py39-test-online
|
|
26
|
-
cache-key: ${{ github.ref }}-py39lin-astropycache
|
|
27
|
-
- linux: py310-test-online
|
|
23
|
+
- linux: py310-test-olddeps
|
|
28
24
|
cache-key: ${{ github.ref }}-py310lin-astropycache
|
|
29
|
-
- linux: py311-test
|
|
25
|
+
- linux: py311-test
|
|
30
26
|
cache-key: ${{ github.ref }}-py311lin-astropycache
|
|
31
|
-
- linux: py312-test
|
|
27
|
+
- linux: py312-test
|
|
32
28
|
cache-key: ${{ github.ref }}-py312lin-astropycache
|
|
29
|
+
- linux: py313-test
|
|
30
|
+
cache-key: ${{ github.ref }}-py313lin-astropycache
|
|
31
|
+
- linux: py314-test
|
|
32
|
+
cache-key: ${{ github.ref }}-py314lin-astropycache
|
|
33
|
+
|
|
34
|
+
online_conformance:
|
|
35
|
+
name: Online catalog conformance
|
|
36
|
+
uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1
|
|
37
|
+
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
|
|
38
|
+
with:
|
|
39
|
+
envs: |
|
|
40
|
+
- linux: py314-catalogs-online
|
|
41
|
+
python-version: '3.14'
|
|
33
42
|
|
|
34
43
|
build_docs:
|
|
35
44
|
uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1
|
|
@@ -68,14 +77,12 @@ jobs:
|
|
|
68
77
|
path: ${{ env.CONDA }}/envs
|
|
69
78
|
key:
|
|
70
79
|
${{ github.ref }}-${{ runner.os }}-${{ runner.arch }}-${{ steps.get-date.outputs.today }}-conda-envs-${{ hashFiles('pyproject.toml') }}
|
|
71
|
-
- uses: conda-incubator/setup-miniconda@
|
|
80
|
+
- uses: conda-incubator/setup-miniconda@v4
|
|
72
81
|
with:
|
|
73
|
-
miniforge-variant: Mambaforge
|
|
74
82
|
miniforge-version: latest
|
|
75
83
|
activate-environment: astropop
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
channels: conda-forge,defaults
|
|
84
|
+
channels: conda-forge
|
|
85
|
+
conda-remove-defaults: true
|
|
79
86
|
python-version: "3.12"
|
|
80
87
|
- name: Cache astropy cache
|
|
81
88
|
uses: actions/cache@v3
|
|
@@ -87,7 +94,7 @@ jobs:
|
|
|
87
94
|
- name: Install dependencies
|
|
88
95
|
shell: bash -l {0}
|
|
89
96
|
run: |
|
|
90
|
-
|
|
97
|
+
conda install -y -q pytest astrometry \
|
|
91
98
|
astropy scipy numpy matplotlib \
|
|
92
99
|
scikit-image scikit-learn \
|
|
93
100
|
sep astroquery
|
|
@@ -104,7 +111,7 @@ jobs:
|
|
|
104
111
|
- name: Run Pytest and generate coverage
|
|
105
112
|
shell: bash -l {0}
|
|
106
113
|
run: |
|
|
107
|
-
pytest --pyargs ./tests ./docs --remote-data --cov astropop --cov-config=./pyproject.toml
|
|
114
|
+
pytest --pyargs ./tests ./docs --remote-data=none --cov astropop --cov-config=./pyproject.toml
|
|
108
115
|
coverage xml -o ./coverage.xml
|
|
109
116
|
- name: Upload coverage to Codecov
|
|
110
117
|
uses: codecov/codecov-action@v4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: astropop
|
|
3
|
-
Version: 0.9.5.
|
|
3
|
+
Version: 0.9.5.dev30
|
|
4
4
|
Summary: Astronomical Polarimetry and Photometry Pipeline
|
|
5
5
|
Author-email: Julio Campagnolo <julio.campagnolo@cefet-rj.br>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -17,15 +17,15 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
18
|
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
19
19
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
21
|
Description-Content-Type: text/x-rst
|
|
22
|
-
Requires-Dist: astropy>=
|
|
23
|
-
Requires-Dist: numpy>=1.
|
|
24
|
-
Requires-Dist: scipy>=1.
|
|
22
|
+
Requires-Dist: astropy>=5.0
|
|
23
|
+
Requires-Dist: numpy>=1.21.6
|
|
24
|
+
Requires-Dist: scipy>=1.7.3
|
|
25
25
|
Requires-Dist: astroquery
|
|
26
26
|
Requires-Dist: scikit-image
|
|
27
27
|
Requires-Dist: scikit-learn
|
|
28
|
-
Requires-Dist: photutils
|
|
28
|
+
Requires-Dist: photutils<3,>=1.7
|
|
29
29
|
Requires-Dist: pytz
|
|
30
30
|
Requires-Dist: pyyaml
|
|
31
31
|
Requires-Dist: astroscrappy
|
|
@@ -40,7 +40,9 @@ Requires-Dist: pytest-astropy; extra == "test"
|
|
|
40
40
|
Requires-Dist: pytest-remotedata; extra == "test"
|
|
41
41
|
Requires-Dist: testfixtures; extra == "test"
|
|
42
42
|
Requires-Dist: pytest-rerunfailures; extra == "test"
|
|
43
|
+
Requires-Dist: vcrpy>=7; extra == "test"
|
|
43
44
|
Provides-Extra: docs
|
|
45
|
+
Requires-Dist: matplotlib; extra == "docs"
|
|
44
46
|
Requires-Dist: ipython; extra == "docs"
|
|
45
47
|
Requires-Dist: ipykernel; extra == "docs"
|
|
46
48
|
Requires-Dist: sphinx; extra == "docs"
|
|
@@ -76,9 +76,13 @@ def astroquery_skycoord(center, simbad=None):
|
|
|
76
76
|
if simbad is None:
|
|
77
77
|
simbad = Simbad()
|
|
78
78
|
t = simbad.query_object(center)
|
|
79
|
-
if t is None:
|
|
79
|
+
if t is None or len(t) == 0:
|
|
80
80
|
raise ValueError(f'Coordinates {center} could not be'
|
|
81
81
|
' resolved.')
|
|
82
|
+
# The TAP interface (Astroquery >= 0.4.8) returns degrees
|
|
83
|
+
# under lowercase names; the legacy interface used sexagesimal.
|
|
84
|
+
if 'ra' in t.colnames and 'dec' in t.colnames:
|
|
85
|
+
return SkyCoord(t['ra'][0], t['dec'][0], unit='deg')
|
|
82
86
|
return guess_coordinates(t['RA'][0], t['DEC'][0], skycoord=True)
|
|
83
87
|
if isinstance(center, (tuple, list, np.ndarray)) and len(center) == 2:
|
|
84
88
|
return guess_coordinates(center[0], center[1], skycoord=True)
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
"""Query and match objects in catalogs using TAP services."""
|
|
3
3
|
|
|
4
4
|
import copy
|
|
5
|
+
import time
|
|
6
|
+
from contextlib import contextmanager
|
|
5
7
|
import numpy as np
|
|
6
8
|
from astropy.coordinates import SkyCoord
|
|
7
9
|
from astropy import units as u
|
|
8
10
|
from astroquery.gaia import Gaia
|
|
9
11
|
from astropy.time import Time
|
|
12
|
+
from astropy.table import vstack
|
|
10
13
|
|
|
11
14
|
from ._sources_catalog import _OnlineSourcesCatalog, SourcesCatalog
|
|
12
15
|
from ._online_tools import astroquery_query, string_fix
|
|
@@ -16,6 +19,45 @@ from ..math import QFloat
|
|
|
16
19
|
__all__ = ['GaiaDR3SourcesCatalog', 'gaiadr3']
|
|
17
20
|
|
|
18
21
|
|
|
22
|
+
@contextmanager
|
|
23
|
+
def _gaia_query_timeout(client, timeout=300):
|
|
24
|
+
"""Limit socket waits using one budget for the whole Gaia query.
|
|
25
|
+
|
|
26
|
+
The deadline is checked when a connection is created; its remaining time
|
|
27
|
+
becomes that socket's inactivity timeout. This is not a hard wall-clock
|
|
28
|
+
limit on DNS resolution, a continuously streaming response, or parsing.
|
|
29
|
+
"""
|
|
30
|
+
# Gaia can accept an async job but leave it in EXECUTING for minutes, even
|
|
31
|
+
# for a tiny result. A successful availability request does not rule this
|
|
32
|
+
# out. Astroquery polls the job without an overall deadline, and its TAP
|
|
33
|
+
# sockets have no explicit timeout, so even a status read can hang.
|
|
34
|
+
#
|
|
35
|
+
# The TAP client has no public timeout setter. Adapt the connection factory
|
|
36
|
+
# only on this catalog's deepcopy of Gaia, preserving the configured host
|
|
37
|
+
# and avoiding process-wide socket changes. Restore it on success or error.
|
|
38
|
+
handler = client._TapPlus__getconnhandler()._TapConn__connectionHandler
|
|
39
|
+
original = handler.get_connection
|
|
40
|
+
deadline = time.monotonic() + timeout
|
|
41
|
+
connections = []
|
|
42
|
+
|
|
43
|
+
def get_connection(*args, **kwargs):
|
|
44
|
+
remaining = deadline - time.monotonic()
|
|
45
|
+
if remaining <= 0:
|
|
46
|
+
raise TimeoutError('Gaia query timed out.')
|
|
47
|
+
connection = original(*args, **kwargs)
|
|
48
|
+
connection.timeout = remaining
|
|
49
|
+
connections.append(connection)
|
|
50
|
+
return connection
|
|
51
|
+
|
|
52
|
+
handler.get_connection = get_connection
|
|
53
|
+
try:
|
|
54
|
+
yield
|
|
55
|
+
finally:
|
|
56
|
+
handler.get_connection = original
|
|
57
|
+
for connection in connections:
|
|
58
|
+
connection.close()
|
|
59
|
+
|
|
60
|
+
|
|
19
61
|
class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
20
62
|
"""Sources catalog from Gaia-DR3 catalog.
|
|
21
63
|
|
|
@@ -43,10 +85,16 @@ class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
|
43
85
|
Maximum G-band magnitude to query. If None, no magnitude
|
|
44
86
|
filtering will be performed. Default is None.
|
|
45
87
|
|
|
88
|
+
query_mode: {'async', 'sync'} (optional)
|
|
89
|
+
Use asynchronous jobs (default) or synchronous requests. Synchronous
|
|
90
|
+
queries fetch pages of at most 2000 sources and return the complete
|
|
91
|
+
result sorted by distance, without creating asynchronous jobs.
|
|
92
|
+
|
|
46
93
|
Raises
|
|
47
94
|
------
|
|
48
95
|
ValueError:
|
|
49
|
-
If a ``band`` not available in the filters is passed
|
|
96
|
+
If a ``band`` not available in the filters is passed, or
|
|
97
|
+
``query_mode`` is not ``'async'`` or ``'sync'``.
|
|
50
98
|
"""
|
|
51
99
|
|
|
52
100
|
_available_filters = ['G', 'BP', 'RP']
|
|
@@ -58,7 +106,11 @@ class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
|
58
106
|
'phot_variable_flag', 'non_single_star',
|
|
59
107
|
'in_galaxy_candidates']
|
|
60
108
|
|
|
61
|
-
def __init__(self, center, radius, band='all', max_g_mag=None
|
|
109
|
+
def __init__(self, center, radius, band='all', max_g_mag=None, *,
|
|
110
|
+
query_mode='async'):
|
|
111
|
+
if query_mode not in ('async', 'sync'):
|
|
112
|
+
raise ValueError("query_mode must be 'async' or 'sync'.")
|
|
113
|
+
self._query_mode = query_mode
|
|
62
114
|
self._setup_catalog()
|
|
63
115
|
self._max_g_mag = max_g_mag
|
|
64
116
|
_OnlineSourcesCatalog.__init__(self, center, radius=radius, band=band)
|
|
@@ -103,10 +155,24 @@ class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
|
103
155
|
mag_err = 1.1/np.array(query[f'phot_{f}_mean_flux_over_error'])
|
|
104
156
|
return QFloat(mag, mag_err, unit='mag')
|
|
105
157
|
|
|
106
|
-
def
|
|
107
|
-
"""
|
|
108
|
-
# Based on astroquery.gaia.Gaia.query_object_async
|
|
158
|
+
def _query_object(self, center, radius=None, columns=None):
|
|
159
|
+
"""Query a cone using the selected TAP mode and sort by distance."""
|
|
160
|
+
# Based on astroquery.gaia.Gaia.query_object_async. Sync mode bypasses
|
|
161
|
+
# async job execution/polling, which was slow even when the same SQL
|
|
162
|
+
# completed promptly through /sync. It can still suffer network or
|
|
163
|
+
# server timeouts; it is an alternative path, not a timeout guarantee.
|
|
164
|
+
sync = self._query_mode == 'sync'
|
|
165
|
+
# Astroquery's synchronous launcher limits results to 2000 rows, even
|
|
166
|
+
# with Gaia.ROW_LIMIT = -1. Page by unique source_id to avoid truncation.
|
|
167
|
+
# Distance is not a safe cursor because multiple sources can tie.
|
|
168
|
+
# Keep IDs as integers (Gaia IDs exceed float's exact-integer range),
|
|
169
|
+
# and remove this extra column unless the caller requested it.
|
|
170
|
+
include_id = sync and 'source_id' not in columns
|
|
109
171
|
columns = ','.join(map(str, columns))
|
|
172
|
+
if include_id:
|
|
173
|
+
columns += ',source_id'
|
|
174
|
+
row_limit = 'TOP 2000' if sync else ''
|
|
175
|
+
order = 'source_id ASC' if sync else 'dist ASC'
|
|
110
176
|
|
|
111
177
|
ra = center.ra.degree
|
|
112
178
|
dec = center.dec.degree
|
|
@@ -117,7 +183,7 @@ class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
|
117
183
|
mag_filtering = ''
|
|
118
184
|
|
|
119
185
|
query = f"""
|
|
120
|
-
SELECT
|
|
186
|
+
SELECT {row_limit}
|
|
121
187
|
{columns},
|
|
122
188
|
DISTANCE(
|
|
123
189
|
POINT('ICRS', {self._g.MAIN_GAIA_TABLE_RA},
|
|
@@ -132,18 +198,51 @@ class GaiaDR3SourcesCatalog(_OnlineSourcesCatalog):
|
|
|
132
198
|
CIRCLE('ICRS', {ra}, {dec}, {radius})
|
|
133
199
|
)
|
|
134
200
|
{mag_filtering}
|
|
201
|
+
{{page_filter}}
|
|
135
202
|
ORDER BY
|
|
136
|
-
|
|
203
|
+
{order}
|
|
137
204
|
"""
|
|
138
205
|
|
|
139
|
-
|
|
140
|
-
|
|
206
|
+
if not sync:
|
|
207
|
+
return self._g.launch_job_async(query.format(page_filter=''),
|
|
208
|
+
dump_to_file=False).get_results()
|
|
209
|
+
|
|
210
|
+
pages = []
|
|
211
|
+
last_id = None
|
|
212
|
+
while True:
|
|
213
|
+
page_filter = ('' if last_id is None else
|
|
214
|
+
f'AND source_id > {last_id}')
|
|
215
|
+
page = self._g.launch_job(query.format(page_filter=page_filter),
|
|
216
|
+
dump_to_file=False).get_results()
|
|
217
|
+
if page is None:
|
|
218
|
+
raise RuntimeError('No online catalog result found.')
|
|
219
|
+
if len(page):
|
|
220
|
+
next_id = int(page['source_id'][-1])
|
|
221
|
+
if last_id is not None and next_id <= last_id:
|
|
222
|
+
raise RuntimeError('Gaia synchronous pagination stalled.')
|
|
223
|
+
last_id = next_id
|
|
224
|
+
pages.append(page)
|
|
225
|
+
# A full page does not prove that the result is complete. An exact
|
|
226
|
+
# multiple of 2000 therefore needs one final, empty request.
|
|
227
|
+
if len(page) < 2000:
|
|
228
|
+
break
|
|
229
|
+
result = vstack(pages, join_type='exact') if len(pages) > 1 else pages[0]
|
|
230
|
+
# Page order is by ID; the catalog API promises angular-distance order.
|
|
231
|
+
result.sort('dist')
|
|
232
|
+
if include_id:
|
|
233
|
+
result.remove_column('source_id')
|
|
234
|
+
return result
|
|
141
235
|
|
|
142
236
|
def _do_query(self):
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
237
|
+
# Keep the deadline outside astroquery_query: its timeout retries must
|
|
238
|
+
# not each get a fresh five-minute budget. In sync mode this same budget
|
|
239
|
+
# covers every page. An exception propagates instead of exposing a
|
|
240
|
+
# partial catalog or silently switching back to the slow async path.
|
|
241
|
+
with _gaia_query_timeout(self._g):
|
|
242
|
+
self._query = astroquery_query(self._query_object,
|
|
243
|
+
self._center,
|
|
244
|
+
radius=self._radius.to(u.deg).value,
|
|
245
|
+
columns=self._columns)
|
|
147
246
|
sk = SkyCoord(self._query['ra'], self._query['dec'],
|
|
148
247
|
obstime=Time(self._query['ref_epoch'], format='jyear'),
|
|
149
248
|
pm_ra_cosdec=self._query['pmra'],
|