#!/usr/bin/env python
# coding: utf-8
"""
we need to go deeper...
больше ящиков богу ящиков!
chce se ještě někam ukladat meta infa od blackboxů
K tomu využijme pitonovskej dak tajping a zkusíme strčit tohle mezi
f-modelem a normálním SampleBoxem. Snad to postačí.
Když ne - bude třeba šecko překopat.
(však do souboru CandyBox zatím nepůjde - k tomu je potřeba podpora Readeru.)
"""
# Nechce se mi tahnout do projektu Pandas jako rekuajred dependensi,
# ale ani já sam pořadně nerozumím proč
# asi proto, že se spíše jedná o pomocnou boční "sekondari" funkcionalitu
try:
import pandas as pd
except ImportError:
print("CandyBox: error of import Pandas. CandyBox will work in Pandas-free mode")
class CandyBox:
def __new__(cls, sample_object, df=None, **kwargs):
"""
Jedname tvrdě - není-li vstup konzistentní,
tak tenhle box vůbec nevytvaříme
"""
cb = super().__new__(cls)
cb.sampling_plan = sample_object
if df is not None:
cb.df = df
else:
# obalime čísly
for key in kwargs:
if not hasattr(kwargs[key], '__getitem__'):
kwargs[key] = (kwargs[key],)
try:
cb.df = pd.DataFrame(kwargs)
except NameError: # if there is no "pandas as pd"
cb.kwargs = kwargs
if cb.consistency_check():
return cb
else:
raise ValueError("Sample and given values hasn't the same length. Zkrátka, do sebe nepatří")
# def __str__(cb):
# # if pandas
# if 'df' in cb.__dict__:
# return 'CandyBox: %s' % cb.df
# # if not
# else:
# return 'CandyBox: %s' % cb.kwargs
def __repr__(cb):
# if pandas
if 'df' in cb.__dict__:
# df je na svědomi pandas
return 'CandyBox(%s, df=%s)' % (repr(cb.sampling_plan), repr(cb.df))
# if not
else:
return 'CandyBox(%s, **%s)' % (repr(cb.sampling_plan), repr(cb.kwargs))
def __len__(cb):
return len(cb.sampling_plan)
def __call__(cb, *args, **kwargs):
# Houston, we've got a problem...
# call meaning is different for underlaying f_models and upper Boxes
# but SampleBox will call in asssumption of f_model under
return cb.sampling_plan(*args, **kwargs)
def __getitem__(cb, slice):
# if pandas
if 'df' in cb.__dict__:
df = cb.df.iloc[slice]
# нельзя так просто взять и накраить DataFrame
# pandas zlobí (o kousek víc jak numpy)
if not isinstance(df, pd.DataFrame):
# pravděpodobně když se nám vrátí serie, tak bude interpretována jako sloup
# fakt mi nic spolehlivějšího nenapadá
df = pd.DataFrame(df).T
return CandyBox(cb.sampling_plan[slice], df=df)
# if not
else:
sliced_dict = dict()
for key in cb.kwargs:
# nechám na uživateli, co vloží do slovníku a jak to bude slajsiť
sliced_dict[key] = cb.kwargs[key][slice]
return CandyBox(cb.sampling_plan[slice], **sliced_dict)
def __getattr__(cb, attr):
# branime sa rekurzii
# defend against recursion
if attr == 'sampling_plan':
raise AttributeError
# hledáme obraceně
# nejdřív se zeptame f_model,
# teprve když ten nič nemá
# mrkneme atribut u sebe
try:
return getattr(cb.sampling_plan, attr)
except AttributeError:
return cb._lookup(attr)
def _lookup(cb, attr):
# if pandas
if 'df' in cb.__dict__:
if attr in cb.df:
return cb.df[attr]
else: # implicitně pandas hodí KeyError, kterej nechcem
raise AttributeError
# if not
elif attr in cb.kwargs:
value = cb.kwargs[attr]
if len(cb)==len(value):
return cb.kwargs[attr]
else:
# у нас есть дата, но мы их вам недадим)
# zde ať bude KeyError
raise KeyError("CandyBox: well, we have some data, but they are not consistent, so we haven't")
else: # implicitně slovníky (stejně jako pandas) hazej KeyError, kterej nechcem
raise AttributeError
def add_sample(cb, input):
"""
hlavní požadavek - jsou-li samply uspěšně sjednoceny,
tak ty blbé zbytky nesmejí mi hodit chybu!
котлеты - отдельно, мухи - отдельно
"""
# čo to je za vstup?
sweety_input = hasattr(input, 'sampling_plan')
#
# котлеты
#
# nechcu zde try-catch blok
if sweety_input:
cb.sampling_plan.add_sample(input.sampling_plan)
else:
cb.sampling_plan.add_sample(input)
# мухи
if sweety_input:
# if pandas
if 'df' in cb.__dict__:
#if 'df' in input.__dict__: # jen pro formu kontrola
# pandas musí mít i tamtenhle objekt, žejo?
cb.df = cb.df.append(input.df, ignore_index=True)
# if not
else:
# zjednodušený join
sample_len = len(cb.sampling_plan)
for key in cb.kwargs:
if key in input.kwargs:
cb.kwargs[key] = (*cb.kwargs[key], *input.kwargs[key])
else:
fill_len = sample_len - len(cb.kwargs[key])
full = (None for __ in range(fill_len))
cb.kwargs[key] = (*cb.kwargs[key], *full)
else: # nesladký vstup
sample_len = len(cb.sampling_plan)
# if pandas
if 'df' in cb.__dict__:
fill_len = sample_len - len(cb.df)
full_df = pd.DataFrame(index=range(fill_len))
cb.df = cb.df.append(full_df, ignore_index=True)
# if not
else:
for key in cb.kwargs:
fill_len = sample_len - len(cb.kwargs[key])
full = (None for __ in range(fill_len))
cb.kwargs[key] = (*cb.kwargs[key], *full)
# we'll see, if .new_sample will be needed
#def new_sample(cb, input): pass
def consistency_check(cb):
# řvat na celé město nebudeme
# if pandas
if 'df' in cb.__dict__:
return len(cb.sampling_plan)==len(cb.df)
# if not
else:
sample_len = len(cb.sampling_plan)
return all(sample_len == len(cb.kwargs[key]) for key in cb.kwargs)