Source code for astromodels.core.thread_safe_unit_format

# NOTE: the astropy.units.format pre-defined formatters use ply.yacc
# for parsing, which unfortunately is not thread safe. This causes
# all sort of weird problems when trying to use ipyparallel features.
# Here we implement a format which is very simple, does not use
# ply.yacc and is thread safe

from builtins import str
from builtins import map
from builtins import zip
import re
from astropy.units.format.base import Base
import astropy.units as u
from functools import reduce


# NOTE: the metaclass in Base will take care of registering
# this format, which will be available in the u.Unit
# constructor and in the .to_string method of the Unit and
# Quantity classes as format='threadsafe' (case insensitive)

def _format_one(xxx_todo_changeme):
    # This is for example 'cm-2' if base=cm and power=-2,
    # but only 'cm' if base=cm and power=1

    (base, power) = xxx_todo_changeme
    return "%s%s" % (base.to_string(), power if power != 1 else '')


[docs]class ThreadSafe(Base):
[docs] @classmethod def parse(cls, s): # Since often we get these strings from a YAML file, # we want to make sure there is no new line within # the string. assert "\n" not in s # We assume that the string is something like # [unit1]{power} [unit2]{power} ..., like for example: # "m s-1" (a speed) or "keV-1 cm-2 s-1" # (a differential flux in 1 / (keV cm**2 s)) # This is of course the format that is the output of # our to_string method(). See there for details tokens = re.findall('([a-zA-z]+)(-?\+?[0-9]+)?', s) # tokens is a list of tuples of the type [(unit name, power), ...] # Here we build a list like [u.m, u.s**(-1), ...] r = [] for (unit, power) in tokens: # Get the primitive unit from the units module thisr = getattr(u, unit) # If needed, raise it to the power if power != '': thisr = thisr**power r.append(thisr) # Now we multiply the units # so that we get something like u.m * u.s**(-1) return reduce(lambda x, y: x*y, r)
[docs] @classmethod def to_string(cls, unit): # The Unit class has two lists: bases (which are primitive units) # and powers (the correspondent powers). Thus we just need to use # those and encode them in a string like [unit1]{power} [unit2]{power} ... tokens = list(map(_format_one, list(zip(unit.bases, unit.powers)))) return str(" ".join(tokens))