def test_init(self): try: OrderedDict([('a', 1), ('b', 2)], None) # too many args assert False except TypeError: pass else: assert False pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)] self.assertEqual(sorted(OrderedDict(dict(pairs)).items()), pairs) # dict input self.assertEqual(sorted(OrderedDict(**dict(pairs)).items()), pairs) # kwds input self.assertEqual(list(OrderedDict(pairs).items()), pairs) # pairs input self.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5).items()), pairs) # mixed input # make sure no positional args conflict with possible kwdargs self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args, ['self']) # Make sure that direct calls to __init__ do not clear previous contents d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) d.__init__([('e', 5), ('f', 6)], g=7, d=4) self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
def test_reduce_not_too_fat(self): # do not save instance dictionary if not needed pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) self.assertEqual(len(od.__reduce__()), 2) od.x = 10 self.assertEqual(len(od.__reduce__()), 3)
def test_clear(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) self.assertEqual(len(od), len(pairs)) od.clear() self.assertEqual(len(od), 0)
def test_yaml_linkage(self): # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature. # In yaml, lists are native but tuples are not. pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) # yaml.dump(od) --> # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n' self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1]))
def test_reinsert(self): # Given insert a, insert b, delete a, re-insert a, # verify that a is now later than b. od = OrderedDict() od['a'] = 1 od['b'] = 2 del od['a'] od['a'] = 1 self.assertEqual(list(od.items()), [('b', 2), ('a', 1)])
class OrderedSet(collections.MutableSet): def __init__(self, values=()): self._od = OrderedDict().fromkeys(values) def __len__(self): return len(self._od) def __iter__(self): return iter(self._od) def __contains__(self, value): return value in self._od def add(self, value): self._od[value] = None def discard(self, value): self._od.pop(value, None)
def test_delitem(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) del od['a'] self.assertNotIn('a', od) try: del od['a'] assert False except KeyError: pass else: assert False self.assertEqual(list(od.items()), pairs[:2] + pairs[3:])
def test_popitem(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) while pairs: self.assertEqual(od.popitem(), pairs.pop()) try: od.popitem() assert False except: pass else: assert False self.assertEqual(len(od), 0)
def test_ordered_dict(tmpdir): # Test that we can write out and read in ordered dicts. tree = { "ordered_dict": OrderedDict( [('first', 'foo'), ('second', 'bar'), ('third', 'baz')]), "unordered_dict": { 'first': 'foo', 'second': 'bar', 'third': 'baz' } } def check_asdf(asdf): tree = asdf.tree assert isinstance(tree['ordered_dict'], OrderedDict) assert list(tree['ordered_dict'].keys()) == ['first', 'second', 'third'] assert not isinstance(tree['unordered_dict'], OrderedDict) assert isinstance(tree['unordered_dict'], dict) def check_raw_yaml(content): assert b'OrderedDict' not in content helpers.assert_roundtrip_tree(tree, tmpdir, check_asdf, check_raw_yaml)
class Sagittarius(coord.BaseCoordinateFrame): """ A Heliocentric spherical coordinate system defined by the orbit of the Sagittarius dwarf galaxy, as described in http://adsabs.harvard.edu/abs/2003ApJ...599.1082M and further explained in http://www.astro.virginia.edu/~srm4n/Sgr/. Parameters ---------- representation : `BaseRepresentation` or None A representation object or None to have no data (or use the other keywords) Lambda : `Angle`, optional, must be keyword The longitude for this object (`Beta` must also be given and `representation` must be None). Beta : `Angle`, optional, must be keyword The Declination for this object (`Lambda` must also be given and `representation` must be None). distance : `Quantity`, optional, must be keyword The Distance for this object along the line-of-sight. (`representation` must be None). """ preferred_representation = coord.SphericalRepresentation preferred_attr_names = OrderedDict([('Lambda', 'lon'), ('Beta', 'lat'), ('distance', 'distance')]) preferred_attr_units = {'Lambda': u.degree, 'Beta': u.degree}
def test_pop(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) shuffle(pairs) while pairs: k, v = pairs.pop() self.assertEqual(od.pop(k), v) try: od.pop('xyz') assert False except KeyError: pass else: assert False self.assertEqual(len(od), 0) self.assertEqual(od.pop(k, 12345), 12345)
def test_iterators(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) self.assertEqual(list(od), [t[0] for t in pairs]) self.assertEqual(od.keys()[:], [t[0] for t in pairs]) self.assertEqual(od.values()[:], [t[1] for t in pairs]) self.assertEqual(od.items()[:], pairs) self.assertEqual(list(od.iterkeys()), [t[0] for t in pairs]) self.assertEqual(list(od.itervalues()), [t[1] for t in pairs]) self.assertEqual(list(od.iteritems()), pairs) self.assertEqual(list(reversed(od)), [t[0] for t in reversed(pairs)])
def test_setdefault(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) pair_order = list(od.items()) self.assertEqual(od.setdefault('a', 10), 3) # make sure order didn't change self.assertEqual(list(od.items()), pair_order) self.assertEqual(od.setdefault('x', 10), 10) # make sure 'x' is added to the end self.assertEqual(list(od.items())[-1], ('x', 10))
def hist1d_to_table(hist): """Convert 1D ROOT histogram into astropy table. Parameters ---------- hist : ROOT.TH1 ROOT histogram Returns ------- table : `~astropy.table.Table` Astropy table """ bins = range(1, hist.GetNbinsX() + 1) data = OrderedDict() names = [ ('x', 'GetBinCenter'), ('x_bin_lo', 'GetBinLowEdge'), ('x_bin_width', 'GetBinWidth'), ('y', 'GetBinContent'), ('y_err', 'GetBinError'), ('y_err_lo', 'GetBinErrorLow'), ('y_err_hi', 'GetBinErrorUp'), ] for column, method in names: try: getter = getattr(hist, method) data[column] = [getter(i) for i in bins] # Note: `GetBinErrorLow` is not available in old ROOT versions!? except AttributeError: pass table = Table(data) table['x_bin_hi'] = table['x_bin_lo'] + table['x_bin_width'] return table
def graph1d_to_table(graph): """Convert ROOT TGraph to an astropy Table. Parameters ---------- graph : ROOT.TGraph ROOT graph Returns ------- table : `~astropy.table.Table` Astropy table """ bins = range(0, graph.GetN()) data = OrderedDict() names = [ ('x', 'GetX'), ('x_err', 'GetEX'), ('x_err_lo', 'GetEXlow'), ('x_err_hi', 'GetEXhigh'), ('y', 'GetY'), ('y_err', 'GetEY'), ('y_err_lo', 'GetEYlow'), ('y_err_hi', 'GetEYhigh'), ] for column, method in names: try: buffer_ = getattr(graph, method)() data[column] = [buffer_[i] for i in bins] except IndexError: pass table = Table(data) return table
def test_copying(self): # Check that ordered dicts are copyable, deepcopyable, picklable, # and have a repr/eval round-trip pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) update_test = OrderedDict() update_test.update(od) for i, dup in enumerate([ od.copy(), copy.copy(od), copy.deepcopy(od), pickle.loads(pickle.dumps(od, 0)), pickle.loads(pickle.dumps(od, 1)), pickle.loads(pickle.dumps(od, 2)), pickle.loads(pickle.dumps(od, -1)), eval(repr(od)), update_test, OrderedDict(od), ]): self.assertTrue(dup is not od) self.assertEquals(dup, od) self.assertEquals(list(dup.items()), list(od.items())) self.assertEquals(len(dup), len(od)) self.assertEquals(type(dup), type(od))
Parameters ---------- amplitude : float Value of the integral v_0 : float Velocity parameter (km s^-1) """ amplitude = Parameter() v_0 = Parameter() def __init__(self, amplitude=1, v_0=560, **kwargs): super(Paczynski1990Velocity, self).__init__(amplitude=amplitude, v_0=v_0, **kwargs) @staticmethod def eval(v, amplitude, v_0): """One dimensional Paczynski 1990 velocity model function""" return amplitude * 4. / (np.pi * v_0 * (1 + (v / v_0)**2)**2) velocity_distributions = OrderedDict() """Dictionary of available distributions. Useful for automatic processing. """ velocity_distributions['H05'] = FaucherKaspi2006VelocityMaxwellian velocity_distributions['F06B'] = FaucherKaspi2006VelocityBimodal velocity_distributions['F06P'] = Paczynski1990Velocity
def __init__(self, values=()): self._od = OrderedDict().fromkeys(values)
error=False, time=False, force=True, default_colunits=['mag']) register(AMCM, n_bands=1, error=False, time=False, force=True, default_colunits=['mag']) register(len, n_bands=1, error=False, time=False, name='n', other_cols=OrderedDict([('n', int)]), force=True, default_coldescriptions=['Number of datapoints'], default_colunits=['ct']) register(np.min, n_bands=1, error=False, time=False, name='min', force=True, default_colunits=['mag'], default_coldescriptions=['minimum magnitude in lightcurve']) register(np.max, n_bands=1, error=False, time=False,
def main(srcdir, outfn, templateloc, verbose=True): from jinja2 import Environment, FileSystemLoader if verbose: print_ = lambda *args, **kwargs: print(*args, **kwargs) else: print_ = lambda *args, **kwargs: None #Prepare the jinja2 templating environment env = Environment(loader=FileSystemLoader(templateloc)) def prefix(a_list, pre): return [pre+'{0}'.format(an_element) for an_element in a_list] def postfix(a_list, post): return ['{0}'.format(an_element)+post for an_element in a_list] def surround(a_list, pre, post): return [pre+'{0}'.format(an_element)+post for an_element in a_list] env.filters['prefix'] = prefix env.filters['postfix'] = postfix env.filters['surround'] = surround erfa_c_in = env.get_template('core.c.templ') erfa_py_in = env.get_template('core.py.templ') #Extract all the ERFA function names from erfa.h if os.path.isdir(srcdir): erfahfn = os.path.join(srcdir, 'erfa.h') multifilserc = True else: erfahfn = os.path.join(os.path.split(srcdir)[0], 'erfa.h') multifilserc = False with open(erfahfn, "r") as f: erfa_h = f.read() funcs = OrderedDict() section_subsection_functions = re.findall('/\* (\w*)/(\w*) \*/\n(.*?)\n\n', erfa_h, flags=re.DOTALL|re.MULTILINE) for section, subsection, functions in section_subsection_functions: print_("{0}.{1}".format(section, subsection)) if section == "Astronomy": func_names = re.findall(' (\w+)\(.*?\);', functions, flags=re.DOTALL) for name in func_names: print_("{0}.{1}.{2}...".format(section, subsection, name)) if multifilserc: # easy because it just looks in the file itself funcs[name] = Function(name, srcdir) else: # Have to tell it to look for a declaration matching # the start of the header declaration, otherwise it # might find a *call* of the function instead of the # definition for line in functions.split('\n'): if name in line: # [:-1] is to remove trailing semicolon, and # splitting on '(' is because the header and # C files don't necessarily have to match # argument names and line-breaking or # whitespace match_line = line[:-1].split('(')[0] funcs[name] = Function(name, srcdir, match_line) break else: raise ValueError("A name for a C file wasn't " "found in the string that " "spawned it. This should be " "impossible!") funcs = list(funcs.values()) #Extract all the ERFA constants from erfam.h erfamhfn = os.path.join(srcdir, 'erfam.h') with open(erfamhfn, 'r') as f: erfa_m_h = f.read() constants = [] for chunk in erfa_m_h.split("\n\n"): result = re.findall("#define (ERFA_\w+?) (.+?)$", chunk, flags=re.DOTALL|re.MULTILINE) if result: doc = re.findall("/\* (.+?) \*/\n", chunk, flags=re.DOTALL) for (name, value) in result: constants.append(Constant(name, value, doc)) print_("Rendering template") erfa_c = erfa_c_in.render(funcs=funcs) erfa_py = erfa_py_in.render(funcs=funcs, constants=constants) if outfn is not None: outfn_c = os.path.splitext(outfn)[0] + ".c" print_("Saving to", outfn, 'and', outfn_c) with open(outfn, "w") as f: f.write(erfa_py) with open(outfn_c, "w") as f: f.write(erfa_c) print_("Done!") return erfa_c, erfa_py, funcs
def test_setitem(self): od = OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)]) od['c'] = 10 # existing element od['f'] = 20 # new element self.assertEqual(list(od.items()), [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)])
def ordereddict_constructor(loader, node): try: omap = loader.construct_yaml_omap(node) return OrderedDict(*omap) except yaml.constructor.ConstructorError: return list(*loader.construct_yaml_seq(node))
bar_radius = 3.0 # Radius of the galactic bar (not equal r_0!) spiralarms = np.array( ['Norma', 'Perseus', 'Carina Sagittarius', 'Crux Scutum']) def __init__(self): self.r_0 = self.r_0 * np.ones(4) self.theta_0 = self.theta_0 + np.array([0, 90, 180, 270]) self.k = 1. / np.tan(np.radians(self.p)) * np.ones(4) # Compute start and end point of the bar x_0, y_0 = self.xy_position(radius=self.bar_radius, spiralarm_index=0) x_1, y_1 = self.xy_position(radius=self.bar_radius, spiralarm_index=2) self.bar = dict(x=np.array([x_0, x_1]), y=np.array([y_0, y_1])) # TODO: this is not picked up in the HTML docs ... don't know why. # http://sphinx-doc.org/latest/ext/example_numpy.html # For now I add it in the module-level docstring in an `Attributes` section. radial_distributions = OrderedDict() """Dictionary of available spatial distributions. Useful for automatic processing. """ radial_distributions['CB98'] = CaseBattacharya1998 radial_distributions['F06'] = FaucherKaspi2006 radial_distributions['L06'] = Lorimer2006 radial_distributions['P90'] = Paczynski1990 radial_distributions['YK04'] = YusifovKucuk2004 radial_distributions['YK04B'] = YusifovKucuk2004B
class UnitSphericalWrap180Representation(UnitSphericalRepresentation): attr_classes = OrderedDict([('lon', Longitude180), ('lat', Latitude)]) recommended_units = {'lon': u.deg, 'lat': u.deg}
def test_update(self): try: OrderedDict().update([('a', 1), ('b', 2)], None) # too many args assert False except TypeError: pass else: assert False pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)] od = OrderedDict() od.update(dict(pairs)) self.assertEqual(sorted(od.items()), pairs) # dict input od = OrderedDict() od.update(**dict(pairs)) self.assertEqual(sorted(od.items()), pairs) # kwds input od = OrderedDict() od.update(pairs) self.assertEqual(list(od.items()), pairs) # pairs input od = OrderedDict() od.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5) self.assertEqual(list(od.items()), pairs) # mixed input # Make sure that direct calls to update do not clear previous contents # add that updates items are not moved to the end d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) d.update([('e', 5), ('f', 6)], g=7, d=4) self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
class SphericalWrap180Representation(SphericalRepresentation): attr_classes = OrderedDict([('lon', Longitude180), ('lat', Latitude), ('distance', u.Quantity)]) recommended_units = {'lon': u.deg, 'lat': u.deg} _unit_representation = UnitSphericalWrap180Representation
'NBIN_PRD': 1, 'PHS_OFFS': 0, 'NBITS': 1, 'ZERO_OFF': 0, 'SIGNINT': 0, 'NSUBOFFS': 0, 'NCHAN': 1, 'CHAN_BW': 1, 'DM': 0, 'RM': 0, 'NCHNOFFS': 0, 'NSBLK': 1 } } Mark5B_header_parsers = OrderedDict() for k, v in (('sync_pattern', (0, 0, 32)), ('year', (1, 28, 4)), ('user', (1, 16, 12)), ('internal_tvg', (1, 15, 1)), ('frame_nr', (1, 0, 15)), ('bcd_jday', (2, 20, 12)), ('bcd_seconds', (2, 0, 20)), ('bcd_fraction', (3, 16, 16)), ('crcc', (3, 0, 16))): Mark5B_header_parsers[k] = make_parser(*v) ref_max = 16 ref_epochs = Time( ['{y:04d}-01-01'.format(y=2000 + ref) for ref in range(ref_max)], format='isot', scale='utc') class Mark5BFrameHeader(object):
def _dict_from_fits_header(self, file_name, input_summary=None, missing_marker=None): """ Construct a dictionary whose keys are the header keywords and values are a list of the values from this file and the input dictionary. Parameters ---------- file_name : str Name of FITS file. input_summary : dict Existing dictionary to which new values should be appended. Returns ------- file_table : astropy.table.Table """ from astropy.utils.compat.odict import OrderedDict def _add_val_to_dict(key, value, tbl_dict, n_prev): try: tbl_dict[key.lower()].append(value) except KeyError: tbl_dict[key.lower()] = [missing_marker] * n_previous tbl_dict[key.lower()].append(value) if input_summary is None: summary = OrderedDict() n_previous = 0 else: summary = input_summary n_previous = len(summary['file']) h = fits.getheader(file_name) assert 'file' not in h # Try opening header before this so that file name is only added if # file is valid FITS try: summary['file'].append(path.basename(file_name)) except KeyError: summary['file'] = [path.basename(file_name)] missing_in_this_file = [ k for k in summary if (k not in h and k != 'file') ] multi_entry_keys = {'comment': [], 'history': []} for k, v in six.iteritems(h): if k == '': continue if k.lower() in ['comment', 'history']: multi_entry_keys[k.lower()].append(str(v)) # Accumulate these in a separate dictionary until the # end to avoid adding multiple entries to summary. continue else: val = v _add_val_to_dict(k, val, summary, n_previous) for k, v in six.iteritems(multi_entry_keys): if v: joined = ','.join(v) _add_val_to_dict(k, joined, summary, n_previous) for missing in missing_in_this_file: summary[missing].append(missing_marker) return summary
The string in the colname is split in the name that will be used to look up the function in the function registry (``'mean'``) and the name of the band (``'36'``). For this reason, registered function names cannot contain underscores. Registered functions have to follow a convention on which inputs they accept:: def func([time],band1, band2, ..., [band1_err, band2_err ...]) All inputs will be numpy arrays. ``time = True / False`` controls if the time array is present, ``error = True / False`` if the uncertainties for each band are passed in. ``n_bands`` says how many bands are expected on input. ''' from astropy.utils.compat.odict import OrderedDict lc_funcs = OrderedDict() class LightcurveFunc(object): '''Wrap function for the lightcurve analysis function registry This wrapper is to be used for fucntions that operate on individual lightcurves. Functions in the registry of analysis function for lightcurves need some metadata for make sure that they can be called correctly, when :class:`atlas.YSOVAR_atlas` autogenerated columns in the table. This class warps a function and provides some metadata. This metadata includes: - The number of bands the function requires as input.
def main(srcdir, outfn, templateloc, verbose=True): from jinja2 import Environment, FileSystemLoader if verbose: print_ = lambda *args, **kwargs: print(*args, **kwargs) else: print_ = lambda *args, **kwargs: None #Prepare the jinja2 templating environment env = Environment(loader=FileSystemLoader(templateloc)) def prefix(a_list, pre): return [pre + '{0}'.format(an_element) for an_element in a_list] def postfix(a_list, post): return ['{0}'.format(an_element) + post for an_element in a_list] def surround(a_list, pre, post): return [pre + '{0}'.format(an_element) + post for an_element in a_list] env.filters['prefix'] = prefix env.filters['postfix'] = postfix env.filters['surround'] = surround erfa_c_in = env.get_template('core.c.templ') erfa_py_in = env.get_template('core.py.templ') #Extract all the ERFA function names from erfa.h if os.path.isdir(srcdir): erfahfn = os.path.join(srcdir, 'erfa.h') multifilserc = True else: erfahfn = os.path.join(os.path.split(srcdir)[0], 'erfa.h') multifilserc = False with open(erfahfn, "r") as f: erfa_h = f.read() funcs = OrderedDict() section_subsection_functions = re.findall('/\* (\w*)/(\w*) \*/\n(.*?)\n\n', erfa_h, flags=re.DOTALL | re.MULTILINE) for section, subsection, functions in section_subsection_functions: print_("{0}.{1}".format(section, subsection)) if section == "Astronomy": func_names = re.findall(' (\w+)\(.*?\);', functions, flags=re.DOTALL) for name in func_names: print_("{0}.{1}.{2}...".format(section, subsection, name)) if multifilserc: # easy because it just looks in the file itself funcs[name] = Function(name, srcdir) else: # Have to tell it to look for a declaration matching # the start of the header declaration, otherwise it # might find a *call* of the function instead of the # definition for line in functions.split('\n'): if name in line: # [:-1] is to remove trailing semicolon, and # splitting on '(' is because the header and # C files don't necessarily have to match # argument names and line-breaking or # whitespace match_line = line[:-1].split('(')[0] funcs[name] = Function(name, srcdir, match_line) break else: raise ValueError("A name for a C file wasn't " "found in the string that " "spawned it. This should be " "impossible!") funcs = list(funcs.values()) #Extract all the ERFA constants from erfam.h erfamhfn = os.path.join(srcdir, 'erfam.h') with open(erfamhfn, 'r') as f: erfa_m_h = f.read() constants = [] for chunk in erfa_m_h.split("\n\n"): result = re.findall("#define (ERFA_\w+?) (.+?)$", chunk, flags=re.DOTALL | re.MULTILINE) if result: doc = re.findall("/\* (.+?) \*/\n", chunk, flags=re.DOTALL) for (name, value) in result: constants.append(Constant(name, value, doc)) print_("Rendering template") erfa_c = erfa_c_in.render(funcs=funcs) erfa_py = erfa_py_in.render(funcs=funcs, constants=constants) if outfn is not None: outfn_c = os.path.splitext(outfn)[0] + ".c" print_("Saving to", outfn, 'and', outfn_c) with open(outfn, "w") as f: f.write(erfa_py) with open(outfn_c, "w") as f: f.write(erfa_c) print_("Done!") return erfa_c, erfa_py, funcs
def __init__(self, func, n_bands, error, time, name = '', default_colnames = [], default_colunits=[None], default_coldescriptions=None, other_cols = dict(), description = '', kwargs = {}): '''Wrap function for the lightcurve analysis function registry Parameters ---------- func : function or callable object This function will be called. n_bands : int Number of spectral bands required by this function. error : bool If ``True`` the uncertainties in each lightcurve band will be passed to the function. time : bool If ``True`` the observations times will be passed as first argument. name : string Set the name used to identify the function in the registry. Default is the name of the function. description : string One line description of the function. Default is the first line of the docstring of the function. default_colnames : list of strings Prefix used for naming auto-generated data columns in a :class:`YSOVAR_atlas`. All generated columns are of type ``np.float``; this is just a convenience, since most column are float columns. It is equally possible to define each column with its datatype explicitly in ``other_col``. The length of the list should equal the number of values returned by the function. If neither this keyword nor ``other_col``is set, it defaults to the name of the function. However, if the function returns more than on output value then this keyword is required. default_colunits : list of strings or None's Default unit for auto-generated data columns. If not set, the unit will be ``None``. default_coldescriptions : list of strings or None Default column description for auto-generated columns. Note that this will often be different from ``description``, e.g. when a function call generates more than one output value. Nevertheless, if this keyword is not set, the first column will have ``description`` and all further columns not receive a descriptive text. other_cols : Ordered dictionary This dictionary fullfills the same role as ``default_colname``, but if allows to specify ``{colname: dtype}`` pairs. If both ``default_colname`` and ``other_col`` are present, then the first values are assigned to the columns named in ``default_colname``. kwargs : dictionary This supplied keyword arguments that will be passed to ``func`` each time it is called, unless the keyword of the same name is passed when calling. Essentially, this provides a mechnism to easily freeze a keyword argument. ''' self.func = func self.n_bands = n_bands self.error = error self.time = time if name == '': self.name = func.__name__ else: self.name = name if '_' in name: raise ValueError('{0} contains an "_". This does not work for autogeneration of columns. Use name = name to speficy an alternative name.'.format(name)) if default_colnames == [] and other_cols == OrderedDict(): self.default_colnames = OrderedDict([[func.__name__, float]]) else: self.default_colnames = OrderedDict( zip(default_colnames, [float]*len(default_colnames))) self.default_colnames.update(other_cols) if description == '': # Find first non-empty line in description descr = func.__doc__.split('\n') # Just to safeguard for empty docstrings try: self.description = descr.pop(0).strip() while self.description == '': self.description = descr.pop(0).strip() except IndexError: pass else: self.description = description self.default_colunits = default_colunits self.default_coldescriptions = [self.description] if (default_coldescriptions is None) else default_coldescriptions self.kwargs = kwargs