From 012b00950c7c43ae9bdbed8b31c4dad15dbf3f3a Mon Sep 17 00:00:00 2001
From: Timothe Jost <timothe.jost@wanadoo.fr>
Date: Sat, 7 Oct 2023 02:42:21 +0200
Subject: [PATCH] changes

---
 .coverage                                     | Bin 53248 -> 53248 bytes
 .../__pycache__/__init__.cpython-311.pyc      | Bin 335 -> 332 bytes
 .../__pycache__/examples.cpython-311.pyc      | Bin 1499 -> 1512 bytes
 pypelines/__pycache__/loggs.cpython-311.pyc   | Bin 3751 -> 3748 bytes
 .../__pycache__/multisession.cpython-311.pyc  | Bin 594 -> 591 bytes
 .../pickle_backend.cpython-311.pyc            | Bin 509 -> 506 bytes
 pypelines/__pycache__/pipe.cpython-311.pyc    | Bin 7382 -> 6924 bytes
 .../__pycache__/pipeline.cpython-311.pyc      | Bin 3277 -> 3274 bytes
 .../__pycache__/sessions.cpython-311.pyc      | Bin 0 -> 6248 bytes
 pypelines/__pycache__/step.cpython-311.pyc    | Bin 9543 -> 9923 bytes
 .../__pycache__/versions.cpython-311.pyc      | Bin 8168 -> 8411 bytes
 pypelines/disk.py                             | 132 ++++++++++++++++++
 pypelines/examples.py                         |  10 +-
 pypelines/pipe.py                             |  98 ++++++-------
 pypelines/pipeline.py                         |   3 -
 pypelines/sessions.py                         | 120 ++++++++++++++++
 pypelines/step.py                             |  84 +++++------
 pypelines/versions.py                         |   7 +-
 setup.py                                      |   2 +-
 tests/__pycache__/tests.cpython-311.pyc       | Bin 1696 -> 2021 bytes
 tests/instances.py                            |   9 --
 tests/tests.py                                |  12 +-
 22 files changed, 356 insertions(+), 121 deletions(-)
 create mode 100644 pypelines/__pycache__/sessions.cpython-311.pyc
 create mode 100644 pypelines/disk.py
 create mode 100644 pypelines/sessions.py
 delete mode 100644 tests/instances.py

diff --git a/.coverage b/.coverage
index ff754ea8b04db0e4bc7db8aee37126477feee56f..7f4cc21f0600cbe15bb35deaaf856e3f4f26e781 100644
GIT binary patch
delta 1590
zcmZozz}&Eac|sCX-j0na3+yGhc-AxUujY^9=j7YY7stoRyM;HNmy2ipW<i0;Jm!&H
zEDVk2&Q>v@#i>QbF(p~~#U;7<r7<q~$)&lec_qa$0hJ{g`FSz%@db&=*@@|?#qsem
z0h0~=L?>JL@|y>9vM@AildiwfSI#_`gIvABli&Dqn+LO#r{B;|&ODfnJiU#+!cN7h
z#l@NVdBu7KmEo)`42{O*cwcz(96x^Z02UU8Mpd%(+vnt`r-R(!&&<Nms7#g_lYRZ!
z&Hb6k({Jb}ZlzaH8O%s_NKXFh&o9Bnvw?ws4KFv}4!(Gv4gAr(Tlu*7xp)&c3kpo(
zF^ghpG-o8;Z?NRa6~fY}O@@9@^5i62FC=+#kf|S(JlV<Ai<UguB3K%Y$@0GN<T-Hy
zW`Qh?s^n>hr%sjtmPTdr%$V#O&tXQUc4*>c3TA24<|IA+H2Ml}{u<A(Ai>3-%E14V
z{}KOD{vG@q_-FC=@t5=G@~3VV6!7G)XX9dF<mBVZ;^1Uq<P_q(bBjlmgN2b(ha+s?
z%$X`v8yFZAJXskX7+AR2Sr|FR*fpj`F))g-u`qIKvHhw`+`j9)6<fmJ+xzRbv9Ym&
zjAG5;W?^CElwipbd%vUly)-imBc}y(+>_Vk(Vw>2KM-eQfPgCu3>>0N79hKr@=~|#
z+IHwQt6k#VX#t9!qO6Q8oSb}BTnr2hT>N_&_<!?%;eX5jjQ>9W4gQP#r}z)^@7XLU
Tuz;T(<PJtIuFZ$%+Zq4>tWqrX

delta 1476
zcmZozz}&Eac|sCX+N+Hz3+%->d0sN`uiy{iXW(1S=g<3{cRsH>&&$n%0_S<GVmMhC
z8f~4eVnT~ki;81HGIR4wGE!sw5{uLGD-+97{heb1it^J^i;FY!^YT)2VgeG2OHxaV
zVhSct^cS7{+lSvOjDv-t(U2@79DU`i!q_R$E<AaqFSk_~8`(xo^cQ!`$;?aDE2xZO
zWnpNvB-0<llUMlhTLrVQFf?kDYlKryetLSbUO{CLGYdnbCb`Bq7MG+JfJ|W`+mwm^
zQdVJ%WCyCFukhrr{`_K`Jg*q|SMqxBt>FvcdBq>f`-7j6cfn>sfeSpAu`G?YjAVHc
zmhL#iSsD$=GXj+EI4IE$Nq6kz8-bMW*rHh)Ey?wV@Z=S70+t~xjoM_J08e%-!7PoM
zWE%rZcFg3PGBIA-GK{6skdv%*;pi*8`D;ACf*2=%Ed&2g{)ha>_;>Pe<X_6)&)>>l
zyID{mnZKTmlZBC!k28ydgN2b(h~v&J9uamHMoumEZ)eY_tYl$fVDQx9U|>?<Vq;<C
z6l2p6jbLD8V+HA9)!=4fVdRux$q`a+kYJQ#W?|$sVUByE&EPOeMTOBpfdL8>#F$tZ
zIrW&f8SPqk<p!5N0|SH0Bn1~0PF6-1IZjT#DlP^F22TFN4E(?Ozwp21f5v~G{|5g>
T{!{#iHwy}^<llUFzO4ZO-HHLj

diff --git a/pypelines/__pycache__/__init__.cpython-311.pyc b/pypelines/__pycache__/__init__.cpython-311.pyc
index b7aa15ca9688d5596858b845778a2b66ee45ae48..8550abbac6f7ee0b29e5f4d402f453d9c6cdd4e9 100644
GIT binary patch
delta 73
zcmX@lbcTt0IWI340|Ns?&k?za+*6GFovmU*i&Kk=V@k5}i%W9zOJiK}lS^|`^Gb?i
d0xC-~^7CTi;|mg#vlG)(i{s;C0w!Lm1^|Qa8t?!B

delta 76
zcmX@Zbe@TOIWI340|NsCi@y9s?kT20&Q>v@#i>QbF(H|``6U^tF@A}~>G_q3WvTwo
gF#$#SX{p7<nfZBnsW~wLiNz(UrA09X6E9W+0D^TI=Kufz

diff --git a/pypelines/__pycache__/examples.cpython-311.pyc b/pypelines/__pycache__/examples.cpython-311.pyc
index 40848c1fb7dc11c2603a36056b8407268dd92f5e..780df463f25f93e2172633060d028bf9f416db06 100644
GIT binary patch
delta 196
zcmcc3{eqi!IWI340|NuY=fCo)g&TRj7>)d$tztrpQ;UjYO0x2cOLFr|V_fo+OLJ56
zN{V9wDoZl*^J3!T3lfvF6Vp?R<KtrjCigJjVq}@D%`DB#RKq;EmB~<n<rYhEYEIfM
z_Ttpy;>`TKA|VC_h9Y4G28Lo51_lO&$@R=)lOHj8AZhbtR+MHb5&@|b1rcB!lE^yp
V*~CB+Qk%api!d@OOy*?01OR-%H5UK?

delta 223
zcmaFCeVdziIWI340|NsCi@tnn{6=0cM$;f?tC-N@)S}{;kj&itl8n?Czr^D7{K~|#
zRDb7~fTH}g)Z*gI{Jgx>oS1;b;*!+TqL_loos75SnL!3YF^CPqpLrM<7^XASFxD_l
zZelVNW4^^woSKtXB*ehLP$bO2z)%cQHTg1A96{{?%!;DSMIs=LVBHdM-960tY@#4>
R$<2%`B8-gklf_ss0RXw3Fh>9Y

diff --git a/pypelines/__pycache__/loggs.cpython-311.pyc b/pypelines/__pycache__/loggs.cpython-311.pyc
index 25a687dceb042dab4bdeec568adea40eaabdaa34..59a5b8beef301a67600a51883a78eafa02fc3586 100644
GIT binary patch
delta 76
zcmZ23yF`|IIWI340|NuYlgn}&xo0vO`8Zp}gche36~~lh<rkOa=9k8}<R_QrrskCt
g#{^WCWaQ_?#K#vTCTAz6rxwS@#{_J?$#{+j0NIBd=Kufz

delta 79
zcmZ1?yIhugIWI340|NsCi@y9u?wO3H{?1l0p~b01#W5k7x%nj-sWE<u#p(H#iDjw&
j&M^T+`Dv-e#hLked8s)u0g1&Wsij3R1)Hxip5p-ky|5d1

diff --git a/pypelines/__pycache__/multisession.cpython-311.pyc b/pypelines/__pycache__/multisession.cpython-311.pyc
index a024fa8bec35026803c235c6a3f33f5577435152..8f189ac499e82d61dfcc199f78f3844e6fe17e9a 100644
GIT binary patch
delta 74
zcmcb_a-M~2IWI340|NuYe!YoYCyj!gtztrpQ;UjYO0x2cOLFr|V_fo+OLJ56N{V9w
eDoZl*^J3!T3lfvF6Vp?R<KtrjHghm~F#-Uipc&Ty

delta 77
zcmX@la*2g&IWI340|NsCi~dBelcr(LRxzQ)sYS&xA(^@PB^jwPeu>5D`IU)fss7F}
g0Y&*~sl~;a`FVM%IWYl=#U-hwMKJ}NSsA?;0lHioFaQ7m

diff --git a/pypelines/__pycache__/pickle_backend.cpython-311.pyc b/pypelines/__pycache__/pickle_backend.cpython-311.pyc
index 1c2d1ffebae72841ab748a80da5580b7f0e6b5e5..3b724cfb7ee20e8dbeae3727c4c62d0942f3a241 100644
GIT binary patch
delta 74
zcmey%{EL};IWI340|Ntt|82R6+?S0)ovmU*i&Kk=V@k5}i%W9zOJiK}lS^|`^Gb?i
e0xC-~^7CTi;|mg#vlG)(i{s;C0wxPHz5)QfO&cBn

delta 77
zcmeyx{Fj+~IWI340|NsCi@y9s?#reT&Q>v@#i>QbF(H|``6U^tF@A}~>G_q3WvTwo
hF#$#SX{p7<nfZBnsW~wLiNz(UrA09XlLZ)G0RYC>8#@31

diff --git a/pypelines/__pycache__/pipe.cpython-311.pyc b/pypelines/__pycache__/pipe.cpython-311.pyc
index d02f820c147218d4c27578979870148cf51a4628..245faedfbd79e61c050d0ce15c0ff7af4844816c 100644
GIT binary patch
literal 6924
zcmZ3^%ge>Uz`($2ppg1qn1SIjhy%l{P{!va3=9m@8B!Qh7;_kM8KW2(L2RZRrd;MI
zW-yyMhb5Oaij|Qeg(ZbGhb@;qiXF^m%i)OPNMT7~&*9AFisH)Uj^fVciQ>uSjpEJa
zi{fKsNaZVHOJPXi$l=cwh!S9AU}A7*Na1W@Na0EqT*l16u$md_28JjhupD;_Lkdr-
z&>CJeS>Y76U<OUTmy8Sy44RC$IGhrTQ-e!V3p5#TNr2eCr8y;;#i_-`nfZB+$;qk3
z#rZ{=jJMc>Awn-f)@U-`Vl6L9EGYKVWWB}VoS2i7n3R)xizTG8AoUi9XGv-in9mVV
zlwXpcoS$=xHzYE^HQw37)!EzA&s~%877xg(fXsr_oXot`WRRIK3=U-m28PcQ7#JAZ
z8KyI&GDI<^Fhnt>Fs3r6Fr~7jFsHJnGE2hLGo-MjvZb)5GN*BMFr+c2u(j|+vEx^p
z!k)&J!qLJK#gWRH!kNkiHkB)tC51JWD~%(CyM<*L0|UcqxD8R<9SjwWQ9Qv6nmo67
zL9X^qElEtyNh~hD#hjc|e2cRnvmiA-FEKau7Hd*sacc1`uEdg(qRgbylGNf`Y(=Rh
zrA2wkEN}xE7}yvX7(g-h*@uCFVJhQvh7wSGKoy|cz5q!Es(^ukp@yM`v4*LJc^L}>
z!)mz6!3--I{WO_wu@;vWq!!&`kB`qwEsu}aWGxb4U|=W`1Q9|YLYRSp;TC6nJlGTQ
z@x`DNte~Kv(D2LK*(xTqIJKxarX(xBxFk2fG{z-AximL5ucSC8pt2+*KQAUez92C<
zJ25@AI6gimpb`>`#W4j4R%St}UO{D%1Oo#@l_*Mx=|SDZ&%nS?EYHBe@S}m@F26`;
zc~5zNeOLXA;su^7N;hO(<afNn?|6a3@iWNJe%J%=9yq%p2VD(A3S%Y%YLc&IsbR(*
zh^PVW!Vqg3!^FT)%Ua8ZVkTP(QwlSxnMLv?@IYr^SOAJjkULRu4O<Ok4J)d?8kQPX
z8wLi39<vfogkq4ZYgkZKf{Ke^22B>fTdc(;sRhNi*fWdcK`b{-)?4i9sU@Hkc8fK$
zBsI6V2o#vNL_o6f<(VZJ@gO;9>SHg4DAi=gmIjJsK?#8coOC%6y4V>Q7(mHEK|!HN
z3Z#M~K0Y%qvm`#gN(?<VA>yD^Rb0owz|g?(R6u+N^9=U|P8S8#uL!7jus)F2ye_YQ
zNnZb=yx|pj!w(EhobikhveUoAWrF5iez6Ia3p7`RUgS5v!f*V6fsr?!@vfZqbvcJi
zat;S1PefjbjJ+rqcSSC40_%j7iQGS)a_~=Jp5Q*i^&*GT6%M5fFjOQBaxDueByMqn
zNN}!9Mvfm)QU~!rdtpsIHH_%-fRYv%QkZI(&{fnh1T$zd`$6)TI=EmhQUX!TMQWhj
z2F`aN@nVq0us|(R1mzAT)bIqm87&TFKv_i>9JXKC7&rwcuuRBaV0n>4_X>yZ1rFW2
z9Q<e^5BP;UxWPf8$$N_<9vlYo@wd3*<8$*<N^?@<<8SfA#}}3+=71tTKE8+(6l%=H
zB}GM`;`bIyN@j8iIP(^%f@FA#OA<>mlXFu`GV)W3Kz;zb{T45@07*{G$%&8GWGn)e
z%Eh4a$^o2g!08f9@PfSX8j{-^7$EQi3nQx&<AjtC3?O<1Glbp{u_I+m9E5!#C=AMo
zj)yP^kZc^R$`eXHFmSLcuMh@P8!~p3Y{>&NF9e4}=$HgBjZTO#unB!&Vr3Os;PHWh
zl~rViGMGAH45lswM}uhu@sXK<O{gUXtOX&8V1Xk5?0b|74wSb*S^x7aaQZ`3Z&A!C
zOi?VUtWj*K>`@#kqABbxEK!``N{I<vU2%gd{3xCju2ilR)>PIs7Eo0c#hW6Q!kfwm
z72#`PjpB!j@Tan-u%@u3v84#Kuto_WMAKMO1Y2061XF}kh0>T(gj-mmgrRJa7M3Ux
za1%is(l!7k&k(m;`~`_csd**wpqdU;XBUBDv`B=3fx$1C3FI9p2Kf$@Kt6wA0yTwd
z7#2V!P^lV*WsD3At3gQxEK$P{k6<&_FvP>ntYOFknFm&t1ut`J7~(<s7%W->atfFQ
zsur{0;;1$-GL(QyNrXBMC=<;kDU8`*TZ-gs7_vb50<5e^qC^zT023)pH4F%QW;3KP
z&t*ont%<RQAq#H90&cK2Gy<dc@dejDOts7<pnL>XUBghrw2X;?VKqENYFTO+79jZ<
zsu0{L$bze?VW?rLVM1*l)UwpDAiJxE2~-!Afa(CKAt2i@YoZ=Ml(2{`0oB`Z9Z3EJ
zwKAaM2nyAosNs~tg77NTb#NbKfr?GAG035f>0)F*BVq;97by(Epk@;TLOq2xptUog
zH8!hX5y%Tw-p+}6dHE#@#i=C<#hH2OIjP|4TcIRhA*84@RUtD?p)$Wzp(r&yv$!O+
zC^bbPH@_%Vp(G<QPa!`qRRL5JC}idpXQreoRIw?5TWUq1cB7`yEumbbRyw2+cZ&yE
z>=p++qk;msNE22K-C`{$%FHXd#hjCx2dVtIksNo6D=aamG}X1JD8Hyk0i*{M)3>-l
zZh=?>uGem{<YX3?++r&ODK5Un3bLzMll2x$acWLlkr7BAsJ6Ss7!R)h;H^tYV**^K
zR0+a*0D7>dg&wGms9^*(As)ymT$eGvBxAh6<)Vz`6&cG8mMa{RHzd?MSbBJGNXpKU
zyCP}O!P3KbmxH$>r6=zqhwK#&*$W)9Pr3OzN_wg~?R)HJ1YY8nyTC2Cz~qXu@da+V
zyFxM_7#QT7m@Z`JU&*e7u#w4+3=G1~Okcp{2L=XSXQmH446=%IyspdWT$0hbD5G~p
zM(+ay3#T@i==ACEoKSdISZapJ0?muUI#+~sI$UlDi%++oWWT^<iR}iJ9V|OCFA95H
z5%%bCxuK%b;nL$Zq4FY+;$0r$2`)1<7ld5o(YnH;bpeb%urcrmT;Z1fz`(|7c~@9`
z2Fo0->k^umBs4EdXkU@ghS;zo@QSd0hszBkvksRY-zz-w3s{!$UF6XR8#%>yfyolP
z4JH?PEUxfaT!5hmq$mbgTFLOT7}Vp1byYmT^;HU}WCQ0)5RnB}nZg80Xdp2Lq#On+
z8<9)!*$gQxb6JBKG+F(AG1`EW^DjodDjo$;HRGR@m6}{)r^y0tM}WE~;LcQhJR<pO
zG8Wl`k_pIKNNNJLZ;Db2isIu@k`zS98>ChX+;Y0XA2z{cirp1q?G=t!g!Qfnn_u7$
zyTBi|LuHR1gaslw!XN<vuX3QC2k}2!fdin1Aq(P51_lP~-HIAU)IttYFcgU~FfeE`
z6`6rrRHEsrCGkb6g{7HAsi3Y^d~r!)a<(Qj*mp(hASJwM`K5U&@nxw+psqMd%kdUp
zd~!x=ayCq|N*s}yP$c|7{s-mb28Iu844k|@yw^FjFL7wE@Vv-jc7?<20t|tDeTxrj
zS$uIxQD$B`O2rNead0SrilFHXDU87knoNmFObiU3B?{%4IXMbRsS3%7IXS5*prWlL
zBUK@}v<TE@P=K1MkeHXEkdj%P4HrnsR{)iexrrso8C=l*h60=sl95@gkXD+PT#}ie
zrvT|h7emU<wEQ9ke{UUd0h*kcr;wAMn4(YuQeTo<prepkqL5jvkf>0Wn3I_TDol0Y
zhUOP3xFzNkrz(Jq$jjFOI{>B<>QIQed8w%>pu)N+H7Bt&FF8X2<Rxg76)PlXBxdF*
zfQmtgn)KAX)S|?aRE4yn{9LfooW$Z1NFiR5kyxToo>;7qnWq3M+~EPB#|3wnXBt=&
zO7MXFke8pQkdj(Zl$xAal9~b!Ix9ptfdWof0UYm;kWYl#3(}vIUk0jEFd{<-92=Q=
zp!%jnAvv))RR<-Abre!Tp#%$caF`L}Tx?E-dlKT(l+2>k<dU39g`(7=(!64@zp;cX
zl5Kt~K^X^>@ryv6wqj8I3hSAQW~QX(m1L$>#)HBRo+ISoIRdMEFeqbyQZl3~0!jW1
zx7eWrUnm_$^pwvK%mB{IMWC@8SeEq%Wm(qLijty4)U3)0b{41ttrCK}2`-ihatEl*
z+`s_pw3UDz0<JWZ;q6!k1_u02V1<+#U?=dVl;#$sro`ui%TlmOMS&noK*oW>A6ja1
zrDcK|B#C9IMODIZcOeARKzbk!yTQTT!3=g7$|wxFo4^G^)n%Xj#1v580~rNPT=_*s
zsl^5Pc`3!9yaLKbpaz2uIO0J815Sz{;ncF!ypqzy99SxcCmd+<NKw$pOatdBz0%@T
zSX_hhI=DpzDqle6=|S_cf~_ss4j4BdlE=U<%Lk?WRE3nH%(7HXxINHZ2-A>R3@#r0
zATiB?2xg>k1$7oc;R^2X-r@!s9uF#xQj4lYP{S1>nh6S6P`{#q;R6Q)Cl54eZ*jm%
zI((&W4I^^eTge1*Q3S|H<UGNZl382;DpXM-7a^Dr8efG(?gM`D4t_}Ff=qzbY-o{-
zYHv{#x`q4&MXB*crFrq7QQ?BrqAKuEGN?}1Lz5{6H4bAy1Zbp2lLgXR1odVhok>l`
zB2cBJDGI6cL3MYLHYjiLAjNobktN6kP<2#f4Pt>Jp~wWp0*zM`>3~?SAi@(w_<{&f
z`Y#Fsu|h#aIEVms(2Al#tT+$>%Fp1S0LNvKAxI2FsDQld3~rc0ii-w@4_pi)5)D2#
zgv1-XZwN{@c-@dRyuc#%fkm3t@&f}ZVa3QA&NxFEG;|Tph=pWhW;Or704KP3Sa~)C
ze_-HY<=GJdrqBr)W>y}M2A&1#U}}d3m_jGG7(vPyS$P(igKXtFpaG^XK*mydz#Jrk
zjRmBfg_UQ4`v(RVR-O$WU<#e!VPcg44UjOgN_=2IB{-N^C01aFqAG%fFDO(s8E<js
z!p6}xMIc!U9Hpk9fCokCEe>dTTwDZ-zFVB&Jd&TEQ(Oc}y|>si^NI^nlS^)~l~fjF
z=A{>bBNUXmz~fj&pl){&56Co7qYFG_af_v-vLF>aDg%jN)JXruVFMW=vnv9XfS_zp
z%)!XO@PV0;k?{tD^aWIOgTeR$D!RcScL5bWK-F@ALHY&*UjrCEU~suW9D2Yk@PUDm
zQT+ys+67effkl*2<O2gHF~Q{{Nc0PcfXM3wGBQehV8Bk!u!YEc1j~N`lMoSP5*&R1
D%H?4n

literal 7382
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
Y`M`jkoM8)*`3RQ(0wy6M$Rs#M0r-ht1ONa4

diff --git a/pypelines/__pycache__/pipeline.cpython-311.pyc b/pypelines/__pycache__/pipeline.cpython-311.pyc
index 854f3a0b5c624ba6e57eb6f8036e18b925426a02..caf0bc1b20115b3044272f07dc526daaa7680c37 100644
GIT binary patch
delta 76
zcmX>rc}kLdIWI340|Nttz$v+n+=@&_{?1l0p~b01#W5vW`Nbu<`K2)~`N^fZsd**E
fF#(k&8TolJ@$m(T$=QkNsm1Z}F#($snR2)Qnk*Ur

delta 79
zcmX>lc~+8pIWI340|NsCi@y9uZbc^3AZM$X(Bjmh;+T-k-29S^)EK|S;`IE=#IjU>
i=a_(^{It~K;>`TKywseSfW+dG)Y77ug3WPEIa~m=9~x``

diff --git a/pypelines/__pycache__/sessions.cpython-311.pyc b/pypelines/__pycache__/sessions.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..124a23a8ee19395a2d1085bb47e2163257425ff2
GIT binary patch
literal 6248
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

literal 0
HcmV?d00001

diff --git a/pypelines/__pycache__/step.cpython-311.pyc b/pypelines/__pycache__/step.cpython-311.pyc
index e61d01184b005bb1eb8e4676f5a31a89bbba6c4c..c4d11c73dbea1bb430c7db0000641c7f854d66ed 100644
GIT binary patch
delta 4559
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
KDuFB@7XScfNl$42

delta 4235
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%0An
z5U%B@VP3!iQf4kd&}hNAET}GJWT@eoyjN6TS%{!s;mQ1B=9VG^)rn%-!NkzXIk{d;
zlu>N+R54pdM!(HB#V<2TR0+6c=A<g5R%8~J6f30V7bz5hs-Rnw&q?Y|{v#>PzLK#h
zn1O*|vbfZ#dT;^911>U>Gg6bYQ;TkKg35&W%)GSxB2c}1i!~)RsWiRF8I%>+J^fva
zit>vzxo`0oLmHFuDXArinK{LXTyu*pCqF$swFqp>Eso;s%z}c<y!4__Py!AE8N*hT
zT3nh_Qsi$25(3xgpm+zh6u=mig+S_9K$UBiI-=SDIW03UeX_lv7+Vx5E96c-D6P-Q
za#2M0iimE9>tr68rR=O175uI!_)Xp?Q^z4|bWt|oifq7Sci9*95)({j@Lv$NT%mG7
z*b;&^s6prpJeI|vR_YN(M;2E$hNEnTu2#%PEg4;{n2SJJYb7%zCxY^HQ98(GQ2vDH
zK~S+*g}eF$`MlW15!Cqo(ZKMPi-C*3qoh;1NBRSk9jDa?2228!Aw^;G4onOJA|2dC
z0+S5|5+_H>^KgM0R`Q^Bg~#N4`L@Z53KGUFXbG5=iJ_Cdh9RA?hH(*N5JM(I4bu|F
zKE_(M8iq!N8rCA&PL9br3W~gJH4HT@Ygm^tGcc@Xo;*iE)s3x_BZ~u+2|#!@Lkjy`
zW{l*`7R;c@;dhG{RNcjc+KHgXBRIl~!WkGCLW&|L^C-sEM}p!P6j4RdAXW^Bhy@X#
zbXNrG{@h|OPb|s<B@a+y)8s4ywd@gTsVD`c8kAg%vO%mg5CM(^aH;_{mcc0oRPKWN
z9pK2RQiCKJuG9ipYYd!Z=7S>c@MJY5%gIGbLcSl^7{sI|gv`*tAZoqB<$|a+1Z{AG
z&>e0!_~kC}Yuyl5_`tv<7|8fQL}H5PbrG#gB3diVHrSs~y&$4>Q6%7sNWcY=fXNq?
z^aDWE6ga&Ufx05aC}{*#E8=b?&ILIQRR4gA@28x6kn}M*R#{dYoDPIIr9NmtlK}$*
zgP$h<<cZ2E^+llWWRWH)R6tc5q}2jSjYXhFNRbjq0#v>hfhzeTP+JL7V}s%sT-_Cc
zoeb)+6@gmkU;>m8iWwO}E!GAG2>igp&#L}`0Zu3}vTA)`V4NJSB3;kO8q4^B0f}To
zVnf8)7+Lv2N}vQAGpp(c1~|dR$Z8Lgg%WIxtd3v<;UpV3E8hnOI3dHzD*k~1MreHC
zb7N!`SrGAo0YqaV1DM2FMHYBW=2evx{J<d2DgyB|$iJH0lZ{l>?Lq1E7F$UrxSRrq
v4JZu2fq@oEzc_4i^HWN5QtgV085kHql~eKJ$p=(Jn51MT=cxs<fWi|1*0RH#

diff --git a/pypelines/__pycache__/versions.cpython-311.pyc b/pypelines/__pycache__/versions.cpython-311.pyc
index 71ec6deb30e45d6dcaea734234554b8054ce6f31..5fbe64984c9967bf7beedd4b37399cafcfd2eebc 100644
GIT binary patch
delta 2034
zcmaE1f7_97IWI340|Ntt6Qe?EvfxBM3C3d+)h#Vj7*d#X*mF6eIC43oICHt8xN^Cp
zxN~`;co-Q{d5YLlSW;MXcysxp_!t>d8JQT|8B*9<7*g0L=E&CbgSi|n3@Mz;m>3vV
zGl9$p;V1#H3|9+73U{i&GG+#b)yyDq5RMW|VG3r@<ar6=Xfod7Oi3(BOwLIxF80%8
zy~W|2n3I#3l#_akC8V+-^%jR`Noo<8&k<0RUy`4kpL2^hBr?D?-q}Ok)!EzA&;2DM
z0|SF5<1G%S#NyQ8lGK8YH)R-I`571(Rx;jVDNfBvD+Z}h_~q|x6%$&VT2vfUl9gXv
zlAB)|<C33Tnwy$eQXCUdS(1^T7ZV>}keHmEn4Vf3A0HDi*_KJ3QE+lBlQ<*)<Wi<o
zF(C#9h9Y4G1_p?cMWP_S<m3-bQc@t%&mdbH7#{Eo_f*fYzrwG5fkV4UY;qry<>Xjq
zemAVTWf&M3sszJQi;6Sz^Yn^KQVZhq5_40<L6#sJXMKfV{Q`$N)VSBo!q!-glLHwi
z3NtRbC^fMpGe0jrC9xz`8su0h5Fs|%lEs2o0>lIvqRCVwGP#aLj!|^-To!W`d63m2
z3=9kn3^&v*I#_zRC-`6FP`Lm`MPdvL49Sd>?O3EH3$e<I3Bn9P36{yOtcr|Elhavc
z8O0{o^Gi;i$0{Yr2T}?OCRpH2KFKO8q6)H&6Ji^`a8G#$Uy<14U#x+aV3Q?5dO$%`
z1oBvsB8aODBGf?f%K&x_Bo=r;q9B5Eatqr<1&}j~K-^?dI)h;rDC2X`<WhDkS@sl;
z6qZ!ZG?o<37M3Wk6rL3B7M3XP6s}+fP2R~T*h39LuG3_^#Zr)2kgCa21PYZRQw9cx
zTP%r1>BYC$vdckqG00p61qFp7(aC-sS`s=SKk-8RBqGtl(!<%o*}+*PHhBWacV3W}
zU`E+ap2DfZC^~s3rwgP0=6{?b%#0$Fg?Tj?MJL<v1~Xbtp1_;T4fcv5$a^l6|M6y<
zgB)>-Bds(q85Ffe-XQ0&6{Y6pm!%eYf;h}Ysky~$3=9k)CxILV(rYt$0iPzL`Q%f4
zTflLmA`S9ekse46IZ{9dh)pgK7n^*AUt7kPfq~&OJH#g(+#Sr20JjBc;+iZdprQ;n
z1eAzC!XUX~P)Pu@*lKcwfEITENG=*gh)wPlP~}C@H+jE+D5L1)s{$tV!5}3Nb)am`
zROHCOz~HCJQ=|@(&;SvdAi@VkSbzuz5TOMkY(PX5hyX==krjv)4<f*x1P3EH!y16Z
zKm^FR;#FYZH86nT<PO1f4z3RjjI2Bx$|rviG-d;9GngFBF1guBD3FoSV)7JW3pP+3
z6q!!GB&^H^Hqv79Z(#+-sL3)SaS$Djn;S$nGcv|aHW6Ft90alu>@$!%Z?P36=B4E4
z7KMPqnys_|lsSt+L29x<A}radmBqKX!V+^zQ(cRS@{2UtibN(Wh)XD>fTTI{Qp@8r
z5{ol1qBv@Dgt#7K!sK@GBaC93eI#Bpa>PLbF>bQGltvuL^dfLBv<4Z(1uATc<5Mz|
zOKvfzr<N3fQfyH%$Q_`92bM-bMikkBH1MXTWR|3+#OEhvr6!jkC3=vS_{m45R2lO&
zzm|H<$f!E`x{Ry|D3ES(fU-_bW?m}9cu?jk0%vG&LP1ZZ*^@P7H5jWV2g=49fI?oA
z3q9fsK$d|c9u$^E;OGWNa`xm0vZ7MCpsWWf?;Rk;LLx{xhzOg^FV|WRGP4N8)fBqL
z4X=4pi;F<@QxQ0xia<KjK?ErA7rB9a&Q?-ckeQcW1j^?{tROj%!;3%}qlg2<1$m|j
zRKJ4DoFY)-0$T&gUtn87=|t=ohfQvNN@-52T~Q|k0|UsR#p;Zc|H*|pGq_wJ4n1HN
X_`tx(sBnWt{sJnR94tSP1!NfjruM$~

delta 1840
zcmccZ_`;rVIWI340|Ns??M%7U8v+ygBp7E+RJRmLWn^M-XGmdgVMt+F#>Bv|nrX75
zuvlOeJ6M>tg&~CvA`H?C!ciPx8TJ;26pmDmWy}l=tC>OKARNV+!W7J)$@vn*(PX^E
znUYwNn4FVXT<o{mn^A_*gM)#AVI|`&mg3Z$v|>gE1_p&+LC#h&p~b01#W5k7x%nj-
zsWE<u#p(H#iDjw&&M^T+`Dv-e#hLked8s)u0g1&Wsij3R1(Vk>$xDK~QzaCZS_G2T
zOGzy#N=;5INloFJ{Ddi0jGKXhp@@fpfdOJq5g&*zG&!DGN(#jM%+J8U(7^D3U%01w
zhW!<O?F$^*Mf{T$S!^d?VCKfITXgbAW-%!tkeSH3t*`K_U*J#&>-Mq6YOgp014ET4
z%&Eymsfi_-`FZgvi6yCGAa@Ca2>!_{SS)x2K}?V#noLE!li#w)G4f63VKrBg0$D2p
zcJvK(iw>3^?g{=EIaDryQ4z>J$&8cNvPeyCWR(>I1x*pi5R?#@yoFU!MHa~%6%DXC
zJ{LI@FMtuu905U*$-Hb*g6ts2AP3@P3pQC11&|S(5U219_mp?=74c8bWDB$eTMG)G
zB2kb=kgtnC?k<u6apggg&j7Xp5*w@_Q4qm0`7_%^Hjp2RSSPO)l4SIo{Dj>~k|mWh
zjVXn_g(ZqBg)4=#g(ZqRg(H|jlY6o?N2sA30|SF5<1Lng%z{)+mLgt|VR{S<47XSk
zi_(j4v1ONo=wcR7DpOEUDB_!ZkV8vC9prY9+6IOjA`%@eJ)9k!9h^n{lbJcc^MafX
zGs<i-JC_P0-((#w7e=kkg<K-cjJ%WEcr_ULCa>oWW;B`1%$Lj!cCr@8X4}byeA(t8
zgKu%9mF6Xb;<v~J<Q%r5)ZF~C)FLMkhq)*<x0ns;B#@&(dQB$_^J_91O}6FV0uF>^
z#>oPL@?szl7J=N08i_grZbBXm3=E$^k<-9%gM+(+xrl#qpMZ)oTn8xafJ`<6`IZT6
z9VEz&CtnrN;`av0g@6c<2mB^a6i~#_dyAtClCz47VFpYN5;Upz18IZn)nqENVqjqK
z)8r`vrHUd&kgO7ja0L;DAi@$vD1!)75D^R_K(StA3}Quq2(T|fZh^Q`6C?&AK)Q+-
zgHu`q0~k(b6-sARpIjnj3=XOy&CP3tvKSc+CrgM}uz`ZVNN;kOh%y@}j~5wEt`|{Y
z44u3{Bo3n5YBP)IW=6*F$vebW#(+b?2V@n<np<o|iFqmcxkbL9cw#Fp0A<c1uy2z=
zA}radmBqKX!V+^zQ(cRS@{2Utz-jIlPi|sGd}2vSYHmSE@h!&8Ta39yv6J_TOG4Zb
zJo%2e9%J-mZiyp|{F^UGyk_JG2c=x5qVUOwr8JU3h8KaNvd9Ev4OekVYC&;)N@jA&
zE#~ypk|I!IDarx45>$A?QYXlWB6E-i-qe)LlGK#={G_bZ<PxOh4$=Y&+$x3155<Ki
zR|@hnW^T@xe$B`zH#u5X)&vw-w>Ut#Cnqy66=Dx4|3LCCIOTxsRsaJ?yrfKCBdft!
zI{B(>d^{+&G`Y}YJriUrIMzX7S_F=3kRysxz;2C?2iFG4sX00E@tTZ9X`u88ss|h(
z7DR!xgNVS%ljT~oKz0;?xSCwIxZ!n4YH<;$#wh~FUp7cb0*G(}5%wSgoVY;A2do#8
qg}_FE62&hLo80`A(wtPgqDBS=29V{&j~OPfl@FWjt}uZGqz(YjN{HwH

diff --git a/pypelines/disk.py b/pypelines/disk.py
new file mode 100644
index 0000000..cfd1cfb
--- /dev/null
+++ b/pypelines/disk.py
@@ -0,0 +1,132 @@
+import os
+from . sessions import Session
+
+from typing import Callable, Type, Iterable, Protocol, TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from .step import BaseStep
+
+class OutputData(Protocol):
+    """Can be a mapping, iterable, single element, or None.
+
+    This class is defined for typehints, and is not a real class useable at runtime"""
+
+class BaseDiskObject :
+
+    disk_version = None
+    disk_step = None
+
+    def __init__(self, session : Session, step : BaseStep, extra = "") -> None :
+
+        self.step = None
+        self.session = session
+        self.step = step
+        self.extra = extra
+
+        self.check_disk()
+
+    def check_disk(self):
+        """sets self.disk_version and self.disk_step"""
+        ...
+
+    def save(self, object):
+        ...
+
+    def load(self) -> OutputData:
+        ...
+
+    def step_exist(self, session : Session):
+        """returns True if the file(s) found had a stamp corresponding to the current step. False otherwise"""
+        return self.step == self.disk_step
+
+    def version_exist(self, session : Session):
+        """returns True if the file found had a stamp for that step corresponding to the current version. False otherwise""" 
+        return self.step.version == self.disk_version
+    
+
+class PickleObject(BaseDiskObject) :
+
+    collection = ["preprocessing_saves"] #collection a.k.a subfolders in the session.path before the file itself
+    file_prefix = "preproc_data"
+    extension = "pickle"
+    current_suffixes = ""
+
+    def make_file_prefix_path(self):
+        prefix_path = self.file_prefix + "." + self.step.pipe_name
+        rigid_pattern = self.file_prefix
+
+        pattern = ""
+
+        if self.step.pipe.single_step :
+            pass
+
+        if self.step.use_version :
+            pass
+
+
+        flexible_pattern = self.f
+
+    def check_disk(self):
+        search_path = os.path.join(self.session.path, self.collection)
+        
+
+    def save(self, object):
+        ...
+
+    def load(self) -> OutputData:
+        ...
+
+
+import natsort
+from . import extract
+
+def files(input_path, re_pattern = None, relative = False,levels = -1, get = "files", parts = "all", sort = True):
+    """
+    Get full path of files from all folders under the ``input_path`` (including itself).
+    Can return specific files with optionnal conditions 
+    Args:
+        input_path (str): A valid path to a folder. 
+            This folder is used as the root to return files found 
+            (possible condition selection by giving to re_callback a function taking a regexp pattern and a string as argument, an returning a boolean).
+    Returns:
+        list: List of the file fullpaths found under ``input_path`` folder and subfolders.
+    """
+    #if levels = -1, we get  everything whatever the depth (at least up to 32767 subfolders, but this should be fine...)
+
+    if levels == -1 :
+        levels = 32767
+    current_level = 0
+    output_list = []
+    
+    def _recursive_search(_input_path):
+        nonlocal current_level
+        for subdir in os.listdir(_input_path):
+            fullpath = os.path.join(_input_path,subdir)
+            if os.path.isfile(fullpath): 
+                if (get == "all" or get == "files") and (re_pattern is None or extract.qregexp(re_pattern,fullpath)):
+                    output_list.append(os.path.normpath(fullpath))
+                    
+            else :
+                if (get == "all" or get == "dirs" or get == "folders") and (re_pattern is None or extract.qregexp(re_pattern,fullpath)):
+                    output_list.append(os.path.normpath(fullpath))
+                if current_level < levels:
+                    current_level += 1 
+                    _recursive_search(fullpath)
+        current_level -= 1
+        
+    if os.path.isfile(input_path):
+        raise ValueError(f"Can only list files in a directory. A file was given : {input_path}")
+ 
+    _recursive_search(input_path)
+    
+    if relative :
+        output_list = [os.path.relpath(file,start = input_path) for file in output_list]
+    if parts == "name" :
+        output_list = [os.path.basename(file) for file in output_list]
+    if sort :
+        output_list = natsort.natsorted(output_list)
+    return output_list
+        
+
+    
+        
\ No newline at end of file
diff --git a/pypelines/examples.py b/pypelines/examples.py
index eb6d392..bc46c65 100644
--- a/pypelines/examples.py
+++ b/pypelines/examples.py
@@ -11,10 +11,10 @@ example_pipeline = ExamplePipeline()
 @example_pipeline.register_pipe
 class ExamplePipe(PicklePipe):
 
-    @stepmethod()
-    def example_step1(self, argument1, optionnal_argument2 = "23"):
+    @stepmethod(version = "1")
+    def example_step1(self, session, argument1, optionnal_argument2 = "23"):
         return {"argument1" : argument1, "optionnal_argument2" : optionnal_argument2}
 
-    @stepmethod(requires = [example_step1])
-    def example_step2(self, argument1, argument2):
-        return {"argument1" : argument1, "argument2" : argument2}
+    @stepmethod(requires = "ExamplePipe.example_step1")
+    def example_step2(self, session, argument1, argument2):
+        return {"argument1" : argument1, "argument2" : argument2}
\ No newline at end of file
diff --git a/pypelines/pipe.py b/pypelines/pipe.py
index 89620f9..8934883 100644
--- a/pypelines/pipe.py
+++ b/pypelines/pipe.py
@@ -1,5 +1,6 @@
 from . step import BaseStep
 from . multisession import BaseMultisessionAccessor
+from . sessions import Session
 
 from functools import wraps
 import inspect
@@ -9,39 +10,23 @@ from typing import Callable, Type, Iterable, Protocol, TYPE_CHECKING
 if TYPE_CHECKING:
     from .pipeline import BasePipeline
 
-class OutputData(Protocol):
-    """Can be a mapping, iterable, single element, or None.
-
-    This class is defined for typehints, and is not a real class useable at runtime"""
-
 class PipeMetaclass(type):
     
     def __new__(cls : Type, pipe_name : str, bases : Iterable[Type], attributes : dict) -> Type:
-        print(pipe_name, attributes)
-        attributes["pipe_name"] = pipe_name
-        
-        steps = {}
-        # this loop allows to populate cls.steps from the unistanciated the step methods of the cls.
-        for name, attribute in attributes.items():
-            if getattr(attribute, "is_step", False):
-                steps[name] = PipeMetaclass.make_step_attributes(attribute , pipe_name , name)
-        
-        attributes["steps"] = steps
-
-        if len(attributes["steps"]) > 1 and attributes["single_step"]:
-            raise ValueError(f"Cannot set single_step to True if you registered more than one step inside {pipe_name} class")
-        
         return super().__new__(cls, pipe_name, bases, attributes)
     
     def __init__(cls : Type, pipe_name : str, bases : Iterable[Type], attributes : dict) -> None:
         
-        print(f"init of {pipe_name}")
-        print(cls.__dict__)
+        steps = getattr(cls,"steps",{})
 
+        for name, attribute in attributes.items():
+            if getattr(attribute, "is_step", False):
+                steps[name] = PipeMetaclass.step_with_attributes(attribute , pipe_name , name)
 
+        setattr(cls,"steps",steps)
 
     @staticmethod
-    def make_step_attributes(step : Callable, pipe_name : str, step_name : str) -> Callable:
+    def step_with_attributes(step : BaseStep, pipe_name : str, step_name : str) -> BaseStep:
         
         setattr(step, "pipe_name", pipe_name) 
         setattr(step, "step_name", step_name) 
@@ -62,14 +47,16 @@ class BasePipe(metaclass = PipeMetaclass):
 
         self.multisession = self.multisession_class(self)
         self.pipeline = parent_pipeline
+        self.pipe_name = self.__class__.__name__
+        print(self.pipe_name)
+
+        if len(self.steps) > 1 and self.single_step:
+            raise ValueError(f"Cannot set single_step to True if you registered more than one step inside {self.pipe_name} class")
         
         # this loop allows to populate self.steps from the now instanciated version of the step method.
         # Using only instanciated version is important to be able to use self into it later, 
         # without confusing ourselved with uninstanciated versions in the steps dict
 
-        methods = inspect.getmembers(self, predicate= inspect.ismethod)
-        print(methods)
-
         for step_name, _ in self.steps.items():
             step = getattr(self , step_name) # get the instanciated step method from name. 
             step = self.step_class(self.pipeline, self, step, step_name)
@@ -85,50 +72,47 @@ class BasePipe(metaclass = PipeMetaclass):
             self.pipeline.pipes[self.pipe_name] = self
             setattr(self.pipeline, self.pipe_name, self)
 
-        self._make_wrapped_functions()
-
-    def _make_wrapped_functions(self):
-        self.make_wrapped_save()
-        self.make_wrapped_load()
-
     def __repr__(self) -> str:
         return f"<{self.__class__.__bases__[0].__name__}.{self.pipe_name} PipeObject>"
 
-    def make_wrapped_save(self):
-        self.save = self.dispatcher(self.file_saver)
-
-    def make_wrapped_load(self):
-        self.load = self.dispatcher(self.file_loader)
-
-    def file_getter(self, session, extra, version) -> OutputData :
-        #finds file, opens it, and return data.
-        #if it cannot find the file, it returns a IOError
-        ...
-        #it will get
-
     def _check_version(self, step_name , found_version):
         #checks the found_version of the file is above or equal in the requirement order, to the step we are looking for
-        #TODO
+        #TODO, need to intelligently think about how to implement this to be easily moduleable
         self.pipeline.get_requirement_stack(step_name)
 
-    def step_version(self, step):
-        #simply returns the current string of the version that is in .
-        ...
+    def identify_disk_version(self, version_string : str) -> BaseStep :
+        """It will be called if the current version and disk version do not match
         
-    def disk_version(self, session, extra) -> str :
-        #simply returns the version string of the file(s) that it found.
+        This function returns True for OK, you can load this tep, it is a valid one,
+        or False for no, not a valid version, you need to relaunch the requires chain list to regenerate from the last step that was in an ok version.
+
+        If the disk version is a non deprecated version : 
+            - check if that step is above the current version, and in that case, returns True, else returns False.
+
+        If the disk version is a deprecated version :
+            - directly reruns the requires chain list.
+
+        """
+
+    def disk_step(self, session : Session, extra = "") -> BaseStep :
+        #simply returns the pipe's (most recent in the step requirement order) step instance that corrresponds to the step that is found on the disk
+        return None
         ...
         
-    def file_saver(self, session, dumped_object, extra, version ):
+    def file_saver(self, session : Session, dumped_object, step : BaseStep, extra = "") -> None:
         ...
 
-    def file_loader(self, session, extra, version ):
+    def file_loader(self, session : Session, step : BaseStep, extra =  "") :
+        """Loads a file that corresponds to the pipe, the step and the eventual version
+        required (if step.use_version is True and step.version == the version of the file on the drive)
+        If the version is not """
         ...
-        
-    def file_checker(self, session):
-        ...
-        
-    def dispatcher(self, function):
+
+    def dispatcher(self, function : Callable):
         # the dispatcher must be return a wrapped function
-        ...
+        return function
+
+    def pre_run_wrapper(self, function : Callable):
+        # the dispatcher must be return a wrapped function
+        return function
 
diff --git a/pypelines/pipeline.py b/pypelines/pipeline.py
index ec6abf8..01af955 100644
--- a/pypelines/pipeline.py
+++ b/pypelines/pipeline.py
@@ -15,9 +15,6 @@ class BasePipeline:
         pipe_class(self)
 
         return pipe_class
-    
-    def __init__(self, versions = None):
-        self.versions = versions
         
     def resolve(self, instance_name : str) :
         pipe_name , step_name = instance_name.split(".")
diff --git a/pypelines/sessions.py b/pypelines/sessions.py
new file mode 100644
index 0000000..fcb92f8
--- /dev/null
+++ b/pypelines/sessions.py
@@ -0,0 +1,120 @@
+import pandas as pd, os
+
+@pd.api.extensions.register_series_accessor("pipeline")
+class SeriesPipelineAcessor:
+    def __init__(self, pandas_obj) -> None:
+        self._validate(pandas_obj)
+        self._obj = pandas_obj
+
+    @staticmethod
+    def _validate(obj):
+        required_fields = ["path", "subject", "date", "number"]
+        missing_fields = []
+        for req_field in required_fields:
+            if not req_field in obj.index:
+                missing_fields.append(req_field)
+        if len(missing_fields):
+            raise AttributeError(
+                f"The series must have some fields to use one acessor. This object is missing fields : {','.join(missing_fields)}"
+            )
+        
+    def subject(self):
+        return str(self._obj.subject)
+
+    def number(self, zfill = 3):
+        number = str(self._obj.number) if self._obj.number is not None else ""
+        number = (
+            number
+            if zfill is None or number == ""
+            else number.zfill(zfill)
+        )
+        return number
+
+    def alias(self, separator = "_" , zfill = 3 , date_format = None):
+
+        subject = self.subject()
+        date = self.date(date_format)
+        number = self.number(zfill)
+
+        return (
+            subject
+            + separator
+            + date
+            + ((separator + number) if number else "")
+        )
+
+    def date(self, format = None):
+        if format :
+            return self._obj.date.strftime(format)
+        return str(self._obj.date)
+
+@pd.api.extensions.register_dataframe_accessor("pipeline")
+class DataFramePipelineAcessor:
+    def __init__(self, pandas_obj) -> None:
+        self._validate(pandas_obj)
+        self._obj = pandas_obj
+
+    @staticmethod
+    def _validate(obj):
+        required_columns = ["path", "subject", "date", "number"]
+        missing_columns = []
+        for req_col in required_columns:
+            if not req_col in obj.columns:
+                missing_columns.append(req_col)
+        if len(missing_columns):
+            raise AttributeError(
+                f"The series must have some fields to use one acessor. This object is missing fields : {','.join(missing_columns)}"
+            )
+
+class Session(pd.Series):
+    def __new__(
+        cls,
+        series=None,
+        *,
+        subject=None,
+        date=None,
+        number=None,
+        path=None,
+        auto_path=False,
+        date_format = None,
+        zfill = 3,
+        separator = "_"
+    ):
+        if series is None:
+            series = pd.Series()
+
+        if subject is not None:
+            series["subject"] = subject
+        if date is not None:
+            series["date"] = date
+        if number is not None or "number" not in series.index:
+            series["number"] = number
+        if path is not None:
+            series["path"] = path
+
+        series.pipeline  # verify the series complies with pipeline acessor
+
+        if auto_path:
+            series["path"] = os.path.normpath(os.path.join(
+                series["path"],
+                series.pipeline.subject(),
+                series.pipeline.date(date_format),
+                series.pipeline.number(zfill)
+            ))
+
+        if series.name is None:
+            series.name = series.pipeline.alias(separator = separator, zfill = zfill , date_format = date_format)
+
+        if not "alias" in series.index:
+            series["alias"] = series.pipeline.alias(separator = separator, zfill = zfill , date_format = date_format)
+
+        return series
+
+class Sessions(pd.DataFrame):
+    def __new__(cls, series_list):
+        # also works seamlessly if a dataframe is passed and is already a Sessions dataframe.
+        df = pd.DataFrame(series_list)
+
+        df.pipeline  # verify the df complies with pipeline acessor, then returns
+
+        return df
\ No newline at end of file
diff --git a/pypelines/step.py b/pypelines/step.py
index 18bc5ff..e2caa58 100644
--- a/pypelines/step.py
+++ b/pypelines/step.py
@@ -3,27 +3,35 @@ from .loggs import loggedmethod
 import logging
 from typing import Callable
 
-def stepmethod(requires = []):
+from typing import Callable, Type, Iterable, Protocol, TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from .pipeline import BasePipeline
+    from .pipe import BasePipe
+
+def stepmethod(requires = [], version = None):
     # This method allows to register class methods inheriting of BasePipe as steps.
     # It basically just step an "is_step" stamp on the method that are defined as steps.
     # This stamp will later be used in the metaclass __new__ to set additionnal usefull attributes to those methods
-    if not isinstance(requires, list):
-        requires = [requires]
-        
     def registrate(function):
-        function.requires = requires
+
+        function.requires = [requires] if not isinstance(requires, list) else requires
         function.is_step = True
+        function.use_version = False if version is None else True
+        function.version = version
         return function
     return registrate
 
 class BaseStep:
-    
-    def __init__(self, pipeline, pipe, step, step_name):
+
+    def __init__(self, pipeline : "BasePipeline", pipe : "BasePipe", step : "BaseStep", step_name : str):
         self.pipeline = pipeline # save an instanciated access to the pipeline parent
         self.pipe = pipe # save an instanciated access to the pipe parent
         self.step = step # save an instanciated access to the step function (undecorated)
         self.pipe_name = pipe.pipe_name
         self.step_name = step_name
+        self.use_version = self.step.use_version
+        self.version = self.step.version
 
         self.single_step = self.pipe.single_step
         self.requires = self.step.requires
@@ -41,32 +49,23 @@ class BaseStep:
     def __repr__(self):
         return f"<{self.pipe_name}.{self.step_name} StepObject>"
 
-    def _saving_wrapper(self, function):
-        return self.pipe.dispatcher(self._version_wrapper(function, self.pipe.step_version))
-
-    def _loading_wrapper(self, function):
-        return self.pipe.dispatcher(self._version_wrapper(function, self.pipe.step_version))
-
-    def _generating_wrapper(self, function):
-        return 
-
     def _make_wrapped_functions(self):
         self.make_wrapped_save()
         self.make_wrapped_load()
         self.make_wrapped_generate()
 
     def make_wrapped_save(self):
-        self.save = self._saving_wrapper(self.pipe.file_saver)
+        self.save = self.pipe.dispatcher(self._version_wrapper(self.pipe.file_saver))
     
     def make_wrapped_load(self):
-        self.load = self._loading_wrapper(self.pipe.file_loader)
+        self.load = self.pipe.dispatcher(self._version_wrapper(self.pipe.file_loader))
     
     def make_wrapped_generate(self):
         self.generate = loggedmethod(
             self._version_wrapper(
                 self.pipe.dispatcher(
-                    self._loading_wrapper(
-                        self._saving_wrapper(
+                    self._load_or_generate_wrapper(
+                        self._save_after_generate_wrapper(
                             self.pipe.pre_run_wrapper(self.step)
                             )
                         )
@@ -74,20 +73,26 @@ class BaseStep:
                 )
             )
 
-            
-    def _version_wrapper(self, function_to_wrap, version_getter):
-        @wraps(function_to_wrap)
+
+
+    def step_current_version(self) -> str:
+        #simply returns the current string of the version that is in the config file.
+        return "version"
+        ...
+
+    def _version_wrapper(self, function):
+        @wraps(function)
         def wrapper(*args,**kwargs):
-            version = version_getter(self)
-            return function_to_wrap(*args, version=version, **kwargs)
+            version = self.step_current_version(self)
+            return function(*args, version=version, **kwargs)
         return wrapper
 
-    def _loading_wrapper(self, func: Callable):  
+    def _load_or_generate_wrapper(self, function: Callable):  
         """
         Decorator to load instead of calculating if not refreshing and saved data exists
         """
 
-        @wraps(func)
+        @wraps(function)
         def wrap(session_details, *args, **kwargs):
             """
             Decorator function
@@ -108,7 +113,8 @@ class BaseStep:
             logger = logging.getLogger("load_pipeline")
 
             kwargs = kwargs.copy()
-            extra = kwargs.get("extra", None)
+            extra = kwargs.get("extra", "")
+            version = kwargs.get("version", "")
             skipping = kwargs.pop("skip", False)
             # we raise if file not found only if skipping is True
             refresh = kwargs.get("refresh", False)
@@ -130,14 +136,14 @@ class BaseStep:
                 )
 
             if not refresh:
-                if skipping and self.pipe.file_checker(session_details, extra):
+                if skipping and self.pipe.file_checker(session_details, extra=extra, version=version):
                     logger.load_info(
                         f"File exists for {self.pipe_name}{'.' + extra if extra else ''}. Loading and processing have been skipped"
                     )
                     return None
                 logger.debug(f"Trying to load saved data")
                 try:
-                    result = self.pipe.file_loader(session_details, extra=extra)
+                    result = self.pipe.file_loader(session_details, extra=extra, version=version)
                     logger.load_info(
                         f"Found and loaded {self.pipe_name}{'.' + extra if extra else ''} file. Processing has been skipped "
                     )
@@ -150,31 +156,31 @@ class BaseStep:
             logger.load_info(
                 f"Performing the computation to generate {self.pipe_name}{'.' + extra if extra else ''}. Hold tight."
             )
-            return func(session_details, *args, **kwargs)
+            return function(session_details, *args, **kwargs)
 
         return wrap
 
-    def _saving_wrapper(self, func: Callable):
+    def _save_after_generate_wrapper(self, function: Callable):
         # decorator to load instead of calculating if not refreshing and saved data exists
-        @wraps(func)
-        def wrap(session_details, *args, **kwargs):
+        @wraps(function)
+        def wrap(session, *args, **kwargs):
 
             logger = logging.getLogger("save_pipeline")
 
             kwargs = kwargs.copy()
             extra = kwargs.get("extra", "")
+            version = kwargs.get("version", "")
             save_pipeline = kwargs.pop("save_pipeline", True)
 
-   
-            result = func(session_details, *args, **kwargs)
-            if session_details is not None:
+            result = function(session, *args, **kwargs)
+            if session is not None:
                 if save_pipeline:
                     # we overwrite inside saver, if file exists and save_pipeline is True
-                    self.pipe.file_checker(result, session_details, extra=extra)
+                    self.pipe.file_saver(session, result, extra=extra, version=version)
             else:
                 logger.warning(
                     f"Cannot guess data saving location for {self.pipe_name}: 'session_details' argument must be supplied."
                 )
             return result
 
-        return wrap
+        return wrap
\ No newline at end of file
diff --git a/pypelines/versions.py b/pypelines/versions.py
index 02cfdae..63face0 100644
--- a/pypelines/versions.py
+++ b/pypelines/versions.py
@@ -1,6 +1,11 @@
 from dataclasses import dataclass
 import hashlib, random, json, inspect, re
 
+from typing import Callable, Type, Iterable, Protocol, TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from . step import BaseStep
+
 @dataclass
 class Version:
     pipe_name : str
@@ -72,7 +77,7 @@ class BaseVersionHandler:
     def get_new_version_string(self) -> str :
         ...
 
-    def get_active_version(self, step) -> Version :
+    def get_active_version(self, step : "BaseStep") -> Version :
         ...
 
     def apply_changes(self, versions) -> None :
diff --git a/setup.py b/setup.py
index 2046f52..96e1e45 100644
--- a/setup.py
+++ b/setup.py
@@ -25,7 +25,7 @@ setup(
     license= 'MIT',
     author= 'Timothé Jost-MOUSSEAU',
     author_email= 'timothe.jost-mousseau@pasteur.com',
-    description= 'Image and video management for research use, in an unified easy to use API',
+    description= 'Framework to organize pprocessing files outputs.',
     classifiers=[
         'Development Status :: 3 - Alpha',
         'Intended Audience :: Developers',
diff --git a/tests/__pycache__/tests.cpython-311.pyc b/tests/__pycache__/tests.cpython-311.pyc
index afa9a4a52152bf6dc1c5436b35c23f22c8904aad..b7fd70566d32d16f28c1d314b77bf84174b64f1a 100644
GIT binary patch
delta 1038
zcmZ3$`;?z|IWI340|NuYGbV-9Qxkb583QJ&Kl5eI;mqZV;$mb-VMt-g;m+lW;$dW9
zVsK|jVQpbZVM}Gm;st2};bqJW46B(zED(<3OXW{t&t?L#iv*b%QW>%YCWkR9s&c#p
z3HepA>gnn0>1i_F;z+GX%q_@CE!Jeb#U7kmT%4JoH+dpsAQw9W0|Uss&pnghFsj#=
zfcPN23=9k@j44bh%qc7>tZUeou`)2MW`#;H)G)-ez}O|+Fct$t4MP@OJc|t`zKoH9
zVKpO+2l8bwgC@J*EuNCp;*$8{(xj}^<dP~bBLgF2M_oe$T|<K+kdLa^ovrjiN<uVQ
zZ?Qv_-C{{eEJ?k^mRFjalv;F)r692+;}&OPX-R%Oh^fgwS%yh5wg}{kTkORUf8Js(
zD9X$$xy728lbKk&lJOQxacWLlF~~&<zdW3+VnT~ki;81Pvhs^da`Q`LT=J7kb5rw5
ziemyQOEU8FV&dZq5|gtN(^HG%<6{CQH!>M{gJQARiGhKkf#I%%!W9X_4wfF?yAtv%
z^bW{eh={z9lzpMH_JTy+MTxpA5_KIcJv?_gcso*ha<1?xT;x!^!l8Hph9;k3lIHAS
zU|^WeP{Xib@<%3-$t=v~A~g(I@bFGyT*kz}u$pPIGjoIh+b!<I;^Nez64%1g#GE4j
z$*Y;Q1O*rv7>a}$7#JYlDiWRiklBHUA0!Y5cIAV~x-60|Dra;qL?m96Ou8bObfLKB
z0|P@iQzX*|28L9|C>ZsTfq^rc=?j?rfI$|CPi|$=RuBW(r^vv-u#%xj9K;p{5uhk9
z0udaOFR+M2GP5duV1N@`OsvsN9~iKc5JNy(Z*j!O=O$+6#m8$3-r^|D%Paw<fm_VQ
zmBqK1@{5aj7#J8P+p$`Q2^CZpq~>Jir55W!Bf1z8?;Ihi#U;*(#i?MY6e%$<Fx+AR
z8Cj$XawOcjzc_4i^HWN5QtgV285kHq>7n?=<ZY~Zk#ZLpP|ytqwF{`|0}Cf3$T!%@
b2^Lp`RX#F+B)@>k4-ispaygqS3&;Tgsdorm

delta 718
zcmaFLzkru_IWI340|NuYF$4Kj&WXH|j6M_9pUE@ka7J;aFr+Z&aOQGFaWOJ5F}O3N
zu(U9wu%<F(aZfg26c^@6<xOGBW&&w05@cdXWys>29L1=}$UeD-QF8JE#y~ER95Vw0
z!)J}jzZuo@QW%06G#ULgnTtSzw**ov5_1c3QsWCU3sQ43^HOhdz*s98Z?P1o=A;!f
zGB7YG{PK3TiU}=FEh>%)$;{0!$w-ayODs;$uS_gU^>>a5D9TSuEiTT?&&x~Ai3vz7
zE=esdiYb_!z-%PR&A`A=EWp6P(7<q4Lg9*pVFybOZwGG&@8rA8(u_5ee=-Miq%baH
zWMEj$I5~kOLV)!acVcmIYEg-6VQFGc5y#{cELuFAAXC6jDdL{Y%<90y2NH+`8+&82
zKdYp@=0(YnE0Q4>Qu97AFnBU~GksuS2xs(xQ6Cu?IDMJEfXNRSWD)P=HLTk8JPZsB
zMdAz$3@aImctLEC<BM29ED!;9ggMyG1_lWHz{1FC^nn3RuradwGJ*KmNQjvrlWuXu
z$LA(y=EcWr^55bp&C4t)Ni8nnzr|c!S$vBrzxWnQL1Ib9<P<h*H;$0h;u7b?;#7z`
zBp4VNZn1#$7D<EL1$X8z4x8Nkl+v73yCO{n1_n@A6+dENVEDky$jEqOG9$afWI1-%
vV1Ww^Q1pO7?gA?Mz{17|ayNEzg2feKm5&S{$uD5?1B4WqyoX(t1>_C@e~q<z

diff --git a/tests/instances.py b/tests/instances.py
deleted file mode 100644
index cda334b..0000000
--- a/tests/instances.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-import pypelines
-
-pipeline_test_instance = pypelines.BasePipeline()
-
-
-@pipeline_test_instance.register_pipe
-class TestPipe(pypelines.BasePipe):
-    
\ No newline at end of file
diff --git a/tests/tests.py b/tests/tests.py
index 97dc509..3afaa61 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -2,19 +2,19 @@ import unittest, sys, os
 
 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
 
-import pypelines
-
 from pypelines import examples
+from pypelines.sessions import Session
 
 class TestVersions(unittest.TestCase):
 
     def setUp(self):
         self.pipeline = examples.example_pipeline
+        self.session  = Session(subject = "test_subject", date = "2023-10-10", number = 0, path = "C:/test", auto_path = True)
+        print(self.session.alias)
 
     def test_pipeline_generate(self):
-        self.assertEqual(self.pipeline.ExamplePipe.example_step1.generate("bonjour"), {"argument1" : "bonjour", "optionnal_argument2" : 23})
-
-if __name__ == '__main__':
-    unittest.main()
 
+        self.assertEqual(self.pipeline.ExamplePipe.example_step1.generate(self.session, "bonjour"), {"argument1" : "bonjour", "optionnal_argument2" : 23})
 
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
-- 
GitLab