def _extract_neo_attrs_safe(obj, parents=True, child_first=True): """Given a neo object, return a dictionary of attributes and annotations. This is done in a manner that is safe for `pandas` indexes. Parameters ---------- obj : neo object parents : bool, optional Also include attributes and annotations from parent neo objects (if any). child_first : bool, optional If True (default True), values of child attributes are used over parent attributes in the event of a name conflict. If False, parent attributes are used. This parameter does nothing if `parents` is False. Returns ------- dict A dictionary where the keys are annotations or attribute names and the values are the corresponding annotation or attribute value. """ res = extract_neo_attrs(obj, skip_array=True, skip_none=True, parents=parents, child_first=child_first) for key, value in res.items(): res[key] = _convert_value_safe(value) key2 = _convert_value_safe(key) if key2 is not key: res[key2] = res.pop(key) return res