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 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 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