Finishing implementation and doc strings
Ahmed Hossam
Posted on June 17, 2024
The main implementation and documentation strings phase has been finished.
One of the functions that have been deleted was parse_unit
, it almost wasn't triggered by any event of HEK events, so I decided to delete it, and we will see in the future if it has any major effects on the code.
Also parse_columns_to_table
has been refactored by adding more variables to make the code more readable.
This is the new implementation:
def parse_columns_to_table(table, attributes, is_coord_prop = False):
"""
Parses the columns in an Astropy table and convert the values into Astropy objects.
Parameters
----------
table: astropy.table
Astropy table.
attributes: list
A list of HEK unit attributes or coordinate attributes.
is_coord_prop: bool
To specify if `attributes` is a list of unit attributes or coordinate attributes.
Returns
-------
`astropy.table`
Raises
------
TypeError
If `table` is not an Astropy table.
KeyError
If any of the attribute dictionaries are missing required keys (i.e. "name", "unit_prop").
"""
for attribute in attributes:
if attribute["name"] in table.colnames and ("unit_prop" in attribute or attribute.get("is_chaincode", False)) and attribute.get("is_unit_prop", True):
unit_attr = ""
if is_coord_prop:
unit_attr = "event_coordunit"
else:
unit_attr = attribute["unit_prop"]
new_column = []
for idx, value in enumerate(table[attribute["name"]]):
new_value = ""
if value in ["", None]:
new_value = value
elif attribute.get("is_chaincode", False):
new_value = parse_chaincode(value, attribute, table[attribute["unit_prop"]][idx])
else:
unit = get_unit(table[unit_attr][idx])
new_value = value * unit
new_column.append(new_value)
table[attribute["name"]] = new_column
for attribute in attributes:
if attribute.get("is_unit_prop", False) and attribute["name"] in table.colnames:
del table[attribute["name"]]
return table
Also a public interface __all__
has been added to util.py
, until now, the public "api" for util.py
is:
__all__ = [
'freeze',
'parse_times',
'parse_values_to_quantities',
'UNIT_FILE_PATH',
'COORD_FILE_PATH'
]
UNIT_FILE_PATH
and COORD_FILE_PATH
are used in test_hek.py
There was a problem in get_unit
because of some units that wasn't parsed correctly, one of them is ergs per cubic centimeter
, because of the first implementation of get_unit
:
with u.add_enabled_units([cm2, m2, m3]), u.set_enabled_aliases(aliases):
# Units for coordinate frames have more than one unit, otherwise it will be just one unit.
# There is an assumption that coord1_unit, coord2_unit and coord3_unit are the same.
units = re.split(r'[, ]', unit)
return u.Unit(units[0].lower())
The function was taking the first "word" of the input and returns the unit, obviously this will be wrong with ergs per cubic centimeter
because it will take only ergs
and returns u.Unit('erg')
.
But this is the only case with HEK units, the other units works just fine.
This is the new implementation to correct this behavior:
def get_unit(unit):
"""
Converts string into astropy unit.
Parameters
----------
unit: str
The targeted unit
Returns
-------
unit
Astropy unit object (e.g. <class 'astropy.units.core.Unit'> or <class 'astropy.units.core.CompositeUnit'>)
Raises
------
ValueError
Because `unit` did not parse as unit.
Notes
----
For the complete list of HEK parameters: https://www.lmsal.com/hek/VOEvent_Spec.html
"""
cm2 = u.def_unit("cm2", u.cm**3)
m2 = u.def_unit("m2", u.m**2)
m3 = u.def_unit("m3", u.m**3)
erg_per_cm3 = u.def_unit("ergs/cm^3", u.erg/u.ml)
aliases = {
"steradian": u.sr,
"arcseconds": u.arcsec,
"degrees": u.deg,
"sec": u.s,
"emx": u.Mx,
"amperes": u.A,
"ergs": u.erg,
"cubic centimeter": u.ml,
"square centimeter": cm2,
"cubic meter": m3,
"square meter": m2,
"ergs per cubic centimeter": erg_per_cm3,
}
with u.add_enabled_units([cm2, m2, m3]), u.set_enabled_aliases(aliases), warnings.catch_warnings():
# Units for coordinate frames have more than one unit, otherwise it will be just one unit.
# There is an assumption that coord1_unit, coord2_unit and coord3_unit are the same.
warnings.filterwarnings("ignore", category=u.UnitsWarning)
if unit in aliases:
unit = u.Unit(aliases[unit])
else:
unit = u.Unit(re.split(r'[, ]', unit)[0].lower())
return unit
Also, the units warnings were ignored because it's irrelevant to the user of HEK.
So, the next phase is testing, we will see if our assumptions about the unit parsing and the other refactoring were right or not.
Posted on June 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.