def get_output(self, output: AutoOutput = AUTO) -> Optional[Class]: if Auto.is_defined(output) and not isinstance(output, LoggingLevel): return output if hasattr(self, 'get_logger'): logger = self.get_logger() if Auto.is_defined(logger): return logger elif Auto.is_auto(output): return print
def get_err_msg(cls, scale: Union[str, DynamicEnum] = '{}', available_scales=AUTO): list_available_scales = Auto.delayed_acquire(available_scales, cls.get_enum_items) if Auto.is_defined(list_available_scales): str_available_scales = ' or '.join(map(str, list_available_scales)) else: str_available_scales = '{}' return 'Expected time-scale {}, got {}'.format(str_available_scales, scale)
def get_year_and_week_from_week_abs(week_abs: int, min_year: Union[int, Auto] = AUTO) -> tuple: min_year = Auto.acquire(min_year, _min_year) delta_year = int(week_abs / WEEKS_IN_YEAR) year = min_year + delta_year week = week_abs - delta_year * WEEKS_IN_YEAR return year, week
def get_week_abs_from_year_and_week( year: int, week: int, min_year: Union[int, Auto] = AUTO, ) -> int: min_year = Auto.acquire(min_year, get_min_year()) week_abs = (year - min_year) * WEEKS_IN_YEAR + week return week_abs
def get_str_count(self, default: Optional[str] = '(iter)') -> Optional[str]: if hasattr(self, 'get_count'): count = self.get_count() else: count = None if Auto.is_defined(count): return str(count) else: return default
def get_year_start_monday(year: Union[int, Date], as_iso_date: AutoBool = True) -> Date: as_iso_date = Auto.delayed_acquire(as_iso_date, is_iso_date, year) if isinstance(year, int): year_start_date = PyDate(year=year, month=1, day=1) else: year_start_date = get_year_first_date(year, as_iso_date=as_iso_date) year_start_monday = year_start_date + timedelta( days=-year_start_date.weekday()) return to_date(year_start_monday, as_iso_date)
def get_month_first_date(d: Date, as_iso_date: AutoBool = AUTO) -> Date: as_iso_date = Auto.delayed_acquire(as_iso_date, is_iso_date, d) if as_iso_date: if not is_iso_date(d): d = to_date(as_iso_date=True) return d[:8] + '01' else: if not is_py_date(d): d = get_py_date(d) return PyDate(d.year, d.month, 1)
def get_date_from_day_abs( day_abs: int, min_date: Union[Date, Auto] = AUTO, as_iso_date: bool = True, ) -> Date: min_date = Auto.delayed_acquire(min_date, get_year_start_monday, get_min_year(), as_iso_date=as_iso_date) cur_date = get_shifted_date(min_date, days=day_abs) return cur_date
def get_rounded_date(d: Date, scale: DateScale, as_iso_date: AutoBool = AUTO) -> Date: scale = DateScale.convert(scale) as_iso_date = Auto.delayed_acquire(as_iso_date, is_iso_date, d) if scale == DateScale.Day: return to_date(d, as_iso_date=as_iso_date) elif scale == DateScale.Week: return get_monday_date(d, as_iso_date=as_iso_date) elif scale == DateScale.Month: return get_month_first_date(d, as_iso_date=as_iso_date) elif scale == DateScale.Year: return get_year_first_date(d, as_iso_date=as_iso_date) else: raise ValueError(DateScale.get_err_msg(scale))
def get_year_first_date(d: [Date, int], as_iso_date: AutoBool = True) -> Date: as_iso_date = Auto.delayed_acquire(as_iso_date, is_iso_date, d) if isinstance(d, int): if d > 1900: return get_date_from_year(d, as_iso_date=as_iso_date) else: return get_date_from_year_and_month(year=d, month=1, as_iso_date=as_iso_date) else: # isinstance(d, Date) year_no = get_year_from_date(d, decimal=False) iso_date = '{}-01-01'.format(year_no) if as_iso_date: return iso_date else: return get_date(iso_date)
def get_one_line_repr( self, str_meta: Union[str, Auto, None] = AUTO, max_len: int = JUPYTER_LINE_LEN, crop: str = CROP_SUFFIX, ) -> str: template = '{cls}({meta})' class_name = self.__class__.__name__ str_meta = Auto.delayed_acquire(str_meta, self.get_str_meta) one_line_repr = template.format(cls=class_name, meta=str_meta) full_line_len = len(one_line_repr) if full_line_len > max_len: exceeded_len = full_line_len + len(crop) - max_len str_meta = str_meta[:-exceeded_len] one_line_repr = template.format(cls=class_name, meta=str_meta + crop) return one_line_repr
def get_date_from_month_abs( month_abs: int, min_date: Union[Date, Auto] = AUTO, as_iso_date: bool = True, ) -> Date: if Auto.is_defined(min_date): min_year = get_year_from_date(min_date) else: min_year = get_min_year() year_delta = int((month_abs - 1) / MONTHS_IN_YEAR) year_no = min_year + year_delta month_no = month_abs - year_delta * MONTHS_IN_YEAR cur_date = get_date_from_year_and_month(year=year_no, month=month_no, as_iso_date=as_iso_date) return cur_date
def get_meta_records(self) -> Generator: init_defaults = self._get_init_defaults() for key, value in self.get_meta_items(): actual_type = type(value).__name__ expected_type = self._get_init_types().get(key) if hasattr(expected_type, '__name__'): expected_type = expected_type.__name__ else: expected_type = str(expected_type).replace('typing.', '') default = init_defaults.get(key) yield dict( key=key, value=self._get_value_repr(value), default=self._get_value_repr(default), actual_type=actual_type, expected_type=expected_type or '-', defined='-' if value == default else '+' if Auto.is_defined(value) else 'x', )
def output_line(self, line: str, output: AutoOutput = AUTO) -> None: if isinstance(output, LoggingLevel): logger_kwargs = dict(level=output) output = AUTO else: logger_kwargs = dict() if Auto.is_auto(output): if hasattr(self, 'log'): return self.log(msg=line, **logger_kwargs) else: output = self.get_output() if isinstance(output, Callable): return output(line) elif output: if hasattr(output, 'output_line'): return output.output_line(line) elif hasattr(output, 'log'): return output.log(msg=line, **logger_kwargs) else: raise TypeError('Expected Output, Logger or Auto, got {}'.format(output))
def get_data_description( self, count: int = DEFAULT_ROWS_COUNT, title: Optional[str] = 'Data:', max_len: int = JUPYTER_LINE_LEN, ) -> Generator: if title: yield title if hasattr(self, 'get_data_caption'): yield self.get_data_caption() if hasattr(self, 'get_data'): data = self.get_data() if data: shape_repr = self.get_shape_repr() if shape_repr: yield 'First {count} data items from {shape}:'.format(count=count, shape=shape_repr) if isinstance(data, dict): records = map( lambda i: dict(key=i[0], value=i[1], defined='+' if Auto.is_defined(i[1]) else '-'), data.items(), ) yield from self._get_columnar_lines( records, columns=DICT_DESCRIPTION_COLUMNS, count=count, max_len=max_len, ) elif isinstance(data, Iterable): for n, item in enumerate(data): if n >= count: break line = ' - ' + str(item) yield line[:max_len] elif isinstance(data, DescribeMixin) or hasattr(data, 'get_meta_description'): for line in data.get_meta_description(): yield line else: line = str(data) yield line[:max_len] else: yield '(data attribute is empty)' else: yield '(data attribute not found)'
def describe( self, show_header: bool = True, count: AutoCount = AUTO, comment: Optional[str] = None, depth: int = 1, output: AutoOutput = AUTO, as_dataframe: bool = Auto, **kwargs ): as_dataframe = Auto.acquire(as_dataframe, hasattr(self, 'show') or hasattr(self, 'show_example')) show_meta = show_header or not self.has_data() if show_header: for line in self.get_str_headers(): self.output_line(line, output=output) if comment: self.output_line(comment, output=output) if show_meta: for line in self.get_meta_description(): self.output_line(line, output=output) if self.has_data(): if not as_dataframe: self.output_blank_line(output=output) for line in self.get_data_description(count=count, **kwargs): self.output_line(line, output=output) elif depth > 0: for attribute, value in self.get_meta_items(): if isinstance(value, DescribeMixin) or hasattr(value, 'describe'): self.output_blank_line(output=output) self.output_line('{attribute}:'.format(attribute=attribute), output=output) value.describe(show_header=False, depth=depth - 1, output=output) if self.has_data() and as_dataframe: if hasattr(self, 'show_example'): return self.show_example(count=count, **kwargs) elif hasattr(self, 'show'): return self.show(count=count, **kwargs) else: raise AttributeError('{} does not support dataframe'.format(self))
def _get_columnar_lines( cls, records: Iterable, columns: Array, count: AutoCount = None, with_title: bool = True, prefix: str = PREFIX_VALUE, delimiter: str = ' ', max_len: int = JUPYTER_LINE_LEN, ) -> Generator: count = Auto.acquire(count, DEFAULT_ROWS_COUNT) formatter = cls._get_formatter(columns=columns, delimiter=delimiter) if with_title: column_names = cls._get_column_names(columns, ex=PREFIX_FIELD) title_record = cls._get_cropped_record(column_names, columns=columns, max_len=max_len, ex=PREFIX_FIELD) yield formatter.format(**{k: v.upper() for k, v in title_record.items()}) for n, r in enumerate(records): if count is not None and n >= count: break if prefix and PREFIX_FIELD not in r: r[PREFIX_FIELD] = prefix r = cls._get_cropped_record(r, columns=columns, max_len=max_len) yield formatter.format(**r)
def get_monday_date(d: Date, as_iso_date: AutoBool = AUTO) -> Date: cur_date = get_date(d) if not Auto.is_defined(as_iso_date): as_iso_date = is_iso_date(d) monday_date = cur_date + timedelta(days=-cur_date.weekday()) return to_date(monday_date, as_iso_date)
def get_year_from_week_abs(week_abs: int, min_year: Union[int, Auto] = AUTO) -> int: min_year = Auto.acquire(min_year, _min_year) delta_year = int(week_abs / WEEKS_IN_YEAR) return min_year + delta_year
def get_count_repr(self, default: str = '<iter>') -> str: count = self.get_str_count(default=default) if not Auto.is_defined(count): count = default return '{} items'.format(count)
def get_day_abs_from_date(d: Date, min_date: Union[Date, Auto] = AUTO) -> int: min_date = Auto.delayed_acquire(min_date, get_year_start_monday, get_min_year()) return get_days_between(min_date, d)