roman-snpit-snappl 0.16.0__tar.gz → 0.17.0__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.

Potentially problematic release.


This version of roman-snpit-snappl might be problematic. Click here for more details.

Files changed (132) hide show
  1. {roman_snpit_snappl-0.16.0/roman_snpit_snappl.egg-info → roman_snpit_snappl-0.17.0}/PKG-INFO +2 -2
  2. roman_snpit_snappl-0.17.0/changes/83.snappl.rst +1 -0
  3. roman_snpit_snappl-0.17.0/changes/85.feature.rst +2 -0
  4. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/webserver/Dockerfile +28 -0
  5. roman_snpit_snappl-0.17.0/docker/webserver/config-test.yaml +27 -0
  6. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/pyproject.toml +1 -1
  7. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0/roman_snpit_snappl.egg-info}/PKG-INFO +2 -2
  8. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/roman_snpit_snappl.egg-info/SOURCES.txt +3 -0
  9. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/roman_snpit_snappl.egg-info/requires.txt +1 -1
  10. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/_version.py +3 -3
  11. roman_snpit_snappl-0.17.0/snappl/admin/load_ou2024_l2images.py +141 -0
  12. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/config.py +204 -44
  13. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/baseview.py +1 -1
  14. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/db.py +45 -50
  15. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/migrations/20251008_init.sql +3 -2
  16. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/webserver.py +144 -8
  17. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/dbclient.py +8 -8
  18. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/diaobject.py +225 -128
  19. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/image.py +35 -2
  20. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/image_simulator.py +59 -0
  21. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/imagecollection.py +149 -9
  22. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/provenance.py +27 -4
  23. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/psf.py +3 -3
  24. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/sed.py +2 -2
  25. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/utils.py +18 -5
  26. roman_snpit_snappl-0.16.0/docker/webserver/config-test.yaml +0 -27
  27. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.cruft.json +0 -0
  28. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/CODEOWNERS +0 -0
  29. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +0 -0
  30. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md +0 -0
  31. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/ISSUE_TEMPLATE/PR_TEMPLATE.md +0 -0
  32. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/dependabot.yml +0 -0
  33. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/labeler.yml +0 -0
  34. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/workflows/changelog.yml +0 -0
  35. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/workflows/run_labeler.yml +0 -0
  36. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/workflows/run_snappl_tests.yml +0 -0
  37. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/workflows/sphinx-deploy.yml +0 -0
  38. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.github/workflows/sub_package_update.yml +0 -0
  39. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.gitignore +0 -0
  40. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/.pre-commit-config.yaml +0 -0
  41. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/CHANGES.rst +0 -0
  42. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/CITATION.cff +0 -0
  43. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/CODE_OF_CONDUCT.md +0 -0
  44. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/CONTRIBUTING.md +0 -0
  45. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/LICENSE +0 -0
  46. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/MANIFEST.in +0 -0
  47. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/README.rst +0 -0
  48. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/.gitkeep +0 -0
  49. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/10.snappl.rst +0 -0
  50. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/13.bugfix.rst +0 -0
  51. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/14.snappl.rst +0 -0
  52. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/15.feature.rst +0 -0
  53. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/16.feature.rst +0 -0
  54. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/18.feature.rst +0 -0
  55. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/20.bugfix.rst +0 -0
  56. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/23.snappl.rst +0 -0
  57. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/26.feature.rst +0 -0
  58. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/29.feature.rst +0 -0
  59. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/3.snappl.rst +0 -0
  60. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/31.feature.rst +0 -0
  61. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/35.snappl.rst +0 -0
  62. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/36.snappl.rst +0 -0
  63. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/37.snappl.rst +0 -0
  64. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/40.snappl.rst +0 -0
  65. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/41.snappl.rst +0 -0
  66. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/43.snappl.rst +0 -0
  67. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/47.feature.rst +0 -0
  68. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/49.docs.rst +0 -0
  69. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/5.snappl.rst +0 -0
  70. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/54.snappl.rst +0 -0
  71. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/57.snappl.rst +0 -0
  72. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/58.snappl.rst +0 -0
  73. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/61.bugfix.rst +0 -0
  74. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/62.snappl.rst +0 -0
  75. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/63.snappl.rst +0 -0
  76. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/65.bugfix.rst +0 -0
  77. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/68.feature.rst +0 -0
  78. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/72.snappl.rst +0 -0
  79. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/73.feature.rst +0 -0
  80. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/74.bugfix.rst +0 -0
  81. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/79.snappl.rst +0 -0
  82. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/8.snappl.rst +0 -0
  83. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/81.snappl.rst +0 -0
  84. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/82.snappl.rst +0 -0
  85. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/84.feature.rst +0 -0
  86. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/changes/9.snappl.rst +0 -0
  87. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/codespell-ignore.txt +0 -0
  88. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/postgres/Dockerfile +0 -0
  89. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/postgres/postgresql.conf +0 -0
  90. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/postgres/run_postgres.sh +0 -0
  91. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/webserver/cert.pem +0 -0
  92. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/webserver/key.pem +0 -0
  93. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docker/webserver/roman-snpit-server.py +0 -0
  94. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/Makefile +0 -0
  95. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/_static/logo_black_filled.png +0 -0
  96. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/api.rst +0 -0
  97. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/changes.rst +0 -0
  98. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/conf.py +0 -0
  99. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/index.rst +0 -0
  100. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/installation.rst +0 -0
  101. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/make.bat +0 -0
  102. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/docs/usage.rst +0 -0
  103. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/experimentation/README.md +0 -0
  104. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/experimentation/ap_phot_simulated_images.py +0 -0
  105. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/experimentation/play_with_photutils.py +0 -0
  106. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/licenses/.DS_Store +0 -0
  107. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/licenses/LICENSE.rst +0 -0
  108. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/licenses/README.rst +0 -0
  109. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/licenses/TEMPLATE_LICENSE.rst +0 -0
  110. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/roman_snpit_snappl.egg-info/dependency_links.txt +0 -0
  111. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/roman_snpit_snappl.egg-info/not-zip-safe +0 -0
  112. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/roman_snpit_snappl.egg-info/top_level.txt +0 -0
  113. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/setup.cfg +0 -0
  114. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/setup.py +0 -0
  115. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/__init__.py +0 -0
  116. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/_dev/__init__.py +0 -0
  117. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/_dev/scm_version.py +0 -0
  118. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/admin/load_snana_ou2024_diaobject.py +0 -0
  119. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/data/README.rst +0 -0
  120. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/migrations/apply_migrations.py +0 -0
  121. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/migrations/schema_to_rst.py +0 -0
  122. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/migrations/scorched_earth.py +0 -0
  123. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/migrations/wipe_all_data.py +0 -0
  124. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/static/romansnpit.css +0 -0
  125. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/static/romansnpit.js +0 -0
  126. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/static/romansnpit_start.js +0 -0
  127. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/templates/base.html +0 -0
  128. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/db/templates/romansnpitdb.html +0 -0
  129. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/http.py +0 -0
  130. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/logger.py +0 -0
  131. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/snappl/wcs.py +0 -0
  132. {roman_snpit_snappl-0.16.0 → roman_snpit_snappl-0.17.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roman_snpit_snappl
3
- Version: 0.16.0
3
+ Version: 0.17.0
4
4
  Summary: General, database, and photometry utilities for the Roman SNPIT
5
5
  Author: Roman Supernova Project Infrastructure Team
6
6
  Maintainer-email: Roman SN PIT <raknop@lbl.gov>
@@ -22,7 +22,7 @@ Requires-Dist: pycryptodome<4.0.0,>=3.23.0
22
22
  Requires-Dist: python-dateutil<3.0.0,>=2.9.0.post0
23
23
  Requires-Dist: pytz>=2025.2
24
24
  Requires-Dist: pyyaml<7.0.0,>=6.0.3
25
- Requires-Dist: rkwebutil<3.0.0,>=2.2.3
25
+ Requires-Dist: rkwebutil<3.0.0,>=2.4.0
26
26
  Requires-Dist: roman-datamodels<0.28.0,>=0.27.0
27
27
  Requires-Dist: scipy<2.0.0,>=1.16.2
28
28
  Requires-Dist: simplejson<4.0.0,>=3.20.2
@@ -0,0 +1 @@
1
+ Added extremely basic static source sim to snappl.
@@ -0,0 +1,2 @@
1
+ Add database connection to l2image, go back to using collection in
2
+ DiaObject, some other small changes.
@@ -58,6 +58,33 @@ RUN source /venv/bin/activate && \
58
58
  "pytest>=8.4.2,<9.0.0" \
59
59
  "remote-pdb==2.1.0"
60
60
 
61
+ # TEMPORARY
62
+ # This installs the preqreqs of snappl. Really, we should
63
+ # just let that be installed when we do pip install .
64
+ # below. However, during development, when editing
65
+ # the package a lot, it's faster to build the docker
66
+ # image if there's a previous step that already has the prereqs.
67
+ # In the mean time, KEEP THIS SYNCED WITH pyproject.toml
68
+ RUN source /venv/bin/activate && \
69
+ pip --no-cache install \
70
+ "astropy>=7.1.0,<8.0.0" \
71
+ "fitsio>=1.2.5,<2.0.0" \
72
+ "galsim>=2.7.2,<3.0.0" \
73
+ "gwcs>=0.26.0,<0.27.0" \
74
+ "h5py>=3.14.0,<4.0.0" \
75
+ "numpy>=2.2.6,<3.0.0" \
76
+ "pandas>=2.3.3,<3.0.0" \
77
+ "photutils>=2.3.0,<3.0.0" \
78
+ "pycryptodome>=3.23.0,<4.0.0" \
79
+ "python-dateutil>=2.9.0.post0,<3.0.0" \
80
+ "pytz>=2025.2" \
81
+ "pyyaml>=6.0.3,<7.0.0" \
82
+ "rkwebutil>=2.3.0,<3.0.0" \
83
+ "roman-datamodels>=0.27.0,<0.28.0" \
84
+ "scipy>=1.16.2,<2.0.0" \
85
+ "simplejson>=3.20.2,<4.0.0"
86
+ # END TEMPORARY
87
+
61
88
  RUN mkdir -p /usr/src/snappl_install
62
89
  WORKDIR /usr/src/snappl_install
63
90
  COPY . /usr/src/snappl_install
@@ -112,6 +139,7 @@ ENV PYTHONPATH=/roman-snpit-db
112
139
  RUN mkdir /sessions
113
140
 
114
141
  COPY docker/webserver/config-test.yaml /roman-snpit-db/
142
+ COPY docker/webserver/roman-snpit-server.py /roman-snpit-db/
115
143
 
116
144
  ENTRYPOINT [ "tail", "-f", "/etc/issue" ]
117
145
 
@@ -0,0 +1,27 @@
1
+ # This is the config file used for the tests.
2
+ # You should not use it for real. Ideally, you
3
+ # should have a config stored as a secret somewhere
4
+ # which you mount (say to /secrets/conifg.yaml),
5
+ # and then set the env var SNPIT_CONFIG to point
6
+ # to that config.
7
+
8
+ system:
9
+ webserver:
10
+ flask_secret_key: o6950bi77gvbc2jie49lklotwll69ayv
11
+ sessionstore: /sessions
12
+ emailfrom: nobody@nowhere.org
13
+ smtpserver: mailhog
14
+ smtpport: 1025
15
+ smtpusessl: False
16
+ smtpusername: NULL
17
+ smtppassword: NULL
18
+
19
+ db:
20
+ postgres_host: postgres
21
+ postgres_port: 5432
22
+ postgres_database: roman_snpit
23
+ postgres_username: postgres
24
+ postgres_password: fragile
25
+ # These next two are for debugging purposes and should always be false in production
26
+ echoqueries: true
27
+ alwaysexplain: false
@@ -36,7 +36,7 @@ dependencies = [
36
36
  "python-dateutil>=2.9.0.post0,<3.0.0",
37
37
  "pytz>=2025.2",
38
38
  "pyyaml>=6.0.3,<7.0.0",
39
- "rkwebutil>=2.2.3,<3.0.0",
39
+ "rkwebutil>=2.4.0,<3.0.0",
40
40
  "roman-datamodels>=0.27.0,<0.28.0",
41
41
  "scipy>=1.16.2,<2.0.0",
42
42
  "simplejson>=3.20.2,<4.0.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roman_snpit_snappl
3
- Version: 0.16.0
3
+ Version: 0.17.0
4
4
  Summary: General, database, and photometry utilities for the Roman SNPIT
5
5
  Author: Roman Supernova Project Infrastructure Team
6
6
  Maintainer-email: Roman SN PIT <raknop@lbl.gov>
@@ -22,7 +22,7 @@ Requires-Dist: pycryptodome<4.0.0,>=3.23.0
22
22
  Requires-Dist: python-dateutil<3.0.0,>=2.9.0.post0
23
23
  Requires-Dist: pytz>=2025.2
24
24
  Requires-Dist: pyyaml<7.0.0,>=6.0.3
25
- Requires-Dist: rkwebutil<3.0.0,>=2.2.3
25
+ Requires-Dist: rkwebutil<3.0.0,>=2.4.0
26
26
  Requires-Dist: roman-datamodels<0.28.0,>=0.27.0
27
27
  Requires-Dist: scipy<2.0.0,>=1.16.2
28
28
  Requires-Dist: simplejson<4.0.0,>=3.20.2
@@ -60,7 +60,9 @@ changes/79.snappl.rst
60
60
  changes/8.snappl.rst
61
61
  changes/81.snappl.rst
62
62
  changes/82.snappl.rst
63
+ changes/83.snappl.rst
63
64
  changes/84.feature.rst
65
+ changes/85.feature.rst
64
66
  changes/9.snappl.rst
65
67
  docker/postgres/Dockerfile
66
68
  docker/postgres/postgresql.conf
@@ -109,6 +111,7 @@ snappl/utils.py
109
111
  snappl/wcs.py
110
112
  snappl/_dev/__init__.py
111
113
  snappl/_dev/scm_version.py
114
+ snappl/admin/load_ou2024_l2images.py
112
115
  snappl/admin/load_snana_ou2024_diaobject.py
113
116
  snappl/data/README.rst
114
117
  snappl/db/baseview.py
@@ -10,7 +10,7 @@ pycryptodome<4.0.0,>=3.23.0
10
10
  python-dateutil<3.0.0,>=2.9.0.post0
11
11
  pytz>=2025.2
12
12
  pyyaml<7.0.0,>=6.0.3
13
- rkwebutil<3.0.0,>=2.2.3
13
+ rkwebutil<3.0.0,>=2.4.0
14
14
  roman-datamodels<0.28.0,>=0.27.0
15
15
  scipy<2.0.0,>=1.16.2
16
16
  simplejson<4.0.0,>=3.20.2
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.16.0'
32
- __version_tuple__ = version_tuple = (0, 16, 0)
31
+ __version__ = version = '0.17.0'
32
+ __version_tuple__ = version_tuple = (0, 17, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g9ae526c23'
34
+ __commit_id__ = commit_id = 'gde6e5cc0b'
@@ -0,0 +1,141 @@
1
+ import uuid
2
+ import pathlib
3
+ import multiprocessing
4
+ import functools
5
+
6
+ import psycopg
7
+
8
+ from snappl.image import OpenUniverse2024FITSImage
9
+ from snappl.logger import SNLogger
10
+ from snappl.utils import asUUID
11
+ from snappl.provenance import Provenance
12
+ import snappl.db.db
13
+
14
+
15
+ # python multiprocesing irritates me; it seems you can't
16
+ # send a class method as the function
17
+ def parse_fits_file( relpath, base_path=None, provid=None ):
18
+ base_path = pathlib.Path( base_path )
19
+ provid = asUUID( provid )
20
+ # import random
21
+ # import remote_pdb;
22
+ # remote_pdb.RemotePdb( '127.0.0.1', random.randint( 4000, 5000 ) ).set_trace()
23
+ image = OpenUniverse2024FITSImage( path=base_path / relpath )
24
+ header = image.get_fits_header()
25
+ wcs = image.get_wcs()
26
+
27
+ width = int( header['NAXIS2'] )
28
+ height = int( header['NAXIS1'] )
29
+ ra, dec = wcs.pixel_to_world( width / 2., height / 2. )
30
+ ra_corner_00, dec_corner_00 = wcs.pixel_to_world( 0., 0. )
31
+ ra_corner_10, dec_corner_10 = wcs.pixel_to_world( width-1, 0. )
32
+ ra_corner_01, dec_corner_01 = wcs.pixel_to_world( 0., height-1 )
33
+ ra_corner_11, dec_corner_11 = wcs.pixel_to_world( width-1, height-1 )
34
+ exptime = float( header['EXPTIME'] )
35
+
36
+ params = { 'id': uuid.uuid4(),
37
+ 'provenance_id': provid,
38
+ 'pointing': image.pointing,
39
+ 'sca': image.sca,
40
+ 'filter': image.band,
41
+ 'ra': ra,
42
+ 'dec': dec,
43
+ 'ra_corner_00': ra_corner_00,
44
+ 'ra_corner_01': ra_corner_01,
45
+ 'ra_corner_10': ra_corner_10,
46
+ 'ra_corner_11': ra_corner_11,
47
+ 'dec_corner_00': dec_corner_00,
48
+ 'dec_corner_01': dec_corner_01,
49
+ 'dec_corner_10': dec_corner_10,
50
+ 'dec_corner_11': dec_corner_11,
51
+ 'filepath': str( relpath ),
52
+ 'width': width,
53
+ 'height': height,
54
+ 'format': 1,
55
+ 'mjd_start': image.mjd,
56
+ 'exptime': exptime,
57
+ 'properties': psycopg.types.json.Jsonb( {} )
58
+ }
59
+ return params
60
+
61
+
62
+ class OU2024_L2image_loader:
63
+ def __init__( self, provid, base_path ):
64
+ self.provid = provid.id if isinstance( provid, Provenance ) else provid
65
+ self.base_path = pathlib.Path( base_path )
66
+ self.dbcon = None
67
+
68
+
69
+ def collect_ou2024_l2image_paths( self, relpath ):
70
+ subdirs = []
71
+ imagefiles = []
72
+
73
+ for fullpath in ( self.base_path / relpath ).iterdir():
74
+ fullpath = fullpath.resolve()
75
+ if fullpath.is_dir():
76
+ subdirs.append( fullpath.relative_to( self.base_path ) )
77
+ elif ( fullpath.name[-5:] == '.fits' ) or ( fullpath.name[-8:] == '.fits.gz' ):
78
+ imagefiles.append( fullpath.relative_to( self.base_path ) )
79
+
80
+ for subdir in subdirs:
81
+ imagefiles.extend( self.collect_ou2024_l2image_paths(subdir) )
82
+
83
+ return imagefiles
84
+
85
+
86
+ def save_to_db( self ):
87
+ if len( self.copydata ) > 0:
88
+ SNLogger.info( f"Loading {len(self.copydata)} images to database..." )
89
+ snappl.db.db.L2Image.bulk_insert_or_upsert( self.copydata, dbcon=self.dbcon )
90
+ self.totloaded += len( self.copydata )
91
+ self.copydata = []
92
+
93
+ def append_to_copydata( self, relpath ):
94
+ self.copydata.append( relpath )
95
+ if len(self.copydata) % self.loadevery == 0:
96
+ self.save_to_db()
97
+
98
+ def omg( self, e ):
99
+ self.errors.append( e )
100
+
101
+ def __call__( self, dbcon=None, loadevery=1000, nprocs=1 ):
102
+ toload = self.collect_ou2024_l2image_paths( '.' )
103
+ self.totloaded = 0
104
+ self.copydata = []
105
+ self.loadevery = loadevery
106
+ self.errors = []
107
+
108
+ SNLogger.info( f"Loading {len(toload)} files in {nprocs} processes...." )
109
+ do_parse_fits_file = functools.partial( parse_fits_file,
110
+ base_path=self.base_path,
111
+ provid=self.provid )
112
+
113
+ with snappl.db.db.DBCon( dbcon ) as self.dbcon:
114
+ if nprocs > 1:
115
+ with multiprocessing.Pool( nprocs ) as pool:
116
+ for path in toload:
117
+ pool.apply_async( do_parse_fits_file,
118
+ args=[ str(path) ],
119
+ callback=self.append_to_copydata,
120
+ error_callback=self.omg
121
+ )
122
+ pool.close()
123
+ pool.join()
124
+ if len( self.errors ) > 0:
125
+ nl = "\n"
126
+ SNLogger.error( f"Got errors loading FITS files:\n{nl.join(str(e) for e in self.errors)}" )
127
+ raise RuntimeError( "Massive failure." )
128
+
129
+ elif nprocs == 1:
130
+ for path in toload:
131
+ self.append_to_copydata( do_parse_fits_file( path ) )
132
+
133
+ else:
134
+ raise ValueError( "Dude, nprocs needs to be positive, not {nprocs}" )
135
+
136
+ # Get any residual ones that didn't pass the "send to db" threshold
137
+ self.save_to_db()
138
+
139
+ SNLogger.info( f"Loaded {self.totloaded} of {len(toload)} images to database." )
140
+
141
+ self.dbcon = None
@@ -16,6 +16,11 @@ class NoValue:
16
16
  pass
17
17
 
18
18
 
19
+ class NotFoundValue:
20
+ """Used internally by Config, ignore."""
21
+ pass
22
+
23
+
19
24
  class Config:
20
25
  """Interface for yaml config file.
21
26
 
@@ -349,7 +354,7 @@ class Config:
349
354
 
350
355
 
351
356
  @staticmethod
352
- def get( configfile=None, setdefault=None, static=True ):
357
+ def get( configfile=None, setdefault=None, static=True, clone=None ):
353
358
  """Returns a Config object.
354
359
 
355
360
  Parameters
@@ -396,6 +401,15 @@ class Config:
396
401
  modify the config. Call Config.get(static=False) to get a
397
402
  modifiable version of the default config.
398
403
 
404
+ clone : Config, default None
405
+ If given, return a clone of this Config object. The
406
+ returned object, if all is working properly, is a deep copy,
407
+ so it should be safe to mangle it. It's not possibe to set
408
+ a cloned config object as default, nor is the cloned object
409
+ ever set as a singleton, so setdefault and static are both
410
+ ignored and treated as False when making a clone.
411
+
412
+
399
413
  Returns
400
414
  -------
401
415
  Config object
@@ -418,6 +432,12 @@ class Config:
418
432
  default", then an exception will be raised.
419
433
 
420
434
  """
435
+
436
+ if clone is not None:
437
+ if configfile is not None:
438
+ raise ValueError( "Only specify one of clone or configfile." )
439
+ return Config( clone=clone, _ok_to_call=True )
440
+
421
441
  if configfile is None:
422
442
  if Config._default is not None:
423
443
  configfile = Config._default
@@ -540,6 +560,7 @@ class Config:
540
560
  SNLogger.exception( f'Exception trying to load config from {configfile}' )
541
561
  raise e
542
562
 
563
+
543
564
  def value( self, field, default=NoValue(), struct=None ):
544
565
  """Get a value from the config structure.
545
566
 
@@ -596,49 +617,8 @@ class Config:
596
617
 
597
618
  """
598
619
 
599
- if struct is None:
600
- struct = self._data
601
- fields, isleaf, curfield, ifield = self._fieldsep( field )
602
-
603
- if isinstance( struct, list ):
604
- if ifield is None:
605
- raise ValueError( f'Failed to parse {curfield} as an integer index' )
606
- if ifield >= len(struct):
607
- raise ValueError( f'{ifield} >= {len(struct)}, the length of the list' )
608
- if isleaf:
609
- return_value = struct[ifield]
610
- else:
611
- try:
612
- return_value = self.value( ".".join(fields[1:]), default, struct[ifield] )
613
- except Exception as e:
614
- if isinstance(default, NoValue):
615
- raise ValueError( f'Error getting list element {ifield}' ) from e
616
- else:
617
- return_value = default
618
- elif isinstance( struct, dict ):
619
- if curfield not in struct:
620
- if isinstance(default, NoValue):
621
- raise ValueError( f'Field {curfield} doesn\'t exist' )
622
- else:
623
- return_value = default
624
- elif isleaf:
625
- return_value = struct[curfield]
626
- else:
627
- try:
628
- return_value = self.value( ".".join(fields[1:]), default, struct[curfield] )
629
- except Exception as e:
630
- if isinstance(default, NoValue):
631
- raise ValueError( f'Error getting field {field} from {curfield}' ) from e
632
- else:
633
- return_value = default
634
- else:
635
- if not isleaf:
636
- raise ValueError( f'Tried to get field {field} of scalar {curfield}!' )
637
- return_value = struct
638
-
639
- if isinstance(return_value, (dict, list)):
640
- return_value = copy.deepcopy( return_value )
641
- return return_value
620
+ _, _, value = self._parent_key_and_value( field, parent=None, struct=struct, default=default )
621
+ return value
642
622
 
643
623
 
644
624
  def set_value( self, field, value, structpass=None, appendlists=False ):
@@ -736,6 +716,97 @@ class Config:
736
716
  structpass.struct = [ structchuck.struct ]
737
717
 
738
718
 
719
+ def _parent_key_and_value( self, field, parent=None, struct=None, fullfield=None, default=NoValue ):
720
+ fullfield = fullfield if fullfield is not None else field
721
+ if struct is None:
722
+ struct = self._data
723
+ fields, isleaf, curfield, ifield = self._fieldsep( field )
724
+
725
+ if isinstance( struct, list ):
726
+ if ifield is None:
727
+ raise ValueError( f'Failed to parse {curfield} of {fullfield} as an integer index' )
728
+ elif ifield < 0:
729
+ if isinstance( default, NoValue ):
730
+ raise ValueError( f'Array index {ifield} is negative for {fullfield}' )
731
+ else:
732
+ return_parent = struct
733
+ return_key = ifield
734
+ return_value = default
735
+ elif ifield >= len(struct):
736
+ if isinstance( default, NoValue ):
737
+ raise ValueError( f'{ifield} >= {len(struct)}, the length of the list for {fullfield}' )
738
+ else:
739
+ return_parent = struct
740
+ return_key = ifield
741
+ return_value = default
742
+ elif isleaf:
743
+ return_parent = struct
744
+ return_key = ifield
745
+ return_value = struct[ifield]
746
+ else:
747
+ return_parent, return_key, return_value = self._parent_key_and_value( ".".join(fields[1:]),
748
+ parent=struct,
749
+ struct=struct[ifield],
750
+ fullfield=fullfield,
751
+ default=default )
752
+
753
+ elif isinstance( struct, dict ):
754
+ if curfield not in struct:
755
+ if isinstance( default, NoValue ):
756
+ raise ValueError( f"Can't find field {fullfield}" )
757
+ else:
758
+ return_parent = struct
759
+ return_key = curfield
760
+ return_value = default
761
+ elif isleaf:
762
+ return_parent = struct
763
+ return_key = curfield
764
+ return_value = struct[curfield]
765
+ else:
766
+ return_parent, return_key, return_value = self._parent_key_and_value( ".".join(fields[1:]),
767
+ parent=struct,
768
+ struct=struct[curfield],
769
+ fullfield=fullfield,
770
+ default=default )
771
+
772
+ else:
773
+ if not isleaf:
774
+ raise ValueError( f'Tried to get field {field} of scalar {curfield} in {fullfield}!' )
775
+ return_parent = parent
776
+ return_key = curfield
777
+ return_value = struct
778
+
779
+ if isinstance(return_value, (dict, list)):
780
+ return_value = copy.deepcopy( return_value )
781
+
782
+ return return_parent, return_key, return_value
783
+
784
+
785
+ def delete_field( self, field, missing_ok=False ):
786
+ """Remove a field from the config.
787
+
788
+ Use this this with great care.
789
+
790
+ """
791
+ if self._static:
792
+ raise RuntimeError( "Not permitted to modify static Config object." )
793
+
794
+ parent, key, value = self._parent_key_and_value( field, default=NotFoundValue() )
795
+ if isinstance( value, NotFoundValue ):
796
+ if missing_ok:
797
+ return
798
+ else:
799
+ raise ValueError( f"Can't find config field {field} to delete it." )
800
+
801
+ if isinstance( parent, list ):
802
+ parent.pop( key )
803
+ elif isinstance( parent, dict ):
804
+ del parent[key]
805
+ else:
806
+ # ... I think this shouldn't ever actually happen
807
+ raise RuntimeError( "Rob, figure out how to cope with this." )
808
+
809
+
739
810
  @classmethod
740
811
  def _fieldsep( cls, field ):
741
812
  """Parses a period-separated config specifier string. Internal use only.
@@ -764,6 +835,33 @@ class Config:
764
835
  return fields, isleaf, curfield, ifield
765
836
 
766
837
 
838
+ @classmethod
839
+ def _is_parent_field( cls, parent, child ):
840
+ parent = parent.split( "." )
841
+ child = child.split( "." )
842
+ if len(parent) >= len(child):
843
+ return False
844
+ return child[ 0 : len(parent) ] == parent
845
+
846
+
847
+ @classmethod
848
+ def _allkeys( cls, struct, base="" ):
849
+ keys = []
850
+
851
+ if isinstance( struct, dict ):
852
+ for key, val in struct.items():
853
+ keys.append( f"{base}{key}" )
854
+ keys.extend( cls._allkeys( val, base=f'{base}{key}.' ) )
855
+ elif isinstance( struct, list ):
856
+ for i, val in enumerate( struct ):
857
+ keys.append( f"{base}{i}" )
858
+ keys.extend( cls._allkeys( val, base=f'{base}{i}.' ) )
859
+ else:
860
+ return []
861
+
862
+ return keys
863
+
864
+
767
865
  def _pathify( self, fname ):
768
866
  fname = pathlib.Path( fname )
769
867
  if fname.is_absolute():
@@ -888,5 +986,67 @@ class Config:
888
986
  _dict[key] = getattr( args, arg )
889
987
 
890
988
 
989
+ def dump_to_dict_for_params( self, omitkeys=['system'], keepkeys=None ):
990
+ """Dump the config to a dictionary suitable for use in a Provenance params field.
991
+
992
+ Specify one of omitkeys or keepkeys.
993
+
994
+ Parameters
995
+ ----------
996
+ omitkeys: None, or list of str
997
+ This is a list of keys to delete from the config before
998
+ exporting it. (The internal state of the config will not be
999
+ affected, only what is exported.) Be careful not to list a
1000
+ subkey of a key that's already earlier in the list, or
1001
+ you'll get errors.
1002
+
1003
+ By default, the top-level key "system" is deleted, as per
1004
+ the Roman SNPIT standard that this holds all of the (but
1005
+ only the) system-specific config needed to run at a
1006
+ particular place. (system should not include anything that
1007
+ changes the behavior of the code.)
1008
+
1009
+ However, this default is a bit profligate, as it will keep
1010
+ all of the config options for all codes, not just the code
1011
+ you're running right now. Use with thought.
1012
+
1013
+ keepkeys: None, or list of str
1014
+ This is a list of keeps to keep in the export. Currently,
1015
+ only top-level keys are supported.
1016
+
1017
+ Returns
1018
+ -------
1019
+ dict
1020
+ This is a deep copy of the internal dictionary, so ideally
1021
+ you should be able to do anything you want to it without
1022
+ screwing up the internal config state.
1023
+
1024
+ """
1025
+
1026
+ if ( omitkeys is not None ) and ( keepkeys is not None ):
1027
+ raise ValueError( "Only specify one of omitkeys or keepkeys." )
1028
+
1029
+ cfg = Config.get( clone=self )
1030
+
1031
+ if omitkeys is not None:
1032
+ for kw in omitkeys:
1033
+ cfg.delete_field( kw )
1034
+
1035
+ elif keepkeys is not None:
1036
+ allkeys = Config._allkeys( cfg._data )
1037
+ allkeys.reverse()
1038
+ for kw in allkeys:
1039
+ if not ( ( kw in keepkeys )
1040
+ or any( [ Config._is_parent_field( i, kw ) for i in keepkeys ] )
1041
+ or any( [ Config._is_parent_field( kw, i ) for i in keepkeys ] )
1042
+ ):
1043
+ cfg.delete_field( kw )
1044
+
1045
+ else:
1046
+ raise ValueError( "Must specify either omitkeys or keepkeys." )
1047
+
1048
+ return cfg._data
1049
+
1050
+
891
1051
  if __name__ == "__main__":
892
1052
  Config.init()
@@ -71,7 +71,7 @@ class BaseView( flask.views.View ):
71
71
  # writes out NaN which is not standard JSON and which
72
72
  # the javascript JSON parser chokes on. Sigh.
73
73
  if isinstance( retval, dict ) or isinstance( retval, list ):
74
- SNLogger.warning( f"Dumping to json: {retval}" )
74
+ # SNLogger.warning( f"Dumping to json: {retval}" )
75
75
  return ( simplejson.dumps( retval, ignore_nan=True, cls=SNPITJsonEncoder ),
76
76
  200, { 'Content-Type': 'application/json' } )
77
77
  elif isinstance( retval, str ):