antares-devkit 0.4.0__tar.gz → 0.5.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.
Files changed (62) hide show
  1. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/PKG-INFO +2 -1
  2. antares_devkit-0.5.0/antares_devkit/filters/rubin_NovTest_soraisam/__init__.py +187 -0
  3. antares_devkit-0.5.0/antares_devkit/filters/young_rubin_transients_soraisam/__init__.py +145 -0
  4. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/utils.py +2 -0
  5. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/pyproject.toml +2 -1
  6. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/LICENSE.txt +0 -0
  7. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/README.md +0 -0
  8. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/__init__.py +0 -0
  9. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/bad_detection/__init__.py +0 -0
  10. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/bad_seeing/__init__.py +0 -0
  11. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/crash_filter/__init__.py +0 -0
  12. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/desi_target/__init__.py +0 -0
  13. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/dwarf_nova_outburst/__init__.py +0 -0
  14. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/ecl_transient_1/__init__.py +0 -0
  15. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/ecl_transient_2/__init__.py +0 -0
  16. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/extragalactic/__init__.py +0 -0
  17. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/highamp/__init__.py +0 -0
  18. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/highfluxchange/__init__.py +0 -0
  19. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/highsnr/__init__.py +0 -0
  20. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/if_anomaly_detection/__init__.py +0 -0
  21. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/if_anomaly_detection/data/__init__.py +0 -0
  22. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/if_anomaly_detection/data/paleo2_106IFmodel_472727objs_nest=1000_cont=0.001_transf.pkl +0 -0
  23. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/imbh/__init__.py +0 -0
  24. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/inm31/__init__.py +0 -0
  25. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/laiss_rfc_ad_filter/__init__.py +0 -0
  26. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/laiss_rfc_ad_filter/data/__init__.py +0 -0
  27. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/laiss_rfc_ad_filter/data/cls=binary_n_estimators=100_max_depth=35_rs=11_max_feats=35_cw=balanced.pkl +0 -0
  28. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/malanchev_anomaly_transient_dmdt/__init__.py +0 -0
  29. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/malanchev_anomaly_transient_dmdt/data/__init__.py +0 -0
  30. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/malanchev_anomaly_transient_dmdt/data/malanchev_ssiforest_v1.pickle +0 -0
  31. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/malanchev_features_v1/__init__.py +0 -0
  32. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/novtest/__init__.py +0 -0
  33. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/nuclear_transient/__init__.py +0 -0
  34. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/nuttela_tao/__init__.py +0 -0
  35. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/persistent_dimmers/__init__.py +0 -0
  36. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/random_tagger_filter/__init__.py +0 -0
  37. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/recent_reddening/__init__.py +0 -0
  38. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/refitt_newsources_snrcut/__init__.py +0 -0
  39. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/sample_filter/__init__.py +0 -0
  40. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/siena_mag_coord_cut/__init__.py +0 -0
  41. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/sso/__init__.py +0 -0
  42. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/sub_lum/__init__.py +0 -0
  43. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/superphot_plus_v1/__init__.py +0 -0
  44. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/superphot_plus_ztf_v3/__init__.py +0 -0
  45. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/test_dev_all/__init__.py +0 -0
  46. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/test_dev_lsst/__init__.py +0 -0
  47. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/test_dev_ztf/__init__.py +0 -0
  48. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/vpdf/__init__.py +0 -0
  49. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/vpdf/data/__init__.py +0 -0
  50. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/vpdf/data/matheson_percent_grid_v1 +0 -0
  51. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/filters/young_extragalactic_candidate/__init__.py +0 -0
  52. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/antares_devkit/models.py +0 -0
  53. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/Dockerfile +0 -0
  54. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/__init__.py +0 -0
  55. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/conftest.py +0 -0
  56. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/data/large_locus.py +0 -0
  57. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/data/small_locus.py +0 -0
  58. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/unit/antares_devkit/filters/test_test_dev_all.py +0 -0
  59. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/unit/antares_devkit/filters/test_test_dev_lsst.py +0 -0
  60. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/unit/antares_devkit/filters/test_test_dev_ztf.py +0 -0
  61. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/unit/antares_devkit/test_models.py +0 -0
  62. {antares_devkit-0.4.0 → antares_devkit-0.5.0}/test/unit/test_filters.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antares-devkit
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Provides tools and utility methods to write and debug ANTARES filters with Python.
5
5
  Keywords: antares,devkit,filter development
6
6
  Author-Email: NSF NOIRLab ANTARES Team <antares@noirlab.edu>
@@ -50,6 +50,7 @@ Requires-Dist: statsmodels>=0.12.2; extra == "filter-dependencies"
50
50
  Requires-Dist: scipy>=1.13.1; extra == "filter-dependencies"
51
51
  Requires-Dist: light-curve==0.7.2; extra == "filter-dependencies"
52
52
  Requires-Dist: ssi-forest>=0.1.1; extra == "filter-dependencies"
53
+ Requires-Dist: slack-sdk>=3.39.0; extra == "filter-dependencies"
53
54
  Provides-Extra: jupyter
54
55
  Requires-Dist: matplotlib>=3.9.4; extra == "jupyter"
55
56
  Description-Content-Type: text/markdown
@@ -0,0 +1,187 @@
1
+ ## v2
2
+ from antares_devkit.models import BaseFilter
3
+
4
+
5
+ class rubin_NovTest_soraisam(BaseFilter):
6
+ ## MS: this is mainly for the NOIRLab end-to-end demonstration
7
+
8
+ TRIGGERING_SURVEY = "lsst"
9
+
10
+ SLACK_CHANNEL = "#filter-rubin-novtest"
11
+
12
+ REQUIRED_LOCUS_PROPERTIES = []
13
+
14
+ ## bare absolute minimum alert properties proving it's good to go
15
+ REQUIRED_ALERT_PROPERTIES = [
16
+ "lsst_diaSource_reliability",
17
+ "lsst_diaSource_snr",
18
+ "lsst_diaSource_ssObjectId",
19
+ "lsst_diaSource_extendedness",
20
+ "lsst_diaSource_templateFlux",
21
+ "lsst_diaSource_templateFluxErr",
22
+ "lsst_diaSource_isNegative",
23
+ "ant_mjd",
24
+ "ant_mag",
25
+ "ant_passband",
26
+ ]
27
+
28
+
29
+ OUTPUT_LOCUS_TAGS = [
30
+ {
31
+ "name": "SN_candies",
32
+ "description": "Locus is a SN candidate in the Rubin alert stream.",
33
+ },
34
+ ]
35
+
36
+ # Slack post (going to tda-noao noirlab_e2e_demo channel)
37
+ def send_message_to_slack(self, msg):
38
+ from slack_sdk import WebClient
39
+ from slack_sdk.errors import SlackApiError
40
+ import os
41
+
42
+ slack_token = os.getenv("RUBIN_NOVTEST_SLACK_TOKEN", "")
43
+ channel_id = os.getenv("RUBIN_NOVTEST_SLACK_CHANNEL_ID", "")
44
+ if (not slack_token) or (not channel_id):
45
+ print ("Slack not set up")
46
+ return
47
+ client = WebClient(token=slack_token)
48
+
49
+ try:
50
+ response = client.chat_postMessage(
51
+ channel=channel_id,
52
+ text=msg
53
+ )
54
+ # print(f"Message sent successfully: {response['ts']}")
55
+ except SlackApiError as e:
56
+ print(f"Error sending message: {e.response['error']}")
57
+ pass
58
+
59
+ return
60
+
61
+
62
+
63
+
64
+ def _run(self, locus):
65
+ import numpy as np
66
+ from astropy.time import Time
67
+ from astropy.coordinates import SkyCoord
68
+ import astropy.units as U
69
+ from itertools import combinations
70
+
71
+
72
+ C1 = (locus.alert.properties['lsst_diaSource_reliability'] < 0.9) or (locus.alert.properties['lsst_diaSource_snr'] < 10.0)
73
+ if C1:
74
+ return
75
+
76
+ C2 = (locus.alert.properties['lsst_diaSource_ssObjectId'] != 0)
77
+ if C2:
78
+ return
79
+
80
+ ## extract info from recent alert
81
+ alert_id = locus.alert.alert_id
82
+ current = Time(locus.alert.properties['ant_mjd'], format="mjd")
83
+ current_mag = locus.alert.properties['ant_mag']
84
+ current_pb = locus.alert.properties['ant_passband']
85
+
86
+ # ## confirm locus is Not in legacy point source catalogs
87
+ astro_objects = locus.catalog_objects
88
+ if astro_objects and "2mass_psc" in astro_objects.keys():
89
+ return
90
+
91
+
92
+
93
+ TS_all = locus.timeseries('all')
94
+ TS_lsst = locus.timeseries('lsst')
95
+
96
+ ## want more than two measurements across all filters and time span less than 15 days (young)
97
+ C4 = (len(TS_all) > 2) and (max(TS_lsst["ant_mjd"].data) - min(TS_lsst["ant_mjd"].data) < 15.0)
98
+ if not C4:
99
+ return
100
+
101
+ ## want star like profile
102
+ try:
103
+ C5 = np.ma.median(TS_lsst['lsst_diaSource_extendedness'].data) > 0.3
104
+ if C5:
105
+ return
106
+ except: ## some alerts do not have extendedness apparently
107
+ print ("extendedness not in alert packet")
108
+ return
109
+
110
+
111
+ C6 = np.ma.median(np.abs(TS_lsst['lsst_diaSource_templateFlux'].data/TS_lsst['lsst_diaSource_templateFluxErr'].data))<1000.0
112
+ if not C6:
113
+ return
114
+
115
+ C7 = np.all(TS_lsst['lsst_diaSource_isNegative'].data==False)
116
+ if not C7:
117
+ return
118
+
119
+
120
+ rubin_pb = ['u','g','r','i','z']
121
+ x = TS_lsst["ant_mjd"].data
122
+ y = TS_lsst["ant_mag"].data
123
+ pb = TS_lsst["ant_passband"].data
124
+
125
+
126
+ def is_it_blue_color(p1, p2):
127
+ g_x_i = x[pb == p1]
128
+ g_y_i = y[pb == p1]
129
+ R_x_i = x[pb == p2]
130
+ R_y_i = y[pb == p2]
131
+
132
+ idx = np.argsort(g_x_i)
133
+ g_x = g_x_i[idx]
134
+ g_y = g_y_i[idx]
135
+ idx = np.argsort(R_x_i)
136
+ R_x = R_x_i[idx]
137
+ R_y = R_y_i[idx]
138
+
139
+ dt = []
140
+ dc = []
141
+ for a, b in zip(g_x, g_y):
142
+ dt_i = np.abs(a - R_x)
143
+ dc_i = b - R_y
144
+ if min(dt_i) <= 1.0:
145
+ dt.append(min(dt_i))
146
+ dc.append(dc_i[np.argmin(dt_i)])
147
+
148
+
149
+ if len(dc) > 1:
150
+ col_evol = np.argsort(
151
+ dc
152
+ )
153
+ ori_idx = np.arange(len(dc))
154
+ idx_diff = col_evol[::-1] - ori_idx
155
+ if np.sum(idx_diff == 0) >= 0.5 * len(dc):
156
+ return True
157
+
158
+ return False
159
+
160
+ C8 = False
161
+ for p1, p2 in combinations(rubin_pb, 2):
162
+ if np.sum(pb == p1) > 1 and np.sum(pb == p2) > 0:
163
+ if is_it_blue_color(p1, p2):
164
+ C8 = True
165
+ break
166
+ if not C8:
167
+ return
168
+
169
+
170
+
171
+ ant_id = locus.locus_id
172
+
173
+ ## for slack notification whether known to TNS
174
+ if astro_objects and "tns_public_objects" in astro_objects.keys():
175
+ known_to_tns = "in TNS"
176
+ else:
177
+ known_to_tns = "NOT in TNS"
178
+
179
+ coord = SkyCoord(locus.ra, locus.dec, unit=(U.deg, U.deg))
180
+ ra_str = f"{int(coord.ra.hms.h):02d}:{int(coord.ra.hms.m):02d}:{coord.ra.hms.s:05.2f}"
181
+ dec_str = f"{int(coord.dec.dms.d):02d}:{abs(int(coord.dec.dms.m)):02d}:{abs(coord.dec.dms.s):05.2f}"
182
+
183
+ locus.tag("SN_candies")
184
+
185
+ msg = f"Young SN candidate: triggering alert={alert_id} for locus <https://development.antares.noirlab.edu/loci/{ant_id}|{ant_id}> {known_to_tns}, RA={ra_str} DEC={dec_str}, {current_pb}_mag={current_mag:.2f}, #dets in LSST={len(TS_lsst)}, UTC={current.iso}"
186
+ self.send_message_to_slack(msg)
187
+
@@ -0,0 +1,145 @@
1
+ ## v1
2
+ from antares_devkit.models import BaseFilter
3
+
4
+
5
+ class young_rubin_transients_soraisam(BaseFilter):
6
+ ## MS: this is mainly for the NOIRLab end-to-end demonstration
7
+
8
+ TRIGGERING_SURVEY = "lsst"
9
+
10
+ SLACK_CHANNEL = "#filter-young-rubin-transients"
11
+
12
+ REQUIRED_LOCUS_PROPERTIES = []
13
+
14
+ ## bare absolute minimum alert properties proving it's good to go
15
+ REQUIRED_ALERT_PROPERTIES = [
16
+ "lsst_diaSource_reliability",
17
+ "lsst_diaSource_snr",
18
+ "lsst_diaSource_ssObjectId",
19
+ "lsst_diaSource_extendedness",
20
+ "lsst_diaSource_templateFlux",
21
+ "lsst_diaSource_templateFluxErr",
22
+ "lsst_diaSource_isNegative",
23
+ "ant_mjd",
24
+ "ant_mag",
25
+ "ant_passband",
26
+ ]
27
+
28
+
29
+ OUTPUT_LOCUS_TAGS = [
30
+ {
31
+ "name": "young_rubin_transients",
32
+ "description": "Locus is a young transient in the Rubin alert stream.",
33
+ },
34
+ ]
35
+
36
+ # Slack post (going to tda-noao noirlab_e2e_demo_2 channel)
37
+ def send_message_to_slack(self, msg):
38
+ from slack_sdk import WebClient
39
+ from slack_sdk.errors import SlackApiError
40
+ import os
41
+
42
+ slack_token = os.getenv("RUBIN_SORAISAM_SLACK_TOKEN", "")
43
+ channel_id = os.getenv("RUBIN_SORAISAM_SLACK_CHANNEL_ID", "")
44
+ if (not slack_token) or (not channel_id):
45
+ print ("Slack not set up")
46
+ return
47
+ client = WebClient(token=slack_token)
48
+
49
+ try:
50
+ response = client.chat_postMessage(
51
+ channel=channel_id,
52
+ text=msg
53
+ )
54
+ # print(f"Message sent successfully: {response['ts']}")
55
+ except SlackApiError as e:
56
+ print(f"Error sending message: {e.response['error']}")
57
+ pass
58
+
59
+ return
60
+
61
+
62
+
63
+
64
+ def _run(self, locus):
65
+ import numpy as np
66
+ from astropy.time import Time
67
+ from astropy.coordinates import SkyCoord
68
+ import astropy.units as U
69
+ from itertools import combinations
70
+
71
+
72
+ C1 = (locus.alert.properties['lsst_diaSource_reliability'] < 0.9) or (locus.alert.properties['lsst_diaSource_snr'] < 10.0)
73
+ if C1:
74
+ return
75
+
76
+ C2 = (locus.alert.properties['lsst_diaSource_ssObjectId'] != 0)
77
+ if C2:
78
+ return
79
+
80
+ ## extract info from recent alert
81
+ alert_id = locus.alert.alert_id
82
+ current = Time(locus.alert.properties['ant_mjd'], format="mjd")
83
+ current_mag = locus.alert.properties['ant_mag']
84
+ current_pb = locus.alert.properties['ant_passband']
85
+
86
+ # ## confirm locus is extragalactic
87
+ astro_objects = locus.catalog_objects
88
+ # matching_catalog_names = astro_objects.keys()
89
+ # # Below is a battle-tested set of extended source catalogs (Antares-based names)
90
+ # xsc_cats = [
91
+ # "2mass_xsc",
92
+ # "ned",
93
+ # "nyu_valueadded_gals",
94
+ # "sdss_gals",
95
+ # "veron_agn_qso",
96
+ # "RC3",
97
+ # ]
98
+ # C3 = set(matching_catalog_names) & set(xsc_cats)
99
+ # if not C3:
100
+ # # print ("No match with extragalactic catalog")
101
+ # return
102
+
103
+
104
+
105
+ TS_all = locus.timeseries('all')
106
+ TS_lsst = locus.timeseries('lsst')
107
+
108
+ C4 = (len(TS_all) > 2) and (max(TS_lsst["ant_mjd"].data) - min(TS_lsst["ant_mjd"].data) < 15.0)
109
+ if not C4:
110
+ return
111
+
112
+ try:
113
+ C5 = np.ma.median(TS_lsst['lsst_diaSource_extendedness'].data) > 0.3
114
+ if C5:
115
+ return
116
+ except: ## some alerts do not have extendedness apparently
117
+ print ("extendedness not in alert packet")
118
+ return
119
+
120
+
121
+ C6 = np.ma.median(np.abs(TS_lsst['lsst_diaSource_templateFlux'].data/TS_lsst['lsst_diaSource_templateFluxErr'].data))<1000.0
122
+ if not C6:
123
+ return
124
+
125
+ C7 = np.all(TS_lsst['lsst_diaSource_isNegative'].data==False)
126
+ if not C7:
127
+ return
128
+
129
+
130
+ ant_id = locus.locus_id
131
+
132
+ ## for slack notification whether known to TNS
133
+ if astro_objects and "tns_public_objects" in astro_objects.keys():
134
+ known_to_tns = "in TNS"
135
+ else:
136
+ known_to_tns = "NOT in TNS"
137
+
138
+ coord = SkyCoord(locus.ra, locus.dec, unit=(U.deg, U.deg))
139
+ ra_str = f"{int(coord.ra.hms.h):02d}:{int(coord.ra.hms.m):02d}:{coord.ra.hms.s:05.2f}"
140
+ dec_str = f"{int(coord.dec.dms.d):02d}:{abs(int(coord.dec.dms.m)):02d}:{abs(coord.dec.dms.s):05.2f}"
141
+
142
+ locus.tag("young_rubin_transients")
143
+
144
+ msg = f"Young extragalactic transient: triggering alert={alert_id} for locus <https://development.antares.noirlab.edu/loci/{ant_id}|{ant_id}> {known_to_tns}, RA={ra_str} DEC={dec_str}, {current_pb}_mag={current_mag:.2f}, #dets in LSST={len(TS_lsst)}, UTC={current.iso}"
145
+ self.send_message_to_slack(msg)
@@ -45,6 +45,8 @@ def get_filters_path():
45
45
  "TestDevZtf": "antares_devkit.filters.test_dev_ztf",
46
46
  "vpdf": "antares_devkit.filters.vpdf",
47
47
  "YoungExtragalacticCandidate": "antares_devkit.filters.young_extragalactic_candidate",
48
+ "rubin_NovTest_soraisam": "antares_devkit.filters.rubin_NovTest_soraisam",
49
+ "young_rubin_transients_soraisam": "antares_devkit.filters.young_rubin_transients_soraisam",
48
50
  }
49
51
 
50
52
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "antares-devkit"
9
- version = "0.4.0"
9
+ version = "0.5.0"
10
10
  description = "Provides tools and utility methods to write and debug ANTARES filters with Python."
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.9"
@@ -45,6 +45,7 @@ filter-dependencies = [
45
45
  "scipy>=1.13.1",
46
46
  "light-curve==0.7.2",
47
47
  "ssi-forest>=0.1.1",
48
+ "slack-sdk>=3.39.0",
48
49
  ]
49
50
  jupyter = [
50
51
  "matplotlib>=3.9.4",
File without changes