astro-otter 0.0.1__tar.gz → 0.0.2__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 astro-otter might be problematic. Click here for more details.

Files changed (26) hide show
  1. {astro_otter-0.0.1/src/astro_otter.egg-info → astro_otter-0.0.2}/PKG-INFO +13 -4
  2. {astro_otter-0.0.1 → astro_otter-0.0.2}/README.md +5 -3
  3. {astro_otter-0.0.1 → astro_otter-0.0.2}/pyproject.toml +11 -2
  4. {astro_otter-0.0.1 → astro_otter-0.0.2/src/astro_otter.egg-info}/PKG-INFO +13 -4
  5. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/astro_otter.egg-info/SOURCES.txt +4 -1
  6. astro_otter-0.0.2/src/astro_otter.egg-info/requires.txt +17 -0
  7. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/__init__.py +2 -0
  8. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/_version.py +1 -1
  9. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/exceptions.py +19 -0
  10. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/io/otter.py +71 -53
  11. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/io/transient.py +60 -11
  12. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/plotter/otter_plotter.py +10 -8
  13. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/plotter/plotter.py +19 -18
  14. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/util.py +60 -1
  15. astro_otter-0.0.2/tests/test_exceptions.py +33 -0
  16. astro_otter-0.0.2/tests/test_otter.py +227 -0
  17. {astro_otter-0.0.1 → astro_otter-0.0.2}/tests/test_transient.py +168 -1
  18. astro_otter-0.0.2/tests/test_util.py +44 -0
  19. astro_otter-0.0.1/src/astro_otter.egg-info/requires.txt +0 -10
  20. {astro_otter-0.0.1 → astro_otter-0.0.2}/LICENSE +0 -0
  21. {astro_otter-0.0.1 → astro_otter-0.0.2}/setup.cfg +0 -0
  22. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/astro_otter.egg-info/dependency_links.txt +0 -0
  23. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/astro_otter.egg-info/top_level.txt +0 -0
  24. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/io/__init__.py +0 -0
  25. {astro_otter-0.0.1 → astro_otter-0.0.2}/src/otter/plotter/__init__.py +0 -0
  26. {astro_otter-0.0.1 → astro_otter-0.0.2}/tests/test_package.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: astro-otter
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Author-email: Noah Franz <nfranz@arizona.edu>
5
5
  License: MIT License
6
6
 
@@ -50,6 +50,13 @@ Requires-Dist: synphot
50
50
  Requires-Dist: ads
51
51
  Requires-Dist: ruff
52
52
  Requires-Dist: pre-commit
53
+ Requires-Dist: Sphinx>=3.0.0
54
+ Requires-Dist: myst_parser>=0.13
55
+ Requires-Dist: nbsphinx>=0.9.1
56
+ Requires-Dist: sphinx-book-theme>=0.0.33
57
+ Requires-Dist: sphinx_copybutton
58
+ Requires-Dist: autodoc
59
+ Requires-Dist: ipykernel
53
60
 
54
61
  # OTTER API
55
62
  ### **O**pen mul**T**iwavelength **T**ransient **E**vent **R**epository
@@ -66,9 +73,9 @@ A Python API for the OTTER.
66
73
  [github-discussions-link]: https://github.com/mattbellis/hepfile/discussions
67
74
  [gitter-badge]: https://badges.gitter.im/https://github.com/mattbellis/hepfile/community.svg
68
75
  [gitter-link]: https://gitter.im/https://github.com/mattbellis/hepfile/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
69
- [pypi-link]: https://pypi.org/project/hepfile/
70
- [pypi-platforms]: https://img.shields.io/pypi/pyversions/hepfile
71
- [pypi-version]: https://badge.fury.io/py/hepfile.svg
76
+ [pypi-link]: https://pypi.org/project/astro-otter/
77
+ [pypi-platforms]: https://img.shields.io/pypi/pyversions/astro-otter
78
+ [pypi-version]: https://badge.fury.io/py/astro-otter.svg
72
79
  [rtd-badge]: https://readthedocs.org/projects/otter/badge/?version=latest
73
80
  [rtd-link]: https://otter.readthedocs.io/en/latest/?badge=latest
74
81
  [sk-badge]: https://scikit-hep.org/assets/images/Scikit--HEP-Project-blue.svg
@@ -77,7 +84,9 @@ A Python API for the OTTER.
77
84
  [codecov-badge]: https://codecov.io/gh/astro-otter/otter/graph/badge.svg?token=BtCerOdTc0
78
85
  [codecov-link]: https://codecov.io/gh/astro-otter/otter
79
86
 
87
+ [![Documentation Status](https://readthedocs.org/projects/astro-otter/badge/?version=latest)](https://astro-otter.readthedocs.io/en/latest/?badge=latest)
80
88
  [![Actions Status][actions-badge]][actions-link]
89
+ [![PyPI version][pypi-version]][pypi-link]
81
90
  [![Linting: Ruff][ruff-badge]][ruff-link]
82
91
  [![codecov][codecov-badge]][codecov-link]
83
92
 
@@ -13,9 +13,9 @@ A Python API for the OTTER.
13
13
  [github-discussions-link]: https://github.com/mattbellis/hepfile/discussions
14
14
  [gitter-badge]: https://badges.gitter.im/https://github.com/mattbellis/hepfile/community.svg
15
15
  [gitter-link]: https://gitter.im/https://github.com/mattbellis/hepfile/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
16
- [pypi-link]: https://pypi.org/project/hepfile/
17
- [pypi-platforms]: https://img.shields.io/pypi/pyversions/hepfile
18
- [pypi-version]: https://badge.fury.io/py/hepfile.svg
16
+ [pypi-link]: https://pypi.org/project/astro-otter/
17
+ [pypi-platforms]: https://img.shields.io/pypi/pyversions/astro-otter
18
+ [pypi-version]: https://badge.fury.io/py/astro-otter.svg
19
19
  [rtd-badge]: https://readthedocs.org/projects/otter/badge/?version=latest
20
20
  [rtd-link]: https://otter.readthedocs.io/en/latest/?badge=latest
21
21
  [sk-badge]: https://scikit-hep.org/assets/images/Scikit--HEP-Project-blue.svg
@@ -24,7 +24,9 @@ A Python API for the OTTER.
24
24
  [codecov-badge]: https://codecov.io/gh/astro-otter/otter/graph/badge.svg?token=BtCerOdTc0
25
25
  [codecov-link]: https://codecov.io/gh/astro-otter/otter
26
26
 
27
+ [![Documentation Status](https://readthedocs.org/projects/astro-otter/badge/?version=latest)](https://astro-otter.readthedocs.io/en/latest/?badge=latest)
27
28
  [![Actions Status][actions-badge]][actions-link]
29
+ [![PyPI version][pypi-version]][pypi-link]
28
30
  [![Linting: Ruff][ruff-badge]][ruff-link]
29
31
  [![codecov][codecov-badge]][codecov-link]
30
32
 
@@ -39,8 +39,17 @@ dependencies = [
39
39
 
40
40
  # useful dev tools
41
41
  "ruff", # linter
42
- "pre-commit" # enable pre-commit hooks
43
- ]
42
+ "pre-commit", # enable pre-commit hooks
43
+
44
+ # tools for building the readthedocs page
45
+ "Sphinx>=3.0.0",
46
+ "myst_parser>=0.13",
47
+ "nbsphinx>=0.9.1",
48
+ "sphinx-book-theme>=0.0.33",
49
+ "sphinx_copybutton",
50
+ "autodoc",
51
+ "ipykernel"
52
+ ]
44
53
 
45
54
  [project.urls]
46
55
  Home = "https://github.com/astro-otter"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: astro-otter
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Author-email: Noah Franz <nfranz@arizona.edu>
5
5
  License: MIT License
6
6
 
@@ -50,6 +50,13 @@ Requires-Dist: synphot
50
50
  Requires-Dist: ads
51
51
  Requires-Dist: ruff
52
52
  Requires-Dist: pre-commit
53
+ Requires-Dist: Sphinx>=3.0.0
54
+ Requires-Dist: myst_parser>=0.13
55
+ Requires-Dist: nbsphinx>=0.9.1
56
+ Requires-Dist: sphinx-book-theme>=0.0.33
57
+ Requires-Dist: sphinx_copybutton
58
+ Requires-Dist: autodoc
59
+ Requires-Dist: ipykernel
53
60
 
54
61
  # OTTER API
55
62
  ### **O**pen mul**T**iwavelength **T**ransient **E**vent **R**epository
@@ -66,9 +73,9 @@ A Python API for the OTTER.
66
73
  [github-discussions-link]: https://github.com/mattbellis/hepfile/discussions
67
74
  [gitter-badge]: https://badges.gitter.im/https://github.com/mattbellis/hepfile/community.svg
68
75
  [gitter-link]: https://gitter.im/https://github.com/mattbellis/hepfile/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
69
- [pypi-link]: https://pypi.org/project/hepfile/
70
- [pypi-platforms]: https://img.shields.io/pypi/pyversions/hepfile
71
- [pypi-version]: https://badge.fury.io/py/hepfile.svg
76
+ [pypi-link]: https://pypi.org/project/astro-otter/
77
+ [pypi-platforms]: https://img.shields.io/pypi/pyversions/astro-otter
78
+ [pypi-version]: https://badge.fury.io/py/astro-otter.svg
72
79
  [rtd-badge]: https://readthedocs.org/projects/otter/badge/?version=latest
73
80
  [rtd-link]: https://otter.readthedocs.io/en/latest/?badge=latest
74
81
  [sk-badge]: https://scikit-hep.org/assets/images/Scikit--HEP-Project-blue.svg
@@ -77,7 +84,9 @@ A Python API for the OTTER.
77
84
  [codecov-badge]: https://codecov.io/gh/astro-otter/otter/graph/badge.svg?token=BtCerOdTc0
78
85
  [codecov-link]: https://codecov.io/gh/astro-otter/otter
79
86
 
87
+ [![Documentation Status](https://readthedocs.org/projects/astro-otter/badge/?version=latest)](https://astro-otter.readthedocs.io/en/latest/?badge=latest)
80
88
  [![Actions Status][actions-badge]][actions-link]
89
+ [![PyPI version][pypi-version]][pypi-link]
81
90
  [![Linting: Ruff][ruff-badge]][ruff-link]
82
91
  [![codecov][codecov-badge]][codecov-link]
83
92
 
@@ -16,5 +16,8 @@ src/otter/io/transient.py
16
16
  src/otter/plotter/__init__.py
17
17
  src/otter/plotter/otter_plotter.py
18
18
  src/otter/plotter/plotter.py
19
+ tests/test_exceptions.py
20
+ tests/test_otter.py
19
21
  tests/test_package.py
20
- tests/test_transient.py
22
+ tests/test_transient.py
23
+ tests/test_util.py
@@ -0,0 +1,17 @@
1
+ numpy>=1.20
2
+ astropy>=5.2
3
+ pandas
4
+ matplotlib
5
+ plotly
6
+ astroquery
7
+ synphot
8
+ ads
9
+ ruff
10
+ pre-commit
11
+ Sphinx>=3.0.0
12
+ myst_parser>=0.13
13
+ nbsphinx>=0.9.1
14
+ sphinx-book-theme>=0.0.33
15
+ sphinx_copybutton
16
+ autodoc
17
+ ipykernel
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  # get the version
2
4
  from ._version import __version__
3
5
 
@@ -2,4 +2,4 @@
2
2
  Just define the package version in one place
3
3
  """
4
4
 
5
- __version__ = "0.0.1"
5
+ __version__ = "0.0.2"
@@ -2,8 +2,14 @@
2
2
  Custom exceptions for otter
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
 
6
8
  class FailedQueryError(ValueError):
9
+ """
10
+ Exception thrown when the users query does not return any results.
11
+ """
12
+
7
13
  def __str__(self):
8
14
  txt = "You're query/search did not return any results! "
9
15
  txt += "Try again with different parameters!"
@@ -11,10 +17,19 @@ class FailedQueryError(ValueError):
11
17
 
12
18
 
13
19
  class IOError(ValueError):
20
+ """
21
+ Exception thrown when the input or output argument/value is not the correct type.
22
+ """
23
+
14
24
  pass
15
25
 
16
26
 
17
27
  class OtterLimitationError(Exception):
28
+ """
29
+ Exception thrown when the user requests something that is currently not supported
30
+ by the API.
31
+ """
32
+
18
33
  def __init__(self, msg):
19
34
  self.msg = "Current Limitation Found: " + msg
20
35
 
@@ -23,4 +38,8 @@ class OtterLimitationError(Exception):
23
38
 
24
39
 
25
40
  class TransientMergeError(Exception):
41
+ """
42
+ Exception thrown when the Transient objects can not be combined as expected.
43
+ """
44
+
26
45
  pass
@@ -2,6 +2,7 @@
2
2
  This is the primary class for user interaction with the catalog
3
3
  """
4
4
 
5
+ from __future__ import annotations
5
6
  import os
6
7
  import json
7
8
  import glob
@@ -28,14 +29,11 @@ class Otter(object):
28
29
  This is the primary class for users to access the otter backend database
29
30
 
30
31
  Args:
31
- username [str]: Your connection username to the database, default is the user
32
- login which only has read permission.
33
- password [str]: Your password corresponding to your username.
34
- db [str]: The database name to connect to. This is default to 'otter' which is
35
- the only database so far.
36
- collection [str]: The collection to read data from. Right now the only
37
- collection is 'tdes'.
38
- debug [bool]: debug mode, set to true to limit reading from database.
32
+ datadir (str): Path to the data directory with the otter data. If not provided
33
+ will default to a ".otter" directory in the CWD where you call
34
+ this class from.
35
+ debug (bool): If we should just debug and not do anything serious.
36
+
39
37
  """
40
38
 
41
39
  def __init__(self, datadir: str = None, debug: bool = False) -> None:
@@ -87,9 +85,9 @@ class Otter(object):
87
85
  Performs a cone search of the catalog over the given coords and radius.
88
86
 
89
87
  Args:
90
- coords [SkyCoord]: An astropy SkyCoord object with coordinates to match to
91
- radius [float]: The radius of the cone in arcseconds, default is 0.05"
92
- raw [bool]: If False (the default) return an astropy table of the metadata
88
+ coords (SkyCoord): An astropy SkyCoord object with coordinates to match to
89
+ radius (float): The radius of the cone in arcseconds, default is 0.05"
90
+ raw (bool): If False (the default) return an astropy table of the metadata
93
91
  for matching objects. Otherwise, return the raw json dicts
94
92
 
95
93
  Return:
@@ -117,35 +115,40 @@ class Otter(object):
117
115
  unit conversion for you!
118
116
 
119
117
  Args:
120
- flux_units [astropy.unit.Unit]: Either a valid string to convert
118
+ flux_units (astropy.unit.Unit): Either a valid string to convert
121
119
  or an astropy.unit.Unit
122
- date_units [astropy.unit.Unit]: Either a valid string to convert to a date
120
+ date_units (astropy.unit.Unit): Either a valid string to convert to a date
123
121
  or an astropy.unit.Unit
124
- return_type [str]: Either 'astropy' or 'pandas'. If astropy, returns an
122
+ return_type (str): Either 'astropy' or 'pandas'. If astropy, returns an
125
123
  astropy Table. If pandas, returns a pandas DataFrame.
126
124
  Default is 'astropy'.
127
- obs_type [str]: Either 'radio', 'uvoir', or 'xray'. Will only return that
125
+ obs_type (str): Either 'radio', 'uvoir', or 'xray'. Will only return that
128
126
  type of photometry if not None. Default is None and will
129
127
  return any type of photometry.
130
- keep_raw [bool]: If True, keep the raw flux/date/freq/wave associated with
128
+ keep_raw (bool): If True, keep the raw flux/date/freq/wave associated with
131
129
  the dataset. Else, just keep the converted data. Default
132
130
  is False.
133
- **kwargs : Arguments to pass to Otter.query(). Can be:
134
- names [list[str]]: A list of names to get the metadata for
135
- coords [SkyCoord]: An astropy SkyCoord object with coordinates
131
+ **kwargs : Arguments to pass to Otter.query(). Can be::
132
+
133
+ names (list[str]): A list of names to get the metadata for
134
+ coords (SkyCoord): An astropy SkyCoord object with coordinates
136
135
  to match to
137
- radius [float]: The radius in arcseconds for a cone search,
136
+ radius (float): The radius in arcseconds for a cone search,
138
137
  default is 0.05"
139
- minZ [float]: The minimum redshift to search for
140
- maxZ [float]: The maximum redshift to search for
141
- refs [list[str]]: A list of ads bibcodes to match to. Will only
138
+ minZ (float): The minimum redshift to search for
139
+ maxZ (float): The maximum redshift to search for
140
+ refs (list[str]): A list of ads bibcodes to match to. Will only
142
141
  return metadata for transients that have this
143
142
  as a reference.
144
- hasSpec [bool]: if True, only return events that have spectra.
143
+ hasSpec (bool): if True, only return events that have spectra.
145
144
 
146
145
  Return:
147
- The photometry for the requested transients that match the arguments.
148
- Will be an astropy Table sorted by transient default name.
146
+ The photometry for the requested transients that match the arguments.
147
+ Will be an astropy Table sorted by transient default name.
148
+
149
+ Raises:
150
+ FailedQueryError: When the query returns no results
151
+ IOError: if one of your inputs is incorrect
149
152
  """
150
153
  queryres = self.query(hasphot=True, **kwargs)
151
154
 
@@ -153,16 +156,25 @@ class Otter(object):
153
156
  for transient in queryres:
154
157
  # clean the photometry
155
158
  default_name = transient["name/default_name"]
156
- phot = transient.clean_photometry(
157
- flux_unit=flux_unit,
158
- date_unit=date_unit,
159
- wave_unit=wave_unit,
160
- freq_unit=freq_unit,
161
- obs_type=obs_type,
162
- )
163
- phot["name"] = [default_name] * len(phot)
164
159
 
165
- dicts.append(phot)
160
+ try:
161
+ phot = transient.clean_photometry(
162
+ flux_unit=flux_unit,
163
+ date_unit=date_unit,
164
+ wave_unit=wave_unit,
165
+ freq_unit=freq_unit,
166
+ obs_type=obs_type,
167
+ )
168
+
169
+ phot["name"] = [default_name] * len(phot)
170
+
171
+ dicts.append(phot)
172
+
173
+ except FailedQueryError:
174
+ # This is fine, it just means that there is no data associated
175
+ # with this one transient. We'll check and make sure there is data
176
+ # associated with at least one of the transients later!
177
+ pass
166
178
 
167
179
  if len(dicts) == 0:
168
180
  raise FailedQueryError()
@@ -203,7 +215,7 @@ class Otter(object):
203
215
  Loads an otter JSON file
204
216
 
205
217
  Args:
206
- filename [str]: The path to the file to load
218
+ filename (str): The path to the OTTER JSON file to load
207
219
  """
208
220
 
209
221
  # read in files from summary
@@ -234,15 +246,15 @@ class Otter(object):
234
246
  same units.
235
247
 
236
248
  Args:
237
- names [list[str]]: A list of names to get the metadata for
238
- coords [SkyCoord]: An astropy SkyCoord object with coordinates to match to
239
- radius [float]: The radius in arcseconds for a cone search, default is 0.05"
240
- minz [float]: The minimum redshift to search for
241
- maxz [float]: The maximum redshift to search for
242
- refs [list[str]]: A list of ads bibcodes to match to. Will only return
249
+ names (list[str]): A list of names to get the metadata for
250
+ coords (SkyCoord): An astropy SkyCoord object with coordinates to match to
251
+ radius (float): The radius in arcseconds for a cone search, default is 0.05"
252
+ minz (float): The minimum redshift to search for
253
+ maxz (float): The maximum redshift to search for
254
+ refs (list[str]): A list of ads bibcodes to match to. Will only return
243
255
  metadata for transients that have this as a reference.
244
- hasphot [bool]: if True, only returns transients which have photometry.
245
- hasspec [bool]: if True, only return transients that have spectra.
256
+ hasphot (bool): if True, only returns transients which have photometry.
257
+ hasspec (bool): if True, only return transients that have spectra.
246
258
 
247
259
  Return:
248
260
  Get all of the raw (unconverted!) data for objects that match the criteria.
@@ -344,24 +356,29 @@ class Otter(object):
344
356
 
345
357
  return outdata
346
358
 
347
- def save(self, schema: list[dict], testing=False, **kwargs) -> None:
359
+ def save(self, schema: list[dict], testing=False) -> None:
348
360
  """
349
361
  Upload all the data in the given list of schemas.
350
362
 
351
363
  Args:
352
- schema [list[dict]]: A list of json dictionaries
364
+ schema (list[dict]): A list of json dictionaries
365
+ testing (bool): Should we just enter test mode? Default is False
366
+
367
+ Raises:
368
+ OtterLimitationError: If some objects in OTTER are within 5" we can't figure
369
+ out which ones to merge with which ones.
353
370
  """
354
371
 
355
372
  if not isinstance(schema, list):
356
373
  schema = [schema]
357
374
 
358
375
  for transient in schema:
359
- print(transient["name/default_name"])
360
-
361
376
  # convert the json to a Transient
362
377
  if not isinstance(transient, Transient):
363
378
  transient = Transient(transient)
364
379
 
380
+ print(transient["name/default_name"])
381
+
365
382
  coord = transient.get_skycoord()
366
383
  res = self.cone_search(coords=coord)
367
384
 
@@ -405,8 +422,6 @@ class Otter(object):
405
422
  outfilepath = os.path.join(self.DATADIR, todel[0] + ".json")
406
423
  if test_mode:
407
424
  print("Renaming the following file for backups: ", outfilepath)
408
- else:
409
- os.rename(outfilepath, outfilepath + ".backup")
410
425
  else:
411
426
  if test_mode:
412
427
  print("Don't need to mess with the files at all!")
@@ -429,13 +444,16 @@ class Otter(object):
429
444
  print(f"Would write to {outfilepath}")
430
445
  # print(out)
431
446
 
432
- def generate_summary_table(self, save=False):
447
+ def generate_summary_table(self, save=False) -> pd.DataFrame:
433
448
  """
434
449
  Generate a summary table for the JSON files in self.DATADIR
435
450
 
436
451
  args:
437
- save [bool]: if True, save the summary file to "summary.csv"
438
- in self.DATADIR. Default is False.
452
+ save (bool): if True, save the summary file to "summary.csv"
453
+ in self.DATADIR. Default is False and is just returned.
454
+
455
+ returns:
456
+ pandas.DataFrame of the summary meta information of the transients
439
457
  """
440
458
  allfiles = glob.glob(os.path.join(self.DATADIR, "*.json"))
441
459
 
@@ -3,10 +3,12 @@ Class for a transient,
3
3
  basically just inherits the dict properties with some overwriting
4
4
  """
5
5
 
6
+ from __future__ import annotations
6
7
  import warnings
7
8
  from copy import deepcopy
8
9
  import re
9
10
  from collections.abc import MutableMapping
11
+ from typing_extensions import Self
10
12
 
11
13
  import numpy as np
12
14
  import pandas as pd
@@ -37,7 +39,9 @@ class Transient(MutableMapping):
37
39
  Overwrite the dictionary init
38
40
 
39
41
  Args:
40
- d [dict]: A transient dictionary
42
+ d (dict): A transient dictionary
43
+ name (str): The default name of the transient, default is None and it will
44
+ be inferred from the input dictionary.
41
45
  """
42
46
  self.data = d
43
47
 
@@ -68,7 +72,7 @@ class Transient(MutableMapping):
68
72
  """
69
73
 
70
74
  if isinstance(keys, (list, tuple)):
71
- return Transient({key: self[key] for key in keys})
75
+ return Transient({key: (self[key] if key in self else []) for key in keys})
72
76
  elif isinstance(keys, str) and "/" in keys: # this is for a path
73
77
  s = "']['".join(keys.split("/"))
74
78
  s = "['" + s
@@ -85,6 +89,10 @@ class Transient(MutableMapping):
85
89
  return self.data[keys]
86
90
 
87
91
  def __setitem__(self, key, value):
92
+ """
93
+ Override set item to work with the '/' syntax
94
+ """
95
+
88
96
  if isinstance(key, str) and "/" in key: # this is for a path
89
97
  s = "']['".join(key.split("/"))
90
98
  s = "['" + s
@@ -109,7 +117,7 @@ class Transient(MutableMapping):
109
117
 
110
118
  def __repr__(self, html=False):
111
119
  if not html:
112
- return str(self.data)
120
+ return f"Transient(\n\tName: {self.default_name},\n\tKeys: {self.keys()}\n)"
113
121
  else:
114
122
  html = ""
115
123
 
@@ -260,14 +268,17 @@ class Transient(MutableMapping):
260
268
  # now return out as a Transient Object
261
269
  return Transient(out)
262
270
 
263
- def get_meta(self, keys=None):
271
+ def get_meta(self, keys=None) -> Self:
264
272
  """
265
273
  Get the metadata (no photometry or spectra)
266
274
 
267
275
  This essentially just wraps on __getitem__ but with some checks
268
276
 
269
277
  Args:
270
- keys [list[str]] : list of keys
278
+ keys (list[str]) : list of keys to get the metadata for from the transient
279
+
280
+ Returns:
281
+ A Transient object of just the meta data
271
282
  """
272
283
  if keys is None:
273
284
  keys = list(self.keys())
@@ -296,9 +307,16 @@ class Transient(MutableMapping):
296
307
 
297
308
  return self[keys]
298
309
 
299
- def get_skycoord(self, coord_format="icrs"):
310
+ def get_skycoord(self, coord_format="icrs") -> SkyCoord:
300
311
  """
301
312
  Convert the coordinates to an astropy SkyCoord
313
+
314
+ Args:
315
+ coord_format (str): Astropy coordinate format to convert the SkyCoord to
316
+ defaults to icrs.
317
+
318
+ Returns:
319
+ Astropy.coordinates.SkyCoord of the default coordinate for the transient
302
320
  """
303
321
 
304
322
  # now we can generate the SkyCoord
@@ -309,9 +327,12 @@ class Transient(MutableMapping):
309
327
 
310
328
  return coord
311
329
 
312
- def get_discovery_date(self):
330
+ def get_discovery_date(self) -> Time:
313
331
  """
314
- Get the default discovery date
332
+ Get the default discovery date for this Transient
333
+
334
+ Returns:
335
+ astropy.time.Time of the default discovery date
315
336
  """
316
337
  key = "date_reference"
317
338
  date = self._get_default(key, filt='df["date_type"] == "discovery"')
@@ -322,9 +343,12 @@ class Transient(MutableMapping):
322
343
 
323
344
  return Time(date["value"], format=f)
324
345
 
325
- def get_redshift(self):
346
+ def get_redshift(self) -> float:
326
347
  """
327
- Get the default redshift
348
+ Get the default redshift of this Transient
349
+
350
+ Returns:
351
+ Float value of the default redshift
328
352
  """
329
353
  f = "df['distance_type']=='redshift'"
330
354
  default = self._get_default("distance", filt=f)
@@ -390,10 +414,32 @@ class Transient(MutableMapping):
390
414
  wave_unit: u.Unit = "nm",
391
415
  by: str = "raw",
392
416
  obs_type: str = None,
393
- ):
417
+ ) -> pd.DataFrame:
394
418
  """
395
419
  Ensure the photometry associated with this transient is all in the same
396
420
  units/system/etc
421
+
422
+ Args:
423
+ flux_unit (astropy.unit.Unit): The astropy unit or string representation of
424
+ an astropy unit to convert and return the
425
+ flux as.
426
+ date_unit (str): Valid astropy date format string.
427
+ freq_unit (astropy.unit.Unit): The astropy unit or string representation of
428
+ an astropy unit to convert and return the
429
+ frequency as.
430
+ wave_unit (astropy.unit.Unit): The astropy unit or string representation of
431
+ an astropy unit to convert and return the
432
+ wavelength as.
433
+ by (str): Either 'raw' or 'value'. 'raw' is the default and is highly
434
+ recommended! If 'value' is used it may skip some photometry.
435
+ See the schema definition to understand this keyword completely
436
+ before using it.
437
+ obs_type (str): "radio", "xray", or "uvoir". If provided, it only returns
438
+ data taken within that range of wavelengths/frequencies.
439
+ Default is None which will return all of the data.
440
+
441
+ Returns:
442
+ A pandas DataFrame of the cleaned up photometry in the requested units
397
443
  """
398
444
 
399
445
  # check inputs
@@ -429,6 +475,9 @@ class Transient(MutableMapping):
429
475
  else:
430
476
  by = "value"
431
477
 
478
+ # skip rows where 'by' is nan
479
+ df = df[df[by].notna()]
480
+
432
481
  # drop irrelevant obs_types before continuing
433
482
  if obs_type is not None:
434
483
  valid_obs_types = {"radio", "uvoir", "xray"}
@@ -6,19 +6,21 @@ Currently supported backends are:
6
6
  - plotly
7
7
  """
8
8
 
9
+ from __future__ import annotations
9
10
  import importlib
10
11
 
11
12
 
12
13
  class OtterPlotter:
13
- def __init__(self, backend):
14
- """
15
- Handles the backend for the "plotter" module
14
+ """
15
+ Handles the backend for the "plotter" module
16
16
 
17
- Args:
18
- backend [string]: a string of the module name to import and use
19
- as the backend. Currently supported are "matplotlib",
20
- "matplotlib.pyplot", "plotly", and "plotly.graph_objects"
21
- """
17
+ Args:
18
+ backend (string): a string of the module name to import and use
19
+ as the backend. Currently supported are "matplotlib",
20
+ "matplotlib.pyplot", "plotly", and "plotly.graph_objects"
21
+ """
22
+
23
+ def __init__(self, backend):
22
24
  if backend == "matplotlib.pyplot":
23
25
  self.backend = backend
24
26
  elif backend == "pyplot.graph_objects":