From ee52090235726f56b2b080e1242eace2e1ce466d Mon Sep 17 00:00:00 2001 From: EstelleDa Date: Mon, 3 Mar 2025 14:28:00 +1100 Subject: [PATCH 01/20] Modify tentivirus to lentivirus in alembic file. --- alembic/versions/9702d32bacb3_controlled_keyword.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alembic/versions/9702d32bacb3_controlled_keyword.py b/alembic/versions/9702d32bacb3_controlled_keyword.py index fda0fa36..4464c2b5 100644 --- a/alembic/versions/9702d32bacb3_controlled_keyword.py +++ b/alembic/versions/9702d32bacb3_controlled_keyword.py @@ -146,7 +146,7 @@ def upgrade(): """INSERT INTO controlled_keywords (key, value, vocabulary, special, description, creation_date, modification_date) VALUES ('Delivery method', 'Adeno-associated virus transduction', NULL, False, 'How the variant library was delivered to the model system for phenotype evaluation.', NOW(), NOW())""" ) op.execute( - """INSERT INTO controlled_keywords (key, value, vocabulary, special, description, creation_date, modification_date) VALUES ('Delivery method', 'Tentivirus transduction', NULL, False, 'How the variant library was delivered to the model system for phenotype evaluation.', NOW(), NOW())""" + """INSERT INTO controlled_keywords (key, value, vocabulary, special, description, creation_date, modification_date) VALUES ('Delivery method', 'Lentivirus transduction', NULL, False, 'How the variant library was delivered to the model system for phenotype evaluation.', NOW(), NOW())""" ) op.execute( """INSERT INTO controlled_keywords (key, value, vocabulary, special, description, creation_date, modification_date) VALUES ('Delivery method', 'Chemical or heat shock transformation', NULL, False, 'How the variant library was delivered to the model system for phenotype evaluation.', NOW(), NOW())""" From ae9f2ff91a599d601430e80e2b40963bb285eca5 Mon Sep 17 00:00:00 2001 From: EstelleDa Date: Tue, 4 Mar 2025 18:55:44 +1100 Subject: [PATCH 02/20] Debug UnicodeDecodeError problem and add a related test. Remove unnecessary csv files. --- src/mavedb/routers/score_sets.py | 13 ++++++++---- tests/routers/counts.csv | 12 ----------- .../counts_with_different_variants.csv | 12 ----------- tests/routers/counts_with_hgvs_nt_and_pro.csv | 3 --- tests/routers/counts_with_score.csv | 12 ----------- .../routers/data/scores_non_utf8_encoded.csv | Bin 0 -> 208283 bytes tests/routers/scores.csv | 12 ----------- .../routers/scores_hgvs_nt_not_match_pro.csv | 3 --- .../scores_hgvs_pro_has_same_values.csv | 12 ----------- .../routers/scores_with_duplicate_columns.csv | 12 ----------- tests/routers/scores_with_hgvs_nt_and_pro.csv | 3 --- .../scores_with_invalid_hgvs_nt_prefix.csv | 12 ----------- .../scores_with_invalid_hgvs_pro_prefix.csv | 12 ----------- tests/routers/scores_with_nan_column_name.csv | 12 ----------- tests/routers/scores_with_string.csv | 12 ----------- tests/routers/scores_without_hgvs_column.csv | 5 ----- tests/routers/scores_without_score_column.csv | 3 --- tests/routers/test_score_set.py | 20 ++++++++++++++++++ 18 files changed, 29 insertions(+), 141 deletions(-) delete mode 100644 tests/routers/counts.csv delete mode 100644 tests/routers/counts_with_different_variants.csv delete mode 100644 tests/routers/counts_with_hgvs_nt_and_pro.csv delete mode 100644 tests/routers/counts_with_score.csv create mode 100755 tests/routers/data/scores_non_utf8_encoded.csv delete mode 100644 tests/routers/scores.csv delete mode 100644 tests/routers/scores_hgvs_nt_not_match_pro.csv delete mode 100644 tests/routers/scores_hgvs_pro_has_same_values.csv delete mode 100644 tests/routers/scores_with_duplicate_columns.csv delete mode 100644 tests/routers/scores_with_hgvs_nt_and_pro.csv delete mode 100644 tests/routers/scores_with_invalid_hgvs_nt_prefix.csv delete mode 100644 tests/routers/scores_with_invalid_hgvs_pro_prefix.csv delete mode 100644 tests/routers/scores_with_nan_column_name.csv delete mode 100644 tests/routers/scores_with_string.csv delete mode 100644 tests/routers/scores_without_hgvs_column.csv delete mode 100644 tests/routers/scores_without_score_column.csv diff --git a/src/mavedb/routers/score_sets.py b/src/mavedb/routers/score_sets.py index be990f35..ac33bd14 100644 --- a/src/mavedb/routers/score_sets.py +++ b/src/mavedb/routers/score_sets.py @@ -648,10 +648,15 @@ async def upload_score_set_variant_data( assert_permission(user_data, item, Action.UPDATE) assert_permission(user_data, item, Action.SET_SCORES) - scores_df = csv_data_to_df(scores_file.file) - counts_df = None - if counts_file and counts_file.filename: - counts_df = csv_data_to_df(counts_file.file) + try: + scores_df = csv_data_to_df(scores_file.file) + counts_df = None + if counts_file and counts_file.filename: + counts_df = csv_data_to_df(counts_file.file) + # Handle non-utf8 file problem. + except UnicodeDecodeError as e: + raise HTTPException(status_code=400, detail=f"Error decoding file: {e}. Ensure the file has correct values.") + if scores_file: # Although this is also updated within the variant creation job, update it here diff --git a/tests/routers/counts.csv b/tests/routers/counts.csv deleted file mode 100644 index 2242e957..00000000 --- a/tests/routers/counts.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,value,c_0.5,c_1,c_2,c_4,c_8,c_16,c_32,c_64,c_128,c_256,c_512,c_1024,c_total,ambler -p.Met1Ala,0.0,22.0,12,3,4,4,0,0,0,0,0,0,0,51.0,3.0 -p.Met1Cys,0.0,8.0,17,4,0,0,0,0,1,1,0,2,0,33.0,3.0 -p.Met1Asp,0.0,7.0,5,0,0,0,0,0,0,0,0,0,0,12.0,3.0 -p.Met1Glu,0.0,15.0,16,0,0,0,0,0,0,0,0,0,0,31.0,3.0 -p.Met1Phe,0.0,0.0,2,7,0,0,0,0,0,0,0,1,0,10.0,3.0 -p.Met1Gly,29.0,18.0,5,0,0,0,0,1,0,0,0,0,0,53.0,3.0 -p.Met1His,2.0,9.0,2,0,0,0,0,0,0,0,0,0,0,13.0,3.0 -p.Met1Ile,0.0,3.0,4,0,0,0,2,0,29,68,5,3,0,114.0,3.0 -p.Met1Lys,0.0,23.0,26,5,0,0,0,0,0,0,0,0,0,54.0,3.0 -p.Met1Leu,0.0,4.0,0,0,0,1,0,1,30,22,12,5,0,75.0,3.0 -p.Met1Met,0.0,0.0,0,0,0,0,0,0,0,0,0,0,0,0.0,3.0 \ No newline at end of file diff --git a/tests/routers/counts_with_different_variants.csv b/tests/routers/counts_with_different_variants.csv deleted file mode 100644 index 9a21eaf0..00000000 --- a/tests/routers/counts_with_different_variants.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,value,c_0.5,c_1,c_2,c_4,c_8,c_16,c_32,c_64,c_128,c_256,c_512,c_1024,c_total,ambler -p.Ser2Leu,0.0,22.0,12,3,4,4,0,0,0,0,0,0,0,51.0,3.0 -p.Ser2Met,0.0,8.0,17,4,0,0,0,0,1,1,0,2,0,33.0,3.0 -p.Met1Asp,0.0,7.0,5,0,0,0,0,0,0,0,0,0,0,12.0,3.0 -p.Met1Glu,0.0,15.0,16,0,0,0,0,0,0,0,0,0,0,31.0,3.0 -p.Met1Phe,0.0,0.0,2,7,0,0,0,0,0,0,0,1,0,10.0,3.0 -p.Met1Gly,29.0,18.0,5,0,0,0,0,1,0,0,0,0,0,53.0,3.0 -p.Met1His,2.0,9.0,2,0,0,0,0,0,0,0,0,0,0,13.0,3.0 -p.Met1Ile,0.0,3.0,4,0,0,0,2,0,29,68,5,3,0,114.0,3.0 -p.Met1Lys,0.0,23.0,26,5,0,0,0,0,0,0,0,0,0,54.0,3.0 -p.Met1Leu,0.0,4.0,0,0,0,1,0,1,30,22,12,5,0,75.0,3.0 -p.Met1Met,0.0,0.0,0,0,0,0,0,0,0,0,0,0,0,0.0,3.0 \ No newline at end of file diff --git a/tests/routers/counts_with_hgvs_nt_and_pro.csv b/tests/routers/counts_with_hgvs_nt_and_pro.csv deleted file mode 100644 index a89ca9d9..00000000 --- a/tests/routers/counts_with_hgvs_nt_and_pro.csv +++ /dev/null @@ -1,3 +0,0 @@ -hgvs_nt,hgvs_pro,value,c_0.5,c_1,c_2,c_4,c_8,c_16,c_32,c_64,c_128,c_256,c_512,c_1024,c_total,ambler -c.1A>T,p.Met1Leu,0.0,22.0,12,3,4,4,0,0,0,0,0,0,0,51.0,3.0 -c.3G>A,p.Met1Ile,0.0,8.0,17,4,0,0,0,0,1,1,0,2,0,33.0,3.0 \ No newline at end of file diff --git a/tests/routers/counts_with_score.csv b/tests/routers/counts_with_score.csv deleted file mode 100644 index ae4c8b82..00000000 --- a/tests/routers/counts_with_score.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,c_0.5,c_1,c_2,c_4,c_8,c_16,c_32,c_64,c_128,c_256,c_512,c_1024,c_total,ambler -p.Met1Ala,0.0,22.0,12,3,4,4,0,0,0,0,0,0,0,51.0,3.0 -p.Met1Cys,0.0,8.0,17,4,0,0,0,0,1,1,0,2,0,33.0,3.0 -p.Met1Asp,0.0,7.0,5,0,0,0,0,0,0,0,0,0,0,12.0,3.0 -p.Met1Glu,0.0,15.0,16,0,0,0,0,0,0,0,0,0,0,31.0,3.0 -p.Met1Phe,0.0,0.0,2,7,0,0,0,0,0,0,0,1,0,10.0,3.0 -p.Met1Gly,29.0,18.0,5,0,0,0,0,1,0,0,0,0,0,53.0,3.0 -p.Met1His,2.0,9.0,2,0,0,0,0,0,0,0,0,0,0,13.0,3.0 -p.Met1Ile,0.0,3.0,4,0,0,0,2,0,29,68,5,3,0,114.0,3.0 -p.Met1Lys,0.0,23.0,26,5,0,0,0,0,0,0,0,0,0,54.0,3.0 -p.Met1Leu,0.0,4.0,0,0,0,1,0,1,30,22,12,5,0,75.0,3.0 -p.Met1Met,0.0,0.0,0,0,0,0,0,0,0,0,0,0,0,0.0,3.0 \ No newline at end of file diff --git a/tests/routers/data/scores_non_utf8_encoded.csv b/tests/routers/data/scores_non_utf8_encoded.csv new file mode 100755 index 0000000000000000000000000000000000000000..d47850d716c0bc9f60f111812e10c449e5a45a0d GIT binary patch literal 208283 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�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

AI>ZjUM^LkIE__3sTJ5_@b(9%#G>1ZlE6lT}CE zk@|;;tHU;z-&|MRxVkI#vEI3(xUzslwo5`2(TON*6hA2iYj+qmqTZAs8maEUP+FgB zoLo~K>GbN^gH&w;R!&?E;*cf5SowLz^Z#E1=-+3h`!pR;to%Ysi{UY^1U@|aX_dsL zuE>`fOoC&Er+X|WAF*J-r^5P0?u%vTIh)|f2H)cwBsKuNhKs$^PM+u%nw)^wHc)WE z%lKg5c<2gSV4|iRlf8DP?pHZCOPtd0?xyklr_6ZYd$Ox3*c?TF2^fC9$RLGediJ5M z5*&HhUv0uGWpzdm#=6{gIc-R!>j1bGE$Axti6MnWSRIbA2Pn@PEC*0vm49a5Oq zPYx`EzVd$hKug{Vf%iN^r?>yD^_{@#2o<3IDrfEJFvPpwP0wfu!#yiu+Hj)>PCfVj zxks46sUk_e;;36rpB_r|t5Y0X`h$=H7Vlr65($+1`;)r&Y`b%kbUcKUths5;r`2T& z`Y8r{XC4RUKu*0p3)ye__uKDR=jZ|9FJ6-f`$4ZwW9 zUwQtt(W}FD#>hEJz#`8QM3bLaj8Jg3y?du>cq8?})+GDk;8F{f3s-$*Z4d5QA)V~m zoB&Wq_)l^7ue-ivu_}uUfE}7DbbfpsLg~oa{0a_T&iHXs>dM?x*qw<%lqgc$-x0EF) z&vrU;+lVW@w41H2za#k z4{UHL`T%qCJ|BqCWYt+Lx!Q0O8#%%@f8hl~fmlnW&7jOitOv*Dj&`2WZ;15ljCo2s z8tc2j-zvk@hLedPD~whd**QCWQ5t;_H*{Ts)xh0a$h$i7t-amDC=)I4(y_l8{jUWn zoTzn>0%DcfH4wyJ6L*&Zg02PuyEf{?tL@q@r zK-rvqz>8M{R(4qZik9b8ALI+O3ypwjf z+sm-|2Y$eHycq%24(GB2?~h4h*_oCzflg(;-;CVKpv^J7=Xq%Db4~B!Vk%@G{_p)~ zRmy!6USi)^o~jn@8Zlw{I5N0P$emK6NbHZM;Q41d2%7(ST7&p%iVS;87;>vc$D(e3 zja76Lykf$e+WD)ghEhbraz4o8N?XE!?)AO3|Bt=*jB2WF_kDwcC`hl;J19-02}B~& zMMOpE5a}QSA_74I0g+xJAfO-wq)U^ov;d)sfb?FHAWBbALnI;Y`J8jcSnGM-wby&T z>^;UFV}HmOM#!A=o^#&!bzj%-`v2Fd|Jb+xPX*s0|H-WGA50-tmJpIiyX=FmM}gvEvUetjl=I>5*UNA5dDG($UH`@uqO~LFfM%D= zGy#}T&#gY zNv=6e5Av;vrlkYraoCEBc+%EBeN*TwBrQS2?C7V*@;S6NqDhr%wY(7uYjcFwbpTJP{k&&Ivlk7Kc zcTCm4nv8n!YE%oTd4xuEp+W8H#6Xhs?2|D*a$N7@O+cnmN%8AMwYqYH-PM^e`_Cz^ zSGT2bH_SiIJ6@v}3H<_S;JD-`kY}s)ntjUWfK0=nW{;C1k$x+6RSoUl*kI$beEi$t z0-KdHGz_kMoTtk|<(mx}EW^JnQ9Z6)3;senydwoR5KnYB$c^&8ywePn7XIHY=A7y9}uzwG_mnh0Go z&ZNjA{vZ+q$VIyCh-(hQ#aEN;JiQRpDX)iR`#k7D8Sxq&?1A6|e zO$MT@PsWmUB?d@E)i+EhF!3*!e2V7<>4f`#z7MeTA^DoCF3Y9o)HC+{SGmf7D z3*k4MEC#{7>7+Ab-+QQgmgrH4-8K)6TrOX*SMV1~#q76?Mm$WvRb#3piy|8Dr~>W! zkjCI@{Jw~HtNAy~$97Tgf=xT~lD_G@ zv8bpB4)V=eU<1SYB>ssx@8`Aw-!mc7>sp@arsvkv7TelX*+HYAE=Ko%$@9Qx|K(30 z9^wF%o97q*ACM~~vAX0neVHM%Z02F-=q!6uYF>LfrK17rI^)*>An_6t%I%O^JNYRuU#SS2t5Gb(ehlPDsD_3Q zNCi4o5ZXxQl+YO0p0TW)HmqS(#Y4sRb6H9%jTNfBN*;A zWG927J3>HRBLjtk)8)t>C;ry3UCsp^%6i*m&3caQf=?JWfHb#$$y|Iex5$_B0YGI@ zL>q5cQUlR2JswyKc{1=VJswkETz7oSJ7db#I`30n`(!p=`d0O7c_jP{vFsYz5y!T$ zijzqq%ItWrFtw3+xL4FZJPU4S$~s!S(q=A&xR^0$%YBy5i%`IRwYItn;%*Ts5Yn@2 zxi;m*(URShvpfmivYOT8)8yj|srm$@#Ii`XcDpqvB{FkIS8}i30iCE*fB^oEqnIw* zc`^*FtUj87clCl_JAB$)5>Wm?qTeumSsI=GedRRHP4KqI-F~BsBQMy52^Mj1ONt@f zg%C1ehCXW!L<(4RXioW|)#i31z)U!7V_+zw~Wzb6p^o5|`%t^RDDbp8E#{*(p&M&3$mk zxBYN$EOK6O4I2IHoVp{M`7Cd!uTqtRBdikI5#Jrg+_?5Q6+&>L}Kn(7jiqUU6tweK0Xm#5Dde2?zc3vRiM`k+Ps1W`6! z2pl#Aro$px;U@LOuc-+d?g9i3UecZB^G9(!tV8B_xN+)1-t;Cj~%@gVN&#7lxMtQDx|&KTM%U%)UG}V!gZn@?SKodBjKs5nWb4oL+Ev7%i@5?LWZ#R48gR>EX=!Y+}=9wSEbPNocGIEnYq7MQ%oO4HE)AP2kUtJDNrP5W06jFP$(v3V_hX5#v z4}4PeIoOt9*5`DNY|c`e3TGg0D06=oU`rH7VOp)K{Ta4OvJ#d2aj8mFShf=mUrGHjW#U!ZRkT{XWn3?2@wSpJk@_PFYR zFNWG{4L$$D=&BqqGDeh6mj}-6dj}Dh1J26MSu|KkIo{n}DMLI_oT@r6z5H`>)HT8M zjL30PM&uc($OtHHWCbvy&ZD@ILu{uPd$qGu;J#~$_hG2JZG_QU=WpBD3(c=3j0GI+ z`ib6IkFF{fq&>q3NH97}#f8k>y1puk_DO->m_j4gP?6(vjT$LG^uqCqR+8FFA1JlQ z*&f$=Pk#>l>>w0{tdb`1J>MYyYUw+p5Qqyi7s2brQbu3;PWqK4ZrH#JXr{|*9L)zY z{Y$5qOw`+j35(qkpiZJp306^ON7G4Z`s-}a>l;6A&e}a6AK)^hY)T#U5572!UlhQ9 zy=6Mc`0ZP-FY^uJZdsqjygkW{u>HVVS7X+HFG3PFaL?sPCMLY{WmvDN;J1z`$#}Wg z8PTk{mr9$BQ9V8@XUPM#5x}NO0L(*C*%A?*`1+;&3>JBY{1)GT&1@E(wz^JUR5_vnHLs}Z8B;6{xiW}LEYEPJpYG9LU47*dREA- zrUeH4;nzhWPr&bZbf1;#OhCj(FaRA1YVa$#T}`a}YOKo?+%mwk_<@L6#;rKh)~r4? zi$?F})DnLsAXl_YGN|@?mv~|hkQzVB(L@3g_M$IfbY_%%link!Q(>?tGESc3G^s?&|gNpSiGIg{taX z#%I|LG~P+1MzZzhTd3n(TXsGYlimi)u+^+m-Zjtx-+@M2-?M`Xa2M51YSh zsJ>R(RhIl_MJ&sSR71nlNUb=T0WZoM+y{Hi$TsalHh;{NRl!?Ss8N& z1E}SXu)aKO%`dDlEa`i!@u~TulfxKKdBBSsCS~68dF|Fsuu0lg(jO3scO3l_?|W6) zJ+!6YdJ0F@!@pL$gTH0L@?h7?W$cv_LviVq58r~Rt}7ifFCx1t&qjBjiiAk~8f;f# z+__DW8p39_*sl{UFuW5t_*ak1BnL=qAHIcod>j4s`!J-o1mU+|KePskWA_mh)XT*U zJae73atMF3IdIET3eKS=unVmKGNOOql`w<~@OI@d}6z}21tIl`18*}b>VWeYdw zMiv7Le!!&q&yZc2R!0=jurpsm6R47}kRaD9vfD(VcA~ID2^_oIrzMtZ?+4@GSWf_b z*$DTsD8$*Sc71m&isg)P;_fL_wRz==;l_fhAySh9-+pvl+-s~Gfe%EBYOanw-BpL_s=>L)0mKlX?HUU7 z={=o^<4acG=XHenK6zDE*KY8^EcBtDI&V;0>Ve#SvmlO`Ti+|A+a6Ig^^a44)Giw< z>|hnAfy6RI->aW;n^C}O9@cwj<-F|8Zfluz!d5xI%6PHKlzCY`dPJs{B0w8C+E3aC zd%uGjn1_^a$yY&bS+4z7OByk>x!C$)Vgmb6=GFV9&jgK)ul1n?Y$@RLWpH1>KGupF zF%=;~&Nd<#jYxJUr*GR`*tQOwcly2!=GBwV;eIwes>$;BQ`MOK{qRpjbd)wAtuY3i zpa6}3nR+P$v&u|GKbvf7tlNYxG-sWf?9~kB!y7kdc@;sMOwY1>%%iqFR32&PIw}NI zJDth0#0*DdFAe-f`onbA;AZ{G+ym={yN4PKNrLv-fK;?5yIaQB;g3c)K|>|PxSei- zX8)0F>`xYZ%o%UrweKu7Q8LJ&pdw((*-1p6<*A4QYYx8t&Tn4HGyO9BODT~}%#E#1 zmmBsFHj6_Hu+2~6m$Rbr_G!M@a7#-f>+7;S5nsQFuTnlH>X&^t?zix!JfwG*5^&8&K-cU1a^eZa8L zo1ZAA&NEasvb=M-4P0l!Jo>@miTyk6A6q|6Deu?t1S@1~hCCh#IDZeTuXT@p_aqS6 zsDU9^ia$d{52VRD2F~bnjB4+ni&n^tQcYdah%;b@Tw#z!@ljyU5CO71v&iMeQU}AaHS_gNQmoHdbKL zs_q$pX4_XAQEnm4TL6I_d*Niw5H3Tndbikvd%Ab5_W(VCSKadPh~padaMe4<0CgR4 z(%9w8g60UrVRDmA^7do=9-8F%nwecvWlZJK<5Rk4k1INryjCDY))rvn9iIb9dLPtW3B^=Y#AmhXTaWL_wU@0% zx%gu)jEKaH^c48IRIahM^i&opy{q|sOukR^8_6O=u+in|!#Jzo5$nWR%>HTk_3;8= zOO;XuX#|i&X5l+>@Xdn7(6XD^8WVmoc-OBZ0?iYDo!~RW02D9Ub00`R3ZhI~$#F$P zA&7$ZbZ>wz-<^3~ZhJ10^K{Kl>9Zi~1x=ZQ;z*N0U`_fzhvhAq@$pX8ZEmk=;`z2d!mG9IZp^|PVo=>GMNa4k0U5t zw9iMe(b!cM^z+iDdP4PRVQ5KHY{R=bhk>AX7Zkttwpg{KIXIYW_rII4kU}>4(x1@V zZii4*s62#KK(%L0$B}dE59liKq3Nkw*Q%|f{3hYvfLJE(EzJ-`R?YOYhOBFX`xjo& z9iVo#@Qq|kiWRV#VT)DMK?5|bF_1YhLlkdvsI|<_c&o>e;0%&yX_ih|-3!;KpXnrd z)({PdRIqqy#Jq^eOj96E(W1XooxuAZY*DdH_O!11@oRY3`bL^$ic+;Jta13V81EO8 zE`0%sQ-6iuo6sJM`J%OfZWb#5Dh??e_IbCZQ8zbM4&CBwtzMlg)G2CC_4&Ogl}Inf zA;5FzsuU-kNSbnFyR0U%x>L^76~(pSbtrIFbLB~qUv3cC`V!_V3Rkm< zF-ervaL;UriavA@t%L4N`r?Rq6R-&9W{_TuB9asX1T)%O&PmLLC4$KJXY_@l*YAs5 z9aC=r+#PO^8Hhk?%1MRT66^Hs?o?syqGg!5(I1dS(%ols9NZy<`6Yc8TtSz}Q^=L_zt;nO+?@gzZ#SRAv+S<)rA#g@F8Z%8l#G6{(0?wQ zLqd>c(~@ZC{0$r-dE)A0+%jn`FKMHWeq_CdV_-0SKMe5K-X&*K&I1|Jrl68l7zT5> zb^Pc4j*scj%Iy(>dq5!ZtuNOif2pH<{WSEk(#9#V-h|;wm+NB7kmJ@w!MLhN7u9M{3crV zwRCC{vt!+|0cr>GBoP0mS7|(3M%E326JJXDslLm7N= zYf1MKtDCI3?V7%&kC^5t5Fi%(b~OA41Oh_P^><)k;`+}n z4t|j;x??!VZyLZ&cAba(zJP2XBWZ{#G=a&2cD-^TtE9|pA!w$ya#`Qi+4XF;rnU7Y zg^POh7o1F`(gp#T)%JBf=!9vXGt6?p=`?X8SE*qQ!M^DvF}b_p6YBRfcMgzMbiWsz zQXI8>ucyB5&f}9Oza)atBm@Vb-}Nh-MrR7hiQNrH^&);8yZ-@2-a#DPbA>^0#u#+G z%WgXzE|0Ibr>kFS6j^S+niQzCuRL-f6`o7dSe_f5OpR^34(k2qHU9mA8hw=??qey2 zF}>C*ZZ%{F?e(B@cZ>`z$A29&_o_IU7d)`ac^RC|Y3Fd|&89XckXN&JL*stEjM4gK z=d`q|9DhGGQBR^M^$*AvvBr&}W;*D=1IQQi7zoim#H`N&t%w5X7}E)JN~E^9m0SZuW}v# zZ6N-BwEve;99`@)C&u+Z8@oM;djS-uXs)Kt3W=Zm)t3vewp}Y0o|k&F{^(-hPvbdi z&>xWAUlytimH+@64nz0U{#IDI{0CI$+Jic>t+k$bNjG$i9Dx4hn?MlmLH>Yb$4L-j z#1|-VPrB~{O7i?b(q9jS0Zg){l}f zq8z%S2n#8(l(BtJs~S6ny3J0#!5Cb&2=I=Rk*+1 z%$oaA8^j#H>sz$+NOM^Jf)b$MuzmF$+Lbta%J3)LLr;S|RrddW1a8AzfieUTaV$C6!IXO!bkVx`-Tsmj`@8!h%Sh1m z_iZnwkhngL0icw(Y|(ota(WWzaBw6iPKGR~#j7)is-JES-z5!;X9gdBO1?!8R0aN< zYn#;!A)?osQ6cKUx`U)D`v&?-V$@W9Gy;aW)6%O_t1n*oq({$w8Z0nRA8}U7P}msmI$i&$K&%a&!A}uY_xD z#?K-5LrMs>DedR*m5kGHj#}@0@%mJK=A}*R7b`vW<@ALx$El0-Zd^H_q<`~J&Na`f znJwEL>NQL$dQSZuT+1STI-j=ZThzL8-}^0nyN_}f&G!Du-G`oxLdRvj$hd6U`P{A< zUAb{Tu&Hm`=s0dlarG9`YuLZp_Uv%f&?kc2iGhEA z$@Ai`9vPPxoar3E*B&u%LdX|TK(O_lBASZ+t_&!yd2=VLtq3S2oCUw=y$@!=Da!U*k?KP&hl^MB;Ay7E z175;CEyAoUpnr_yXISfGzfZ|kzaVp!Ns5IjNGA7^@CI#3e5k{Z=e>=q0v)JAC+>C; z`9~K`VtOAA0oY3pZ|(ew(l<_X^Q(FRfe!V#~dSlmR1wn2%Fe7tu1apMTV~Y*0G1Hm`F1eZKwYnqb$u8m}hG zVq02>yK;T(dQ&L2*>>MEbwws0+xw_r#OR)~-_W!t+q4Z+*3(M6~x+TS=-^KT%^FDMJ(Eppmy>GHeMxR!@VuUxDp$1~Bb!p?Dt$ADQ zI*L_$@bB9F<=mZ@*jb!rBF+PF!$w}|wum?}IJ#uc=R$4iveQ=Z48aNDz+2KydEDtQ ziWO?nKmEc0L==Au2L5paXXC+8tnwMJvflg)Ge36)O$AjE<&J$m55S|=hZFT>Ba8WA zR`>RSH&TZ1On>PYauvwAgq zqGI5@->9_n;QIN0dlxIWS2=Y>VAeMEg#85S?YG~LYD$oGbE{jtq*-g7)bX!|3W*19 z1dZs7K3gI*mCClJW24+2h!d8_G|yfNy){zl)a@!%j|dP5xjHg-)%4#Uuyls%v$o3O z#SCcK0g4@&Z?*fkE1XvJ{XML1zmy0Sb`>AE5b{{tDnF(A`-m)y*d8XSRrx3Eg4?$qYq^9@8GR@M}(-4u2d_*4~YvGpg`-EN!1q? zZ?)tcvBa@#*cZLF^j_P$oe07Z)mxGz>l(r>Zcmmq3pA&7URL{kKMg&(ON{dwy4u~X zrJpt+Y+Pn7`;WRz&`Z#5L+=0TL-%L;KX!(Hm)WEG5?XfID4ygbQV5Z8SCcX2C&MIM zu+q#&DM~4c&iBsBIcH9_S*Ck$FUT+@up7DGF*_xOnpghMu7T8|<9uM<&(A)J>sd@W ziEl2!jj;%hJPjK$?m2S$NH?Kw2FuZG&cey*e#sqj;H;O&^6k}Eg4kL*&%^4KMQHsr zCE^sjdR2r3*}Yal#VS72$0E^OFoM;WKny)rbPbqw!9DXc z$L7p}d*8?AReD9gorYr1)1P-Dqh3lTu5TR2>M||Q!4)U>J!X_Fu?p2PFAgmHoPG&> zReEksZa!f%b9d0D*MavOAT{>eodSj(_M+v(SEP zSi4g10)}V0Q*xoyh(+?!<1+Ei=4{esG6b%BzONc+#ocNKG^70$Yk!q1l_j}X_Z5vO zD7(1CYQ`65@Cq(iw9?@pd3SQqhVog-mbgWP&=RbuuTyQNahq>atqsY&h4OdQ9wDnN zN(^w84QCE9J_|_B0g>%VjATc^MwV>{UA<}N+1sJt^VFS$ewTWq=!cBv|GK$D`g9U(&w1)zbSWPAnr&Q@UMW`y*tBCg#sVMwy*PE z-_w&lS6%xY+RzfI%R(0Ig|MkvbYo4pQ&fM@MRHr4;zVxoi*O%?i#o{L# zxVjj5ei@(%=E_kArn;~4C5gpOTsgLWj4_r#8a?5L>Bc%>=g34*>Q(rV%WcdGfr1oZRD$X)qvVLCNiyBHwgeRJg=>{-4fa@vbwLhVafPHaaeHwqj*g*deQ2LGV5>60AoVG zN;WJKW;zdc#^+KX%sw1G0>Uvfm1nc8ScFPF6XgRRxZKUZq4xP*y~^!ahvxk+IiT8q zfzZtZ|?mssGD`fc$fnk*qmX< z;`7;O;Ae0YL-cqM<@`?y#X}lCsKj0r`AJ{?{#RR*3y<{ZnLuRK0q9v>Au8W-5yZo` zlk#A12_JI%Uz%wiG#MHhHx=KfSlN&rnN~ODK8S_NvQiz9I-UFN+b_ z$BdmKYu+Zdq|~Udf>s^2wAoVjg4{k3Z}9Q?pU?i>o^>kGYefs5m4dzCeAfY9@P%>X zuouBX4l^Mi@VRW#qsbGMCLX*tqh6ljN)-)dGQAZ2JXJ4@ipN=h}IH=hjs2RKBLuygVlG zCWn-=Ku;yaTv%5t`gwa;0lA?+LX~)`i73(!*dxGihlf8{=<&|Fl;B$5B=4bkzvVIi z^|vS7SQk@+GeLy?Slx4E1d$Pc_`LH%#3+q74j?3%b%kJo4io-VSB4yK-W6%S7XxS6 z?HCQhD$N*EYFL)uxn7EH%(rb{#TobbpMncab<&Mt*_dsO0mY68)h|t2G{yPl`7Hqw z0Nkl1CWNk+v~`pg25L)>3})Sx>#A~)4*#*nHs6o$TF9)LMRCJJaMdCU6ZTx#<6!*t z43n%ClN;h9f{selr2aCwN{MnYH;%s0*;v5I$Um-AB=_1xDG`|xgkXT#-%YX^2lG`t zNHZ^-U$!^hSWH%|Up8ZDf8|w}g&j9pR|kb=53D|io{qRcg#k)M*g~=(#wz8V{Rkc@ z`hc`xSZo&sWR&S2EtE_c$e0G{;G1oEW-O$ox^+@u=zcUa4B02zSk|v72^5HWQn+xF z-n5hB;49^NxO0jRtJ_td5G>S7nzKB9fcG2iKQ)*#NeQ~$)qT9qbgcCyf*s}qWR>{9 z_lR#-HjeO)M8CX}O=}JZQ$ahsg-s{#6yG!#TdvREW@eqn!*q>ugSys4M$#?dT}X}) z_Yvi4SH}DEQ?JZ|&E0*Sap%D25&pg+)hs#u1)&ogGwTY3-u}xQNv`jHegmfdhAuOT z+II+(E;H4gxV%w9ys!xdxp`)`F?`V%pEySfTW0M>7b(32|DZcBij?r?-pTF|WD$Z!OhA+kX zB&=Vu5DVDQxO7p)aUc=lZqC@>dG-rf2M08#0$C9!LTRN;T_L%zw%Ucr6Z84q?JTW= zhQ#@|UUNl8q@8n5*CVeoZioR|Y33fYc+pr-K)Kqlu8e9zFivi_CZMi*$xQmU%hJQ# zCY>}> zan)w)Q8(|~EHTEIwbadmM9&o4L6?GeCn8=Yk>tp(A=p}OZzrW0syQw^tncv1sjQq_ zdwYr_sJCrgF!&9rei3t4qh};3)J#a+2qzfqGu{dCpgC+kW1K*nQah0^9`1u%4qjNa z_&5tU4`LZv@FvCN2%7M&FnftdIW8ET;a8UAb-8(w?uX`1$C@MG+TpGy#nk&u^|nA$ zl|V>TlYECoul0WUs#f~!-E^ZYoZiPwP)~GEIp~r6j~`fCQq?Ae4FHwC*^xti-%_dKAxAu=UgARp*S`4c0#j5|3=(#%>sWd=naG68D_(Q1Tkt7@Kkurz8rM%N*4Sw_m^9kdNJL(HrXJAY2OU}2gT)YnAqr6>$ia1Y^BY6h&t0g#j4~wZectIr<2m4hH&pX z!fXTXWR8JNYC@E=Ot-Z*J?78Y%#h8`?OHy?d?xLd@U=SQq0c zLYT@$-~x<=bMI`eVh7@=*H_pkeSfl@-fXSO^)0suD2LtuM>H;FQ+9Qe$O@7DDSP0lSI=bm8iI-&m}im?H+h( zp;-Ec#&|!Mn82|Cxq=Xlf%47v+$QI59Gz|##^tH@HK)y+3P|^nUb=Zne&jTip@i>u zWNN6mJ6r}uTjNE${h6r`#(%c41plxcZxTLvC&_v|sDpFO?!i;{pVtSapIMo5u?f~| zn+o=C^CW<+FG36LU|DO<6T-2KQHf! zwI}F~NG~pg=O56gxP939Y##(`>2oxLlFt*B@zx0i1V>cQ6+6n>Oqn-UUYTWxenz18 zY53faU#1?-_5rMgZs`MG4SWw33{Wc1${_{J6dt(Z6j&V3#s(X~`(D}gXo=&;|4n`5n*|+hpp%sV zO`s~{gf06;E)rvEqj(Jo`Dr*sBf&g~k!Rc>r$L&%p43F&8I_(x&g-uF2iV95N6P<9 zW47ViC?oPc3;ktf$;-Bzhn8I`ZI}AEE(NS^oJ^#;Tf}wJ6VN*+3DJ1#IG}`2Mfldj zjC%vfF%lNLJ{|V=X2i@^wZF4zJ6{;PpsmAmp@1U>6tTq4&*S_8CU#hx2);sL0t|ch z8Vciq{-;GWBMj>BSG1u|P@gH{B8ON^Sy|_3q>B5sC~{x=m@ZeGmu8c$N1q6SE*=@9 zNKgIQ%oJXDcS;cfc>#0VqQG<7zNBhj;ZJ<@Jhoixen$7=!2-V-Ni*Y((8vg#3`??f zsU7U*w_YeCJjD4O=Izz2+qvQD3JVi~LQLirf2yx!s1GvORrC>)g_%$8zmS?y{=LQgiIUSrfp3BR=~*x8Sk1l#$aMN6yCYcR zXlIb65nouL9oC%|LkCIm(?js(UXSwcUH z2RD?H+|ih*AQ|e~E9^>jM9vgEX5Dj+rzh_8`-GUM0T3sq> zzmWaW6m4$^yC3ZWEY92_MfV~(7n=vUNwALg-NDWXm@7$V8D))KATG{3w&U!RhOYO& z`)DP5A)uii)M1V*O1Js}E#}iTcHx%}7^WwJ%?S_z~YAWhD?(`JvetRZX|fEa`zhN1CK{*9u?6^{o6H2Ed11AE=Dx?ZI8hD>cO!8 ziPPdO&-f)+`&<*H&jJ6~uMOC+GqqnKbbjmSvt#Jn#gG?!XCp35G2r`g@{4o6YiVK! zc;rKI-xu#XN%YMQ$sjr+umL8_V6d9InZz*T$)=RBUjL9aH1n3_3M}qc_)VH^@rNl( zf0P*GeVfeNPvzDEpr@%9bDg3|u7tx~L!u@Y5z~ZV(M%L4YINY-r~Jf;KeGpH=Yo7f zCqQX^zK;yNy*!2&OV2p=qx~AuF-{^A5enO@{JS;E_I5;GWSLj?EuH>{6RS7UaW*+> z90~Nvv#dgm$;AvkHD@4KhAFIYwVbbwSw!U|1olLRoi>FGdT=# z`INE!&d*Bpx}G`#eW1|QU01?4EGiWqvbGwzz!(kJ5>3*TcUoR1NB2q^*Js>$Pgr?X zDO2*eg@xH9+uA;TX2mtVR`R0w3l1~fw0mqGt>rP8gF; zSK0m89g`UN8u}Ky&Q#TZr;QsFxsDPehU{dPk~46t@w%$tS2?MnSjDj3tY8hkfbZ5% zUF@Z6P$Gkc&mFz9@4V$zl&^iIZ}Ju03St~sWz%JTAOg&vl#6f>`72KiTJ(843$EI| zak0v2^ABiYCA?mr!!|?;Naf8;zAAL#S6Uw0b_50t%0d++q_$CR!UFpvgvV<;1*kg2 z8&1-VllxVQ`wCA6TEDEdPelyV503Z6vOK?9XvVIR0W~9!ksQY1{)I3N08v{}PU`DC zk+tW`*Z;-IZUDzXfyoC5jVdw}*ImzbeWKCDZ7BTMT;5`y5j$PmEy_=2(;kTTY$itq z1cu=(*vCT8wvviMVB^0hO?4I<#a~O>km65Vc*M3AhBo zxQ{JXbM2a#R5nRynXDLS%V!lFi{3RX`d*`nVV{IjZfUNq%8VRu^T5WjLVjcErB#a`X;S>24lXRChIT zX;H2D8GBWuD%YNbyhRpYlm7!s6cHphkSu*GVNi>y#_h|B_-8uC=H|OArqUKtgYL~4NH3$N9!t{>#-NuZSpm!iUP9nRHnr`jQ5&LsxQ zia%eud!+x^c~tLUz_ZIVx(Er4QT!R#9nOYr0rE}@+RU|_`fRCBSQyt@q5+)#oUV9N z>bK9$(<|7TT9Flh72YjpZg17cn3syF^4}5XXnizRqGm$-Jz%%npRY=|hfE#x=l-5A zGk zTa)YInx#Nzan;i1LKW{!Oi}h@bCQir#?X@B@TfI^?FY15xUxARqz|zmiABeVr4IKj zh^9RB`#CHabjHV9qq2BmX~pn_^01H#9Hn^mp48geS<6rg4^=U)TlW+J6&(b4@af+s z2P*FNN8!vxew}I%S|~NASSa?Y8a`6C*~@d1;9pZ3?|b^K+v1rn5BVG*-mFjfx=~iS z;`6kmzo}|ld%CN23Xo0yE|(sba8L4D@Y{FqBqZJ?pIv{!y82JDP(FhIrAF;Rb`-1r zfHwO#{y!#8{)aNDfGk`1fW|`}z$?eV4@^IYS?PBAgN2lgG3?#TD^{bt#u1xF28Oe6fuy`OY}^JTl}?g0K`{M0Rb&m(t_K2Za{3 zKiBmsCbh7g9pii+Dh8X+hV+`TvxuH1cg{fODlLde%&ybEwHaG%58iBADPy?fL)NgF zgjVU*vF1Rj&@_DwQAt@KSq_awv%%>o7b1p5xxrk;Hgm8pST^?S=8Uhi!IXau_?nAA zvE`E74-fmo0J${bSL`4f2XZ1@eoZ+B3_+|Bu_G4t6YW>lMwk$6c4Vssa>|K=39lKk z*_oPTKaT|Cy>(A|PSYjRT0sJIN9!*;@xxdpH1<3(q6u4ja?8Au4DHdbDdFi)D2BR! zzSEoJm(3ZT8%nvH6T;#4YXlT-{?F1<<`DUB{X2k61@~>k|MG+QGxHzCCICaUs7*O} zgMEI!(Pfk+dG@h9&%rExlwTL8cJiC2Idc@_zc9pp07E?K2H;|L{}qNf4q%AHzc9pk z$ZuX`BMeD{KSUEWENF(+t#T*1c10usyH-JEDht4%rFs4H7Z=|GB;)_`pU5VA2I5Kp zi9mhNGVg;yxH=Z0;)c#rzsHxeH&JY-<#Kc9*{O?KT9=O`ck}-O=8S-ojRq=~zfZJ7 z|6yFSc^$M)n+NC`dT$6>9iVGo$Wc52x`v||sItu#v(f|1JqP6W+ z2JYMcrD-hAiFX!k7%0<% zwLhk_+S-tF;aqF^P%WdX)GP^x0_*@228TYa^^mc>9kJ8w z)&2F=^>N;ldCe0dk!eSVILJI;v01&+Q1l(mzW=lK#47m|zKi6dJvO=rPI5%nq(B5V_xR+kwht2$=$1s&k*s2q^n329 zvL3Jxzm2|h*LPOGi|C0EAW9(ws=>E$rZu~r$`6|DdL>o{?T6nk&6x%$7&?}{bf8XR z>(kuzg#12{Ag3T6weh+qi6y8MT`BmjkHm~k4Q1ytZ&HqVXPnzRj3+8kxDCBfHfO>j zEA}S6_XJ4S>^K2%SbTtvUv2Pc2CL$BC3>(;AMumwBlnjdEF_u~hriQueFMHGeJAz= z^ZmW05B)Fz;XlmTU8QmjuX86)x`a~K+st<0wkMOeM#Y{ zc?zN)GQO{P=()?d3nd=5@yG4CLNu;2eqK=qi2L}h^i2rs&;65gWKToDSROl$6TW`f zH#@0UWl8^E63;29}~mvDU!5_^As~UP+U^{`dq-H;q8M!Z-FOShM|C|6tezrTRm zZdq}Tfw9t)|AW2vjB4s@+kH_~L_nH!As|(0Dor5}6lo$xMQI^KrGo(#kRTxe>0MAj zL5YfhNR!?ZT0jM)6A21QP^1`1l(K{n&-%ab+2eiw&-3i_VUKgp9%GO917942F)cJ{3iuSH~z9Y42G9z z?wOUCZy;5YtEN`Pwji4wL6?mB|XMOXM|qU_1zV zs%@!jeP}SrRdbMrcCoM$Jv!i|!uusd8gS?{J`N^2WSfaCP-j!1nnl1I{qsb692&1q z)zU|MIbE92KGfdy(4f9F;?QeX^GyB^a4q-58{4%TJHBS#)7_S7%G=hTnHhf@nk~< zt!8#yK|#)X@!Yva!#g>;MM>}NORR4U%0z!teK+GQ!m|d8CGCX5>F~tOmEMeG;!(IP zX4Yl2qHb@Xwmx}OpJ`-MpZ#NZef_I~ukW(x17KU+fHO_w!hUlz6W|mWRB#nonDr7dJkUYq9FqgWD%C9Qs(W}Z zNIapzoABDd7VAu$@>N&oI<9~35)P`V64ptqYs^8Cgq_x^=VyS8J;oeCz zoNe!{{dTLF;xd@V6vl?oDEI207gGWCE~&hY^m>HLuJao^N9M;??QYwmHv(Tolt=bo zaeg1SA_@ zMMay$=WoU1EV_aQ@wR!W1Qo)CJ=L`q$NcS64%QNG3HS1D|*S|jE ze41}TNnv>bTei9-i<`lQcePlj^2IZWLmp~nKJtAJ+7H>f8bnS*XH^Aw@UgeSVpkRu z6kSEIO554cU|OrN=yJ9I^=%y^wK}oNWuAY1i@C&V4RFEF8f7E9AeCA!ivA9r-x;RpLg_aY7coY^F z+Wp2O7j}LT&w`WUsKQa406I))FzA_o!6CK}M>Wr|`K4bq0_l5c>Qlu`Zjh|r+gkEf zdiJT0mFcu2KFX!F+Yb!zvH{#fY&cVH?h2d9t*2|w?xJ=VFCKpG;_PRfvZpoc1aaif zV7T59qbF{=rsLc^cp$1Ao<`P2_ev6BFVwmmu;`oFli$l4^g%N!oRAp~jqD2MM9R6+ zN*B5Ogql2bMX>+T^2(hDHM~$kAOV1@2sm)}2`@A(v@LqW#Px{c~(Gex#a-o!&AkEIJ|@c)7?AH*q@tuDQLl)EGuzY$zlFrw)K!JSWChO_0jxN9rerZ|G-_YdLO4 ztYuazZdn!GQfWosE4zQ+NBI!39_ZfMgByY!2q}vl!z$5dg#&V12Gc9T%E^Uf)4`5= z>n5#D1R+rv+7k2f`X_#VCE{XpCAXie&H9#ZfRg2YFf*j4~vk*&(KYQu;8yaUaUe!6$sSgvjZY3KKYCL zOG?%T$bP?zE-bAlHC-dlghcpVZOYSCuKECj@zbXJjLMw?`n-nB4s~C}+ef*FaDzq#+AQ^M(D*;2{h-_Z7;t&r zVL?IJZdXgjU}No;L>Jui=c|Z_CR;Hp)m^s|PAEk|5j0B7TEPD@hu(- z^DD-9pjadK@c~r{KSIwm+l@CQuf5!J*mcU&`O$YP?;|Ixlz?DRZ01OB=fDDxer@n@ z21Ekz=;dmO0QVNfG#~5kc~Jb??YG}n)4+|+OpzPNXFKYy6TbiwEKOIyqY5*`fMm2? z0r4@QniO&C`es9keDY#Wrt4y+KDeGWq-b&7E|fKEd3tB&2M1s9h17b-`OzV%W_)bJ zmz%v0*!UjV$=bV_9on8XF)lTYwGkm6Dy=h0d)D&#e;xh3=hJ=R`y~2BAZXo}jsO02 zE-0Sj`p~!}wSGEC03f=o$(224XsjW181x@iV&OoQpvR7fAaGA7T)8DQ7b5f^V+(j%rp|(F1*q98Lw2FTA!Az_ETh zLn^R-{}|WuY=2D?Dp^6fofXy%lLT7r_fhUD#FhFx(&I1p`=M1zGd~4hB!^ugl=(S= zj;)9n{?!60+NWm_h)4M^?+?VupEo(41p-ZH?E!Q#Rvl2^GR2J%WykBiffPm>zSBwJ z@TAXpWu*#*iFF%E*+RVflKmV!xs2jNfAY$touz#t)RNHKPOhkU+yRzhW+`$}6l(!) zed5~WOWi-7o!q#%*iuhJJU{TtLfKYU`W@eoYWd|P7XCYO4ynrFrLD+tF6Z|Ugv_J^ zB&n1HC^W>mLU#tOUp;o6IPOU2j!5Lt>mB!U282FRkAZ{-QIb!PB-WXQO2MkmRV9WQ z9Y}ECZ?An+ZW&FB)G9*@UXreQuA!q#oH^p6e1_LN}6rvkGEbuAW-*;jK-R7 zKjJD+VXawVJ&-iKIEfAmN-&hl!AaG{oXM~e9gO6u&s$%coTq*IRNr(gb=MV@CK(TN zg&-P?AI$qH;T({m^x>fG?5g$LuE!3)#ZV^`F8#Za z%vH$mcGm<-+1=}LfN&KiqiYzLz0iyo*G(+=FyGhRP%L2LQc;JgR1RlmD*c*zXLabb z`H`0y<0pxtzh~>T34Iw%x5x*bx$dIe_gjWxktG)ziCb_g^n>AVIVefv+a2bdG|U)u zpI89|hP`?ZNf1WAHB-_xB1ie%jcB|=;WhuwhL(mS*CHZMFDrN+ zFFeiqB#qd3X*hrN{7NYYzNHV$o&{nmu&1{PL`4hM&pEQIV}4OUL)hJecfZz=rbG?e zvp>Iy$oGz)7r672=%Et$y7hi0q6XKWw>#te^T;htjE{3u&6~Di-H>bL$R3?9ADr77bw+y0)* z*)dmh^m>l-`RSxfE{Bq`j>}r2qd1{nub1!obfZ!fYo)a<@r=PQskTA`>H#~B)U12FHH-AvQUw?cPyo_m3zO3vVMzsg%_H7s z>cd*`ndp+vXL<%jPYid4pP8(fx6$#)^Oo8{ym39sY*#ZdMT5n1b%1WKEk%E$MVg

6p=(Ty@5}(3#=-g*2w7x!GlO;gsnB%D*K|wDJcjEdJN& z9N1A<0C;k*&h2q{4xs2hX*iuhFzdHKc;beErjTfz26`>vQAlY{gq+FX1-BD9d*#Jd zwMV`Pq`l|qT}gp?X2^d+VowiqWw956_5#X`qV1U?hP_PPiBN&2%K8&I^0uqX^Gzw= zd)K7C{Zh*Bzl}U<&x0W`A*|MJaF=twb?fxA`{PYyxvjlo%W3O&BY#&#RV?Vi;k?JnV`WB7u;Yzb81vNm1 zd$S~~;l=2?u=2~3F^`1!6Z14wx5`35O(-de`FW=g>9ZM zdZ9)-AXMm5OhAWT|LHdUNKJC&P|KT4`QCLfPj(VtU0lne&UQG>)>3--IZ726_3j$L zH9R!(WN53r&-sEcGj9VcV%LeFJ1@ZJk)8NGqldjz9-zBx)29ayif^@iQ5-%xY5y|O zq^<_2eXUkY4_`a{y=qln+d{4wVkgzVboG(G40$jJ5*Tnzn(kE)2cmE)z|x8%d!t9-v($xrvTS7RUF==A89BV(Svxt1p_g;T^c~jE+QH_O zqu2NH{N||37%gz^0&YXG&a+O_50ved1FF01RVadGVeUvRZj^MuOv&B2uX{568&KsA&fk#RA%MhZfR+11Df7(dp4 zCE&dHE+W|Hh5=m6`4e(>38DQmWm|Pd;&SlQvW|tlTe|BqY;bL`2ZQSE813ihT*pI9 zt=(8#{!W3OO|1#m<3DaNzhn>TaL?GtB&jB<{In0gTk<`Vk+Bz((?^EXqI!0)mO@zt zk7-OR>XuaovZ1wlf$Z$(|cjaUeZChe_*f$#jPa2yWO(nM+) zxt=@F-m3Ts`5Ad`!^lX?BWet;Njy3I#FG(aJPUS3|6`Kl{}i0muRCo)t1loFVl4qO zDg^qt54NiAOAq)v@u_fQ z0S}tQ%DpoY4bHjgrh{u}3Gh>#O!-FbmbLs5YvfM=?3_RYmvq3r+2A|8mja zkL0TBK$ZvmZ%*s-e-Uk$HU5KF^%t}1pMH4%4F8uX209u7axVJHdcx)Dp0&}o2+dr# z#POT`qPy;j*qD}iaK!|Ke}9bx)eb2X$3NpA`(&q|3BmyzE!em04K5E7&wdS~E57-| zQ{XfU>;M(2-m<`Co*uCJf3KSxj>6M+Q$Vs@;oq;iiyP||oeAsUWE+MgFpb?G`i2!>LsTqHGl$}!kUHKl2 z#Zt?IakiFb0kv`bZ`lmMULXH^V*>1^d<9~N3_>4X;8Xt#e-2*4Y_pNeUk~A06>`Px zA>7EdAda{{jFX1+0$aC1zo1_s2#F$sEwT5|;D4P7{{Fw*gNx-~Nh*21e|Ubal;LUl z7eRZ8Ka8$F0{Ts6!C1UbL+~1JC;l_9>%VUd9JPP@#O6UGA@j)G*?T8wV__ zz)Sapt$z;>xXG`GEt^P}IHkh76#7pNA#=X}9__zgg@5}{|IeF-IT&j)^$IZ?dizvq zR;Z~9*Itc#DoOW;^zDW(J9qrfefw9|fU+E41JKpa{Kz`3=V4;VPPtg7s zS+-?<(t3-zIqbB?^)K_b*Uq@}$y|HT@g>^*sT&~;_C**JzptUervLMX6O$KqSRVMd zKYV{i{%hU%yO{#GJd>F7(yvtQ2@PGDa&@$kR7{Gw`uV!#JXJ)M}rb$op6F ziLfxJ(~Jj`-i7W6TdB44`{Q5&u%{l>y>Yb>VPVXLTBbQzQA<%gx!LO+m#`x z#d(ehpC@jvc1fN`4qeK!f(v!!n3wO^a$(1iH(G={NOG91PRgssyJ4|wXpgh)X_qiP zZ=Cy0+uk444{XhL-XmCUd{6TiV%=`Lxh<>`s{&M&b8d}~Ik5Teg%q(B9;-AotXnO8 zV2EX&7NefHm_R*ae$4H`%{@2wn1OcqSdwo5jCUDT+Ym>Okay~ooaO(4g_Qsa%$wwh zh|1zeHyDk_>_UpfoVZ4bibFbl2CNUHtsNX+3Kqt?-aBT8*8ZUn9_-l)8dXfG@6<@* zYh91b_a7X;JXE^Z<*D>6BidYnyd{qNSO7MN9cW27!h zg|BgR0-1PdBoxmlqr)6*=g7J> zzU*<7LDKddeyI4^LC{HgNAd=Es0#bO#@;_W7Z}Yp0Zqd~s;tX6sjMwtvQdyOTg51$swv9)2vET`q7~H6$q^D{Nhxhtiu|qiGFKz? zN){;>Y;LAV3=AEqdvpKX(zBX94(a}2bKTY!0-!j85`{7c2Q(iHb4`d{8+4r!kUnJR zbtYcGA;>42_e23+>+LjwPhG_czO@^)2M@8p3zmYB}mlo&|c;JvZr4r@Vv-AId8TT*Kej5G!?_h?Sv#xs&`YsmT|S(a8E`=MEm_u zWPh{{eCkW)O|^tur{4qa=5O_Pd=bHPudlWPelKt%{A}f}$x$Hg`uHk|2RZHRJngnv zTT}A_`C0!Q;(h4-m=iZ+aT~X&k%%6AeQp|5b<1M$7LffdrQ;pzIn=9cLDtjJHT8}A z@0xI?{3q;t#Vbn5@UIf5I~2gG17?hdV#ds6#2V{&JFo`FZu1ckut&BFuy`6+-`UGD@d}<3J9!-zPe0Znv31Q{f-8Z4=gschPEj}jR-Xs&){^{%lW;H=R$(VgxT`ha z-UtMVU>*1pD(dZ~@%7{)s+Kr%#$CJF%cUq?QGo?ID*KgxD@kF-^)(9)FR!F}(5 zq&cv(D~k6mn~jF-#UcV|@+MtGi8}WF+6uD=`>Vr(BT7Hn3l%-N`KhMoe)&!PEHk5O z6RX*Fx0UEse8w0SET?W=3?K;&rZ)%EpXznvgjtro_17CI_x*mtLp71^J!3A@`oD$} ze=_SY|KLp}k!7v>2nhrQ68#xgiZuh5redZ$WdlPeF3ZsD<+GRpH+WhAdz@HR#3&~OHdoRPeF&ix<=e;g9C zF0D+EA9t!MUTl!OKjmTxWl6?;J1pu4ZSa(l2D>2?P^|p9ASMLVh^ORw2%^_U&`=Au z>nv(=HAP!Z)w1Ru#vrWvjG0sJJmOhP6%Y#@X66vQc?AM zpeh4;ViJHDM!UK*7H|N-SsF?W=Hl6V1-L>n zNUc`Sj%j_>H{mV-1k8b6@PG{PFeL-^DG4_=ZA=K!6~G)>7!te}p!Q2Q)LYbwsbbBH z2l*|j^b_x+K*4~JN~+IDR0OK#f_5#Uq@l-HulqZ!DE75T#98DeyvVX{fc!)^QfRt7 zWZ@jE!_!jGt(EWhY03+AFdI^M&WLQo6$6ZV^Q5|)>x6eK;M6BVwT-)kMRh7(Et~Xe z+4pOqi!HwT3|^c!Ta$}FbzlvjfRf}2VO@bChVTx~;TT3>COb*%2dyc?VeGr>haV<} z^#%Qx>=qCC)P{XNUU%r6W=*zMz`H8ESI|L>ZWmsVqYh5F*ti%p&F5Eu*T2sxR&{%GoGBw+WeL)(cF)=KuDg$$sbgV4MKRVU zD@c5C({eT?-`ws5me!l+#dw&VzGp~JwogLE*jdOrnShTeIqDM^(U_N=K%ik2`_U{hIr;@x;=`*Hd zSRc0cuTEEV`$iH`730yXht+KvM|-AR8sVJuoy>Cm{23&5)X%mGPthgWPBEOHDzD&*6vCTR` zCu}Po_;ho}2dg+%?s_7LUDZ>SO5(>#6mtY8LUs2zFWgl~3)6XuF+h5M*kGa~BZQLj zMwPzosY!cOmyZhX*taW}#K%2?8zxC|Ou;rYj#>)sbLG=#0O1_l@l~k2;ra$LNW|IJ zQ(IX!_^r=98P6?verV%7MA7k`;=z@UA!;E5oP)9$;foI#E72=eZC;@VHVNGqy|vS` zi$3@KQn};$Mr-44(F=X6h_J1`yUf%|#77c%l&8Y`%;bSG8Xhd4?mc(t!%#0sWPpN< z8QF6=EKEFCLuvHt{z{U6Q}j%@^R;KOO1t#SGGsuE8!V%R)J=#X)dp6v-Vb#f;srQ% z&zEv%PNZC}&g%+@+!?G()nCRunH3nc_M4sWmbS|5&ysC0Q{#fji4dl`Wi@b(ZA5l` zVgwV{&ye)L(ZGZxo%+hce(bMq|DA#&!+p$iVJa$tv$rYdUNu zjr9P(&gzUGCA8UiKX%Z0pdMW^(DK0FIFO+4H0+#jl8<&YDULEIAKgO;ZE3owtTvDt z4}v^4n3`LrfO-c^$eR^c(o5i(!W^gAOoo`atS$%S3*q=@yqnVM_4a*sIc{v8>~=i- zx_#Mj)NMWPI6ZgjFu;p)Y6!q8G5if(Fx{bUD7EFG!if>?Nx-M0K&XZi zvLdm#iIp^DEpPm4uXDBUc0Sqo1d?^z*&>-=Vjj zaV+a5=tN1XzOh@&{;HynhA$+iXu<3GewPkk-)8;d-Hq-LE9`+@+0w>>1gTPv#iSNj zZi*u^7CMw5hH(@!`0-ukfy-ppy1+6b<yxT&8RS5vxBby7?T zwl%%7h@C>G1L4oG(7H*T`tah3@=(5swMaNT^5iA5*4OO9#zcFS>3Qn;(;kXnc!%o1 zpvb!QY*s$F->au2bKpg80F2x+|F9)D`o-v>bW^=kl%SjsR79i=jOx`IYj+@R9>?q# zjgp$**8DrDo^(_{BNkG}ZDa*?;H$qSL-~Z_EcU9Mh}_q0*xxS|W&Hjd)PsRQ?ZH^PvEw%NbEuN}VWsDiZw|`8wAbT_ zw7Il9By<2X-F*~8>CD@RseE~~yUH&&&ofKo-I=yHx;Jn0j$h`GCpZOwymbMC=$zdP z^Tj8cX^w_w2yiY=uF7dUbV+VP9Wy}+S@K&+Jy(=w{$tOE;}-Mf(=qW^kD9A5tx!uC zB`I79&|H;IXSm|K5Ocy}zC@AXVv>b+QT>m`+iwJtJT4VYN^dl|(cZ|seG3CqdHz@T z1g%&si_iy23~Ur?M{BBFONmH?!uQ17eDJbz|xkCG2QD?eK+T#W!Grqpt zk+URog%S`u^YTG_<IPVJ8wZw@y825w z8P`v&%Eo*?zb>qQb6S&Xy?0lx;^Uoj$tw(2E^{}SqInSrD8*g}FgOKYh_JRnN`*U! zsg^&r7Kw5gn>~NI+U}&6FOwl|Yxuk2!Tm>XPxAa?LguQNrbSpa7K|CnAc-$JnF+H4 zn~QXcXufrcg&F6DL#MyiHss7+5?+5CNEah3hZ92eI4wCp_%CC0XzUnhlnl}2Zp(Rh_dh*`4vnNx- zzg_RW@+f*4FO8E0C=4SeAL}}>$i+uNMQ@b@4;&wt#41gWPND0fztko@esO$A!|U|x zTUo}kC|O;inJ-@SdebmxcM#i$ey8e%YSBu9a{jq`;+x59O@6zlj8iP-2irytSU?_~ z3vBJ+UE#qtS8yp1aT*weECx=R8Kr8LQ({{PK5qVm}4-cVb8jnzjS-Ge`mxVz2z zEwKk?y%QhbIV+kp{j=ta0)n2~Elky;g>~bFmW|b;LQHQJva1rY77;WJoeH6u=)z^M zw2Fe1S8meGO9-(ro7Y!VU1asI@)!&(6ZyBR&?Gt<>j~VVg@crmj1=R>xYbvyCZ=%P zNR-X+s;`c6+k|`g5ApNp({wlMeOi^*-%Dy;$mRiU0~}`n#MdRG#BqYlu3t;Y+t%GE zVd1op{4%tTw$4xO3vJaFg~)F2-a`~iN#~=I_OajYSU6?jh6r^VWRxW50^n7M;G7-7 z>2%JKgqJ{+(W;QTZR49JmS;mw3iRw~w^E2>YiR9MM18+V_lgiPfi@JYaJ(H*Vr$Z> z;>->#L-vL0N&;aQ9oc~-hL9eDIBAgbYCx&#M|tIsA2YVQQeCYsWR_l&cBl^+g37Us zK>7m*&cX>P(+OrQIoW2sVEAI{T+ zT7y#Ybt^Gu${ej~_C_iPRtn~J@g-J#uV0D1V$og>VHfiqxT6(*M8(HU!3xMW;Hb`F(4+A-O3W?3ayQWTLH zIX}}|46B76>uLS)U2w-V$7vMrR}t0;D*IgCPF9LF1>F`N{Cav}Myr}QR>wSKB80>? z{Rl<)scZ$HrZo42CCdnYNOq8Zwtt0D@O%sIk2}o%ypho6QG(TB=|+V_*gb_glSZ}c zH8_@c){B>Z_okD5#W779NeX^VPMt;3Meb2_Ei6q0(0ybV_=KDMGB3vm<3?rk9 zu+vXg;W2&icz2Ji+T)_-um;0Sfv0v(4K1YPh@4-P8o${lgp1NbNPYR zM$dYVloa! zB6a4M-6sw1#9d1&pw4|?F8L^(=cQ*aZqv6f=9Y5AItq;G#_s}ZOr82>`JncoaGIN> zcnp)zfG4(DJX^{=X+wqUXlMr&<;=Vtc%A7weMWT0X&O`4TmiwtuNO^#aLZF^p)e|+ zJ&UqllDcLmq~0ZlahI}P-7-DvjMgI6zvP#qR#p^VdUi5*Bl(K0qQcPnL$JNl274l< z4f9SlX`kYN7hPP z(a~U(<2M5H(>>sdwFTf{ZPzu3Tmk9PLxC!hC_}A%^ai>v!qn=34Xr(%))#s(M~qjo zDbC&YO_NfGB5zR}dxZ&B@#pq5vij(xBs5O)6fJ1qf^2cC%H|p4!7rQN5({%Mr8QTffF0D9~V)#Hs+D!pUuXbbA3r)|g}MSS6h;99Q94 zXZvYMSR?}R^5KI+Ihi)9xv7ogp!ut-N*rXcNIU}zGCvXh3>WqB&`3{e!-CkBQ+vUt zb72s}Id#UJ-i>}s8|JIV=yJ_BAnTHo_|>^!q}Oenz+Vl%ecN&MgzXcbDF1hZFYXp@ z3?`2Eh4Z|dn^mx7^MMwoeNbIGMieSl?0?75^&!`wEq>T-Ak{timPl6cy6=m|Q-*wx zE~f@=%U2Cmr8?s4u5io1qy_~Qz_JAE1Lpnml47b{f7w=N*dofjlI`q(D%rzP@mEK+ zdrrH^*zo-5xFB3!H=8K?G`CX|m5e(v>Ny%J4b_As8l-7vXN}Ue;wAC zG1^N#EJVxs^*-fRj>^wBVWHAI+lT*tHfeePh4VL$dSy-2K8+Xu_6PQ7^uGi_&`5$w zFi$WaQ_6R!O}F_@bFwNp`o7Cxmk2^JX8a0VfXdNjS>;iU?$L+!g-naW!6Fa>aYAs^ z0~>$hw9a}*zlS=n!3Yq*wH(yswt-%VRoBVSJlFAEcJ!gmeN%Ya89e6-gp~yZbMG~v z08t3|6v3pZJ?b14;z5u=QIX5tW&MYT3>qW&brWC1EV`cJzw_3I-GSg6{*QkOdc^!7=`Y*A|SLevwk794&?A;3pVo>TfeG$0i&C-bhicX!nu5>z(11mKeME$&+Pug^E|^A z#EUGzfR=y$wf~gw2^cAEys0_}DS7sXhp_N<)gZv-Q;Ze;S7neAnLw^FN3yAnfUHa|(14@&Ds3w!GKi1;_F4 zbHkeRPlLIv@oYc*zi;aQ%_jw|?J@&Hej2i&VaDr^#h=0*?`zJSe)%$YV}IJcZ5ij| z1+gO5ds^`SJjnmFivHyn`}^GZ|M*Q;@L&W3BM~-Jf>IZ4mC>X| zk2psa+RpQQr}9>p{%KPGKQ1w2|Fy*Y-E;E00X7ZhVq|gq&q2iW>kGIJf~Q95qHc!W z-)x3sqkP)Rqtb)Z0~Y_5?ZLf^6Zg*}B*HwZq(M^gY!^xdAoPG-TCI|E6n*Bgz>rzP zlj!v2{Epxt?V8??f;*X4?RNVp@@}*;hEi5I{47GRyXnX!fs|QcOxWcKrWj4HQ)SYz z1}=SHSy_7O{+@mBZ5B?=6UDc)@j>zyjBi~-N$z?;iAT|5URC$BMHy7q)qa%Ji6yRqKfTJV(ZxhPF1)8JwU*HqNEx)85%gFSsx#fBJkPORB<~0 z#MzEBjbi;9S3GrkSj|;~?M~}X00XMa%IWVUDp2&R*?Qf>7%)xqUk zxC&{*_t%_l{C0j-@>=K-5gvwotXdxfecTzsoHJ}#FQ(0u{?w@R*kbT@<)C_Pv{E~w zIP+UT+2dZGXv3>j4isg`S&YMaE2snp6)jWy;-R6}!qN16TivyDeYXVPxSqNBYj07K zYLVfTrhS7#ZfMCZFgZ$QCk)_TC#HZmB(?^a_ zKOIvDKAf6E-N!uAnU4866oVHc9$Lh|S?SB*_s2<2Ru~L=xU!)wcOIJ&Zpkyhgh@7( ziFfi^sbqV4DeXHfc#0P!-}$qJnQ3Ky`05)d$oCS~IMF!L2;Kt1FzsO9}*$?N_i=WORwtTtM`zw4*dmL+q^fQhH z=#LGb1Gec8vCS%h2CSeY{B_;k)7-9`K))^E_nMHZZa4N4- z%-4;Vv3%`Mb+c^s0}>g?~->;3TR$&~5f`$0$||AhXpGK<=C{*!VBI z+AiBi=1NwNg_Z@Z2-}+YkfSA+E@-(2g%Lbj}CFgNCXW=bucz&ikR7ObUAZPJTaxAq>`E zXrQ)pER0RL#8OW+$l$};vi4{AR-Y2gf9Zz)T9X&Lbf5+mPnYQXE|o;!KWhSp$ci*>?K?7SppMX5o+v?I^^RN!l; z73}w;_IGo;!PY?X#*7I26J7)=9PtXXOs^#B3wc{T*HW&mS31 zxgAHJ{I1DZiN^^5Wh^7mmLg2@BS-^MJyM1se+P@d#YhvkseW*2Vs$Up2`|Ad_~|ko zpWPv{?)ch2*Cfe-T__?s8zlwRT!bu7m4NW7f?cSfL{>pZvHx#Sy zF&LkT7+G5Hfbvag9)4-X;XOuC_<-%RTk99u5awaFaJTjO){#)t>s>HmS4l*SLBmUG zXxf9?+CMxm-yKUn>?TCKruAx%WCKwOdlMKmN(y3{9rfex%kN&lYcNxWe+}q51^nRw ztSfJHnK=7ro(s$MO-+4p#xN(fa^PCoJkx;&16!FOZ%|}N-1=SBZ9-B|n-4?V2R>Fg z7a^DOmWe$}eW(e^6NwHLL^VD5k+sw@m)BDVTzQ5?0HyR-Bp$7*aB<4$s{C|D(st8Iln z#09yl!-EQO9_6|0oRmWM!goHeXQ$sfex`@~oN<2fd(LIY?zdN)h??7_FyEoQ&Ipb> z1uOL24=)tRxh5QsuCuqYTSm#cxemR;`&dREJbtK?=rphx@HOY?wV3SR%U=mQuV_=ptuBT8>K63FCA&Sf4`?NN z=HER2MtV9&+7%80i(qpF)$|}C?f?~%FxNcJ5%rjh^xqBIIBx`2?d2}yceQx7eA)C# ztSifZJoCX9ZPAoAy5euYA#2%t>n+dvEN~-30c4ef6dMdjiCzJ*VgKPtZ*zJL9Ovqa zeD2>)dg0$9(zJCo%Xw%2$^7qscowP;TitKkU9(qT8+HTCeiFe5BS%*_y3d#JV&Bb_ zr#MGPdvha>{nZrXFRI1O#&nCm_j8e?x7i5paqC<2A?aCHiM>S19GzRZm=@JgtVm9y4Y-@sjV z{sbSF+p#uVBS~P-wiE3e^CE4Cs>)m~`@xNj{$^C!Ik0kfIzg~z z*3DY}liu&(lRntaz8wBpbGh05up3oiEKUmmpF@c+xC;mIay%(0i_wtJvYX&I`Drbi zSR2f+*TYAZc1WGp&v>VGJeZ7}1gQ<_F`e#5wqIb4=rAETE2VSu>-y7MKEYujL^aab zY8j~-Iot7`cUvt z$!lTSlg(~(9XAc>vBVe@#}N1;|--d_&ye#*nWk@2eZLwX*7%C3Yu;G zsFH-|XB*855w>!QQDVf;`%+IH8>F^C`m7fL}omQGZ!WOZlSv4peU6WZg=#QfA=y?uDuFV;S- zvw)|i_0T~r)P;=aVC-4Y_o8-w0mcOKy;AlO;(uQ~*Ek!m3W(3o3|Z9i?jl)HMa5z=_8* zRtqLz;=8q+=i#-Wn+pK%^X8&_^0&%g$Fe0}=bAl>ogj(;#_8%5NK(gHZ&9Tewx zF2{x`=Hc?jsXV>CXF$5teU3MLyff(AQToYoX?gLkH>aIkB^kfyE1fVQrVv18wJ@M{ zXV#A;jQsd+K=yo(s2 zHp#0$xf@N`X99Di@BBzT+NOK%Ns11(8T~hbV*?ovcSel!I8)<=4_0w*&(-dnwz=^?_GY=;a}-SM2dbv(o2+ z`Y#R&J2Xfb5k_GCiBDQjrwOK&Yrj2Xpn4@1>Z$xwRh7=F?X81ye0JI@F0^xoi?^QR zN2+A^DTtn}C1?IbU^e?5PIt2JT<# z8E*4mO~ytY6#oPi@$G2}t<6seJd~J8EFT7-Pb`nuY#gr4SBSXWVqThVdeUV7rn+dN zn}0*waa)_uhd6Yd52{#-7#dFi>JbMezmf##RR z(PTf5NUp;fh3OAJ-7H%LApC8>NCPX+kO#&+^9eaj$C80}FS9IOKtBj=N;fBttLo3I zX1-`PsEn$b+#TfM7)q=jPH<0v?>}JNiqyPK*FL!Vs^r$$wA+q6g9_deF?Ov zvhR_2lu`Y17cJMu{Y@cx;L2Ev;2(^SoXClvzQMhuMq+P4_|7_5E|Z)$6k;tEJpu(GJ`sT>VVDfz#(v5_O~c2iu)vIQ z*Sc}QarMi zhCkpYohy#1dz<3;ZO(T`Pu`hmaWwD4C0y~mF6>L8VuwRf>eKSaq@&(tbcakyxx6BcNw*&mZmfJM5ZnP#X?uWna!y9~YLvW5l6;i# z0+cH;^8wpWJoV!KHAc;1W-)o5qicaShaA3H$ zU21}`{N>Dh?8usfH-W0C9#Y*(F9gg$S+!0!S{ilzPHHbsN>mRB@Yn1y>=(6;4t@wd zeBE5{Ferf70PY_V#;7oY7cEiU1vGqjHDd`r9vHh!7ySYE7WWSF)?4l!`XL`<_A;6C z;`=_600;La_5LsznZG~r-VTWi@KNBbuUP%96K(%4OQ-pf{{E_+M9YL<{E%Byqr!Ww zxF6+eJT}2cNHSG{^P1fSJU{WrFp9Yp&zL~-Piv#IpWm1JToNrAyd#mi`bVYT0LDv5u1VU1F5d-R`uatLGw2( zNB0ar&3$m?;PZPt$DJMTDay8ql{$D0_(tP|nbtHERjibOqayeTO5h~LNhn0MCo{nN zM_m6GkLZnTIl>UE%>?sDTp_#~+A;>sw-2&p=}ToC;;vuzrx zfGM~%uN`}LMq%4ru-+hH`NRFoh-b_wPnzKpC26nE1@J7R>BO>RF)(^oH?o4a!b;fD z#jELeO_G$q;`64dtRY2%H(b$_AZsDjL}48Xh6S0z$aQ5LFJc~ISkz!n)BD4rU!abZ zJa~6a34CT2SaK{;0Vw}qIpZmXHbUA(5#;b&_KlmGf^557JqH$5FsSYZ6X#fEb?4tJVpvw))Vp%8x;khtf#dvRWw(a?WPY_+DJO zGx_r`VGVAm^u8ezWEH)jP8V;dg8`HC34-)%uisavbF`P66Gis!hJHQht*y(n-#5rk zKk_2E)7sQyw|osgsQ@}Qg3gA|LfrE_koCu2 z+MI0@`>d(K;rYmfLQnD|cJfHW$`;B=Z%M~AXt67tp zSC>aA*S2*xU<_&%q@D^?F%dQo+eu_#h?y5){7r0%;jt?74j$s+(SjaCvT(Oc!&*C9_c9-Cjd z#*%K#?Yf_kXYxxi>G05}231G~H}~?FjDoMf8h%1%!TkkbtSrV01{hry&jH$8i{su9 zpXN`S#Zvmkz7*AhFVkLoNA5Pq1#7gJF1R~nM+llg*ZcJO7(S#!EZLfFR1`vZr;4|e zrS$f8x%c_$R-NQPp5-U`VNS}rgN}Yd7d98H)K(t6x!)5N_Qbwte9^uaxfMlffb_s( zW^|J8CQuHqL{+*q(N*f;fbOM}c+&ApL%nx|+S?X-p(*h0n!pPvrh%Hyp+>6$NXWJD5Hl2Kt6Pa#p%YALGce-Bz^Ss_n~%+6ap1YGDsY9ejk z-J0W^{}XiPu_yzR7P@=n|9tE_QiJ&t-BMTRA?lxd{cK%6*O7MWu?I{u0_PhIH9 z@yIOpJt(-1($Z-=+#b%M9M$yePf(b=;73OT{Sx|KA0ip3r|3%p?58%i3mI;q1)N@) zQpDIGE3x5+fGfAxq!XgnVYdG+N1Q@3XKL{S+sl1pro-z6_5FR^EGS0q6ZT}D_71%L ziu3H6l>2}pQq{=nZRXgT%p(6G;$Aepoo?<^#9_{s5eJS0IqBrC9PcW={WG~h- z(#bf!%t-?8i#gJ})~%SrmZr>!8I$eddunz;=&RK?7{Oo9>uv9<(IgUBvaAs&@vNnF zj$(Ao&GyNk>j!$zG#xwYUpu=N@tM;5j}27oUXX7Dg>Hodf(T&$zY3Xw^w%{V?InH9 zgBsl3KS41IXIp@bCe+`vbY1*h=iwhA5}NSOgZ_9`wM|MCwaT$s;A95(z(?gT1fX(R zE)>7di-i65Z>i~3pW(1%^e%yqU_xnNraVGWYaV`+&ROeU%s_PJ3pX{=HfwK7n|xYp zjjp>_l*vLqJ0b8r%Umn%OjoMNk562i!(u}W_!lB25;?I*DhP5H9`+ zGN@2zasfxgxEK7b$|5YG8Ufs=GlM`?;S#_-@cRGtKCmdn4@UwJGj9D+u$_9>nquXz z#AvKAt!kwYB4rd(=)K)95lv7VEy}FDRH*l@_2}y}1}b6?Or61(5m#_s8~{N=LaTtu z1`s4-0Wrt;uK=db2Jkd^bF5e(fQH#)4Xm4BfFR)v5F|LktP=qBU->UgoeSVwr~!5; z901=!$doCk{}*c`;4jw3Q5Yj0w0^4EiX{m7i*M2L7vF*p!Ze1^9y26ZQNv1r_S-F> z>rQc0zG{In3^2TZf(*X_H+_5-M;HA+jruQp>OaZj!2Ui?_8OF}LyU8?e}r53a$Sx4 zSX$KQs6w`}vDgm`8n~8NX&Yn6!xdp5TWSn|>i-yre-0;b))spYkbV9Z9fkiKPEgQO zdtfO479IG1jwaibwR6EgqvIbvBS8gttc!EbAjHE|7j_~ z5;9uU3a$EMhy=`)J8XX2RqxW@H}`Fw@tCbo%AO0p^*|rWAeGEwj?!Tp1bTkvN}|(LkGFd!GH(T+;0rq{Gw* z5url_6D(h%Id)qBz$I(s!|cYz30Zu5D(N2n zj$_A&JWXw*Y4*d8)O4u%%#{f)TiTxer=2}|UwY-7ev5BtF}@)|kL+vbcqai_`9S5RyPA_`dgBA0MeL!z6hQMz zALr%u>UwO>R)UzV3HuXIFA(TH=moeQ;2V75rSk#@jz2-{VD4NFx>8p<B)Sp7EXi3$=2kzjeW`*T{iZHxNz--3n+N$8qZag>;VC_jxu2GOG*Rx>7X&<` zClO>~bi?pnRe1_FiPD(nqHaM8`$9KvoCsEPY1A`;$KFnxmUi5O%&V~(i2ng%J$wBs z9#liCU|HxS!!{gfrL0Wk0_i|WX+NHTTg-a^gi*l}^%{&nSzQDc4K*bz zC;9Y^R(d3Zp>xK#E8hmU55G*9uhFxnOuB4`;M z=K!D><}m_6l7zob5FpiFvZrO`axAZ+gU!z$n*F2BlH2!$Nyp9D*()FF)ZaI-wd8pK z4iGGzgOm;l?7*dq&oM4BE&$_48^)U(Vt;)MVK6C||6_Ccp_^`C^yl~AR=n+xeLWA- z|48?wc88GP5{#DGtfC)P7t;#5T#o~FaQf%)){V(#o2r{>A1I+=8bq8wl7H~mU4yl2 zyocqE1rr7T1bGw1fw~=xHEo-$-mPauks&?a@Kq<=@E0#d78`l&GAw)B8;LU<+VkVH zHMz^LZ9%WqTWS&ftO=4dRuZsUy4F~~C=I0-U&EQhYV>j#UhRLk5-Pr+DqwdPk2@tCOal zzv*+!zcp(7b!fv`%V_9`sLaYk(BWLjEU!_^K@LW7-w+m!`r1Yxo~+J#!EpQNwL&0F z2Jx0QHa0lU84G8fa+!a8(}0A2EQJ$bP4Slc=xfnP{Rpmk%!O%!7&(jne7A(f?>4h% z5Zh`VfDG^x)a^YJVsmAnQYPKocMjvfc%a#>gQHz7h~h(Ar2OlgskxSY!^gwRnu0BovR35`SRbOnK0*H+qq}oKKNoPY#q#>N zN=j|!7OSNf4VEvs7>A&WR%s?MPK%&*uD498svB?6;nD+Clv}K_gO%P}RjHQyRv)e{zPp2t*sWqLFK!8; zt-A9y7`#EHbBsaz1k-W%h~69*YERl(b*%~%dqcFeSA>ODfCUa~&my&Y3x-Xiqz+PA_(z9p?Xa$NEr`|JkUU1=%r@ht2nDBJPpI zVMz6a0x@j_=`-^}C?dx7sL8TwkzjvV)m5%};bE;eea@H#=iBC;??8o1q*?e)z$8zb zt{*|`w*~k!1<}8Iav*Wc8=S@7Cii>cSx;ncnUO#bHM76MC41=J)O zX|cMDOyvCq805qqx-fRK zz@OtA%mO$R#N*4QBT88aeRlxcfc6k zfGX}s5}DYw3JvklZnFqNw;n_%s{$FOOq;E5nAh_yXc^^|Ene2FPQDxi;l7mJA-(3m zp07xEUJwT0vyGq1@G1J?-qy^_%>^1ab*v9|CTvgPS$L0wCa3dHL^C7~*wZa8$8-~q z%y;BfGVSU5Ni^2fu6#@*9{#jyu7afOd2C5O<0E;DptJjt;XwxT&S6JdqhAMs!9YQ{ zctyyo^>MGdIk=3jMaOtlRZXsTnMk)6Rj?`F*5ky*SQVYSkM$_)yLIVZ5Pm|yl2t+n zXc~IFk|9j#8(X?!kGGa8`dyRR#BsGf;huzBh=5ZW??bfX0I=Ewo%#l?##aV_Z7(xH?Gl_osQ9s1!0odteI_iOA( zO(nX1u{j)Lx(E?o)!?cAsT&YnyinEGCZ4J~Zm#gjn7v=6Tqf07=DE}+(HkM`g=>mQ zM9CdI_Zvx|Lgi_NeU@Rk(%#d}p;UiWyFp8V4=rs^;q}}dG_DkGIZ#+GZGX3cezKji z#qk{>+;P+g%RbhjWTcfZH0c+l4FB1hrW^1ubMH-;*oJ4$XNjbv9cEwh-aYvV`-igO zuRQfWV3W=oW2qfvGlgiG)J7N2?nghH;|Z3&qQVsn?6mnnCx zoMxs5_m^PG?7H?V9?kvgF(lv|0e~Vint*yTdPaLXE=U<6hW5A{ZNefoy#*@Y&pKq- ziCD@EofOAkeBLY(a4BE_06FnzPO!@!==aZmT3n z#w#_8oT)Qg`*jFp_Tn%=7o>IuRrHf;!oy4H;4gAu50Y2hGTdEUOBr+hN z1fz0%XOY+;wUoeW)^U7Xl<#(nnbGO z`N9XY$5hO<22x+n+{Ki?nd!lLf5F_K5tIG|-BFJs)d?hfLL_ca1A^VdR$bo~Y$vp` zK53gN5!zZ@o+Zy8Z#oy!GGp6+kw1x;$Pxky-lRiI8U1}ML0WZ1HM(X=BBJKRlsjFN zJg?Gt(?!A@?q2FP^+EBtOHbOHH1oS>Huep;<~#I(3mr?)`@Q+>4AZ|xEKa9;A8t_~ zI)AwgFq@gt+kp5)PmOx=O*fm6_L8Iy^Jcir#)>7;O?S5#+O(xbyHtA9;R)>wx_)d> z0eJPS)5nu-o~dtg;a(3wFbzOA2^G^J&O|bz$`&x!rm#l<^{r2V zp(J7NAK&jI#r5Ui#t+QK(0bQfTNk<#c0K1goeZi^-1BqI!yKl7qj5BI-y5ABXBu<* zZ5tRt<<8DC&g>_fkXx5Fj85G;@?LmIXyUQ$6Pec>JK0Q^LI<=aOQc57*|^yIzIUN5 zA)jJ!qOsY5uqrwC_)F=jj88Z!icaQb&I%u&-uMr za#yo(pEV!d&<$J!3z~OYJqfG6owsBoF zkJi3jrY^jFs$}WhoQeCvVw_-Ja zhL75@;sffv-Ascfb1aCF#AlE4PbHi!X9Up%|h0tx4V_E~o&OqGUHKCo#wQroi|;-#O-hY+W?yr2GZmo}l8yP#&& z0b%lyjok&YakZV*MruHBPH$$OZzsmK2hO|Q#*Al*}U{=1vkaSjpyCzC44;Ys8+5E*ao2Wm0L+WthL^;-_xv#y{Glk zQ{lzg$g0o$Cq-8tJyu>s&9ng=8ft$GRt;lMZ;m7=zxIaFs%x~u&ep_MLr3_(I6H*o zbUV%F>H1C%?a4)Gn)9R`b-OC3THwvtUV_B&?w>$QzspLQWdJ04@gPeM@{jY`52tHC zcUBJAI2Pu;e3G46Kk3ce`c;oxNKF-t*n*8q-zKJe!*A^cZ#n%0t(s z^c9~k3#Pl1(-~aG<65gV$*+QDE$_4$-fVC+&Ix((E0pvQJU_#xV6RD&*e$0as3J?G zSXWV+Ow!^wl(Y4`Hgce(;ZnldVBqlb%$$+vXg^QWjLe^)DZc?W1Jxh>8*2a|@Werd zTg2|=2_+%}r5*tYH@&E9Ya@JepG@k3eW^@yCd6xVB@TW&bAC%jxcea`Y=x}XBVN#? zPK5*qu8W@iP68LDekR)rkKa@=-{D9%IM$d&?GFfcFJ_vjlS`_&I;lw4gv)jGdLQu; z6YtI8M4g&qKu_4>v>Mhnr6sILCu@KU)mP9Y-d?zd)$O23bW!1bSbl~}h-yp%^s?{k z8ApQ7d4H9?(a&Fo_Xnry<2tjxC8%b&%!&MfL;?sX@d>dJAU455=;}bp2^3IWGo2>4 z07dZ@5<-ZztcSrDYFnp@j)>j-aH!V7kp0ffjL(V33h<8ryELvE%p;mabjL|_!aFO< zer`p@2*?HfP`YhP)Tg!TseeO<6wy(^U!dp@BlXQZ;N69839{|k#}R!FEUf7+H4z;k z^pPz}5}h_2lYsgbbE9dLs;V`7Q@qw%`$Kbfz=QaYDN%^5LvJK!H~$22>Z_npOZaXX zE=oa^{M(3Y)5n9w_hRK+n(}#Ec@sjO3Li=tk?#Af;PHUxXw48%nVYXn>))`T%ikQu zc~xCOyOMfveEPC#d1WpNcyH~MsKC{YAn8-fS8k2>D?CX%zAY*TXrujH*^qgK%z^$ zkQm**hcq+YgB77GB{z^_hH2+(K()NRNrWpv?)hxjMVa@rGj)APIe9qd zLQM(*vhU;bh&ug*X-WZnMTyZJG8l`=m!kxAN^YLvRESbbhnkAiwiSMFD%EwP=bG!~ zOqb7m{EoDh9!ZS(z8>0i(Hc7kH|JZs0V!Vc(`~YXe@ON*c zblz3V^7nkxyxO0ylbw#~;@``};eVL%A)A(#*G4ATwRO4S~VYaU0R0e#_q znE>L@xsiNL&wCPJSaBc3Fn@LctLuIZOV{+DEtqgSm1&Y~eI*%m7vv}B3Cb^(yiob~ zJHp72H-Mi-Gl>BK{4DytIQ-&)twkiZoArop@lmq@Vjw@i zZ2i*YhLtNBQWr%po$XfU3kSRLKOoZn^=&50%TL*YKxaXVpwq~|km`T52Y4*EE6^~Q zR5ME;2*NUdA@J&gTWs5v_-K>4WdrHliKVi=7si4qLqb;)*|Xlw8GPqif0DBd0OS8` zGOkMkX!=MWAoUQD2fTHf7sqRjD|bXhZ=48!Nz(y6di;n|^cN1^4q;)nQOsj&FlM?b z^Y|kelj%cZTm(!vPW~^5?O(UD?pbP)kFYj(;e{h-FMex5F${NbzZig9N5E^qt-}(q zTmO3(gVuyk6?z65+odcIfW+n8l_r+r(*V5vUtY#%t(BmBBFn(Amg7EGHP|}me{$9O zDLJ7C0P6kQ%i;g=Fi?nqpU%M(Fd2B7b!YkNiID$QQ=s2DzGQ+Z$|^M2i# z_^)olBWhjWdZNPY!B-Hkpho(dfA0g9)_-K410nYJF|Ky+T@V_p+Ig*z9CkImZ1wc^ z+Vl@TbDUpk^jkSW@Q3-EMi8Z7kvB{&yB=8 zkB&+GPr7mKkTnlqr>NPx(-{69fyeo8CCmPeZt<_fqb&7USrC82rgP%r&cI&jzd`eV zi*o?L|BrF_zd-(fhVXy>V*bZp@c*P+{+%=Mzi*f$+Y>ub_}RzSZMSfQ?66E>6{*QR1%ucRaQFv7d_#B|0s{MeTg47UetMd%ctfG=xI7P|Es46 z8;ic+v36GGWP5z!_JF)zzq`%9?(6>=k?*=>+m``NvnmVM)^pUibYf}5Zf%O*Zw3h) z{K~C3RxfO>RQms9IBuduZO%bsD@UKdloKv3F)bAXSWEwD&iXH(U>*C)QOed>V3G3{ zCq<&f>P8~{Uw)UefBOdQ9bEx61wQZAprpKI!c4+@*{Y&jR%Hv$Cc%i=h-b^$qi>-e z*TC{A{EveEZ722DZt9;u+@I6`-Qqr5Y4snyoLDFfgsbcHU*6*)xmy;xAXnACrO|V*b3i$hM--60G=J4V$uK!X`fW>X{yxO*1 zYw{P{QnbqLkgpDtUqoAO9ydA{?w`h`O~$d~km^x@mTNf17&vPt8Ci@omF25T#cM^+ zj_{d-3s$J%-qRmE1lZ;Ttlz#n^b3#2YB6xm2e|}G+DdOuxiS6R_9At+rTjaUuT0DL zeB!Wf`WutC8L_i%@?%7)1}nxj7C)NH;uG{RN@17OkQGi1M5j8GS67Ia?p}NvH0Sgs zoBL8v1fue z&CKK@TwC_fGtPh5TB^=o)RTbI_L#?AwQ22NT~E@co=}FZTtmNO;#^R7vTr9k&iz_& zxPLcpLY$lPporsV0ibFJ?n1@sv*l87F+aciGPO}b+E1r{=Ldc-%po1_mM%~Sv0wa- z#M4Ho2wHs~jEjJv_je=9Tp7sDEQ#H{s9Q;XY61nK0cKMJKgwG#{ZY(Y=lRwN;E?eQ z($W{zdvH${PJCj*OFtuX=33_>?8d55im6MDjkoRFPMFZ(oS zj=H`wy`Neu$0M$j%HjXzbLey^;u)mAxew4-?nTrgB3T@a^!^;n=;kU0nt_Ew8aCRa z*LDaRk=Egg_Ccp3_G%GlStG4mcmP*40p#p-7=#5N3wq?_zRLu`Q7%N9>RUV)yCHus zKrY$x4ORY|2~-MnF#n2}OXMQ~$xnh6xh7t!`fWZ;f~8{{)0Zzomsu#FWETZrY$A^S zG|S5uX{a|*O*wBEvg|C*NtvTy-#>2&WZ`0ZF@KbEnL_)q^mW&4H`XQ?tY z7Yo8y=+nt3-&&knX|8W>u6wdsgF^Yu8KaQML$?U^LthVDZ<-(BIabgGnUMe}fk(CT z0=hCExweyWA`E}k(uqK@$Y&W{>*N`lMmYHfCiOjElml1NERyg1m(cPShHh_ftCMh)?B`y&=K}+&8OtrsjI9`;xFbwtcZF_8 ztX^-uBZW%DN}z*nXj2v1a~2+9w~@iTNH!nTvG|GI?e>(z zjH!k%4K9A_e6DD}?W-BkD>>9oME&aet+ssgO%Bck_jBjIZgq7mM7#rRce+v1MwI2r zTT@V>*9_s|Aef*xR<-t$$8u(#0_u#bP^;O(e5Q`>Qfh58f4B)&u#HheOYbg_#zL95 zC$*kIechnGi>gYU_h$wLlL3nLloXWqrnx0GQb@1vs-5?IQ&0R*Kon;U07b-Lb?6cs zbo&01eLUgv%XOkK#)@pAe0~(FeqU`v3nH*;Z@9cMX0YHpl$fMBclAU0a7L0L_!-A0 zE*jTZ+KrD}I5Q5FM;4YK*$zazY_!;OT-Dchn3 z$5rc${beoKkr|BQC1T9N=`nqvPMKjr8P>I?iQyBWn&L6EBwv+{A^SS>-CK0kr*ZeQ zTK%66$)&vaOU#~4^aJhlIv+H5fW0nlmU{c&rXcbB-yikwa@H*A`kpYyXq2uQ8b^`y zch1V0Dpx)*t8FmrVQ0p#>Yu?*$+9uvltI#=Jl0Rl>;T-k@u*bm9a6 zJF9f7@#F}9nZ)Tauhz+-2XMy)A71|x3Zo4=BjI<`VCn&aN2gJXxHzYz{^SlGbU(#3 z_VzSXad9MpBnX9gF6lmv=GKla87qqTqvLI+T;>l8g>PoipKLCL>S+&pfRcQZgDR*5 z1#)D)bvKR-lUhK^N=#69ssg(1fA?c4jF+?~4)PA)Ifg%B#tO<%2)z9%-=J)fI4eTl zN`N|6qjl|QD~V9a5WvfKgi>W=CHj51q#IcbZ<@;fJg}j2`vW`iY!W@MgpfrZ!4uR` z`&O)Rn7G#9+Zv228PCUXRkiv3e#$|SFjl3$S#7OgV`Hwm=waXai|5FFbT#swhL7v9 zgJ`Tg_S1sSs5~7gq&Uq$+R>}q+|_pDzm5I=Xti+weR?P3URB_dXsB4knO{+6cVB=* z8KL_g7;Q!rAUD!g>!q(oW3p6gTPHBe{xx1T?nsI<@s!2i(!%W3zDgBFA=Nz~ zyk<{-n5IeWBhK>nvD7DVVL+le{Q4{d-kl=r##)&4om#PL?`Q7Db4E{s?|8mD9499O zPR98XBeCps&bAVtOP=vT{L)>IA|KhuL2s0Jjm>|TQr*ebF$#WIc~r~QEu_Qw0r%ix zx1*GH{1T!c5<>!EC4FGx`f>|ej}*iEYkds|{X z!YCurFkxUWu(gV2Y1T4Ad>8ZFUH_6g`0AlfQo^+yu@p+zEc232UuN-E>nDd3a{Fe z8e{e<9;RWNZ!Ri+!R7OXl`0|sB%fBoaj*)g^P(8?>^`#+4(86QWOTqD&E`D(L?si|D zi%;-%%X0^5j!Vf7FCP=ekEsv5dou3ix=N}A+|N?!5|n%T@{RQVIH@H&`n8%0I5+D( zj*@qKRLJI3cI0)Q1@10R6?w@ue*>AlD8MuZ#e?qZ@4MmE!On;|`Et>*VLi;=6a~I8 z!JM}`sSrQ+hhw%pyW{0EHs|g7xQl5-YBp`#m7cK@u1(@Yk8}pNK70~F34Kqv@v12s zCO0627eDr>d^GM)E}#0{A;;+R4)1E*v@zV zG`HwZox_r<3N_Eub3niM$feX6+6cunK?}ljxe#62oyO>x2_4~eWh9uUU#q1b5+D6F zrX5+F8}bA9NZdFn2lkAed*qYr-w#bIS;;IpfbC{iyMMxq#2*Bgxp6(WC-c$9S%<4> zgT95Iy|N5923}hjR(w;qS1s}F@S`%09i4wuj7Tv+wVh75V$b`V-U0_Iy2>3W`i z@=4(r?**mt9h?N|eK7;sE0vE|tbS6pP;&5Q#zj+HRXvkspMA{Du;{c>{2nQuC`yo~ zdA@7S>amh_(W_1^;htnZ%L$Du$v2KaDi_BVqL^cU)0iVI25f&8R^3Uz1Q(Rxd@M$05--^4V|JWa#*>)^LGkc3?NHs68tJ`zx#oQZh? zRia4CAgv}E@G(RQg0%mVh$ zIat&Qxd58LNCLULF5?RC4)t-kCBahq8&Gr=Csr(C)N%x(n%zx45-leRc&Nhx8?XWj zRkM@#6}q$wP~Hn%4MKszqTcEyz15EJs1T3Zl(x9@@|B7BIxE!(-`Qd8L)OCYsH~nX zSq4@A=zM22F$T-!a|0Q$npV~0KRZ(Gy{FNskSgvne3&qPNJ-y86@Xn{Vs+8uT@Z;5 z4eZBO&&~sn`&etXE`6fq2wcIw3r2g6 zRt99A!-JU83}5oR;h5D?*YyPfpb9qjs}+?ys0!xzqL6TEaTRFbNg;XyZD&mj#ZeJM@qNc zb^_=9Yt$DIG{)kfq+u&s_V~n(swtV&W9ddRk5ekJAH_iTa?F!nI%cP>4_#3fZc>0A z_PF)PPK5OZ!FPvdAC7?+eqT5I3~pO5jY#_N*K9n~F`Akmwy{^cJepC5tb5(?0r3>{^NO z_iIpqPZxQ20*11bHYU=S{{ln#*AP5WC3(TGhLNSt3&W*8b%dF)s^K0Rh2z3ro*8b} zH&Xlb*PesIZiMYSF;$uwwy&7*ao?ZAZrzBf{^*UJ3jT|;PM7+#wbbwI+8q6APC+XO zBn|MUrd-x}c~DrG+nL4EL`CC-Pl)Tham0BLV-Wi`I6X(gci+e&!s$fauf7U=0f>B- z+b3j4i*9vSl+~)M4;y zwF;VX3$6~yuKnn5AWK{X&#b@0UZQtYElQL48N|++%$OI06qn0P`y!b$3$s__da!}X zKbqe4`@6j36l&pG1}484SmRbVBo3=G3OImy=PQl&C!Ba&(DggNxzMt7wL>m`N>eN8 zHnadIh}XW7AgzTv7q0wu-RdxU&>0BDN0^(8DxAnX#*i^c&a>*1s_)H8nQ@)f{NiB5 z#9B6G)t!2^!iV5cx%`cwN}+m^J4yjxrL0bvSR*(-SYNNVsfsKq+x2bqUUY``P?nQz zBSGVRscJ-Dt?wMxj(g?!9w-b2Y(ZvY76EjQVE$_LVQX+4bq6eh^z3exNK|VGIYFB$ zEB}QThR?eCsq{Iz-$}|*H1)XPC!nX(i)g6n0`mY$0L0FOqzC*)eXeJSXnvpP)ZrUVyq5+Wi{iCji`~TaBrx2KgHG z@0||D@i$n{JD(cW=Ht0*E3mYDOhb>W7!(=<9L8tt$y}Yv!}2Edk`}hMPRuf_0>@ zPsmBoHK)YPrpuW9OiOyv{XQ4_fY!~sY(|3qlI=Rjg%?ab}t6$v}&Ulmj zTfM;nZWY#|__VbWe{aD4wlFx`1ay?tWZK!HFX@F7(HgH@GwONNkPjJ$!aPeXlwy^p ze7{VELf+(6re9uedD^Dp^FoHK^vK*>V@b)fwZsqhIH@(3n)_Bc z%)8v%S2#HuoGrC65I)!QF-`oapMX9$Lly9Bz#Y+-?ms*gSBf!a#1vv~(ETD7tNfHR z>hV3T857Fqi>oa{0#s7rCb!?BHY zgyDx1wR}0-9rp4&_};2_VWj!0Gw?ewm9-PUkyb?FY_7~G9&QrZ35C9~w=W~I094lD^jm2vS4nv7Ih zb5Gr@_jD^Nh9Fkft(JQ-snqKYP>pSY=5VbVnfV#=>iY05re84ngkc;%2%C)g(=tghK=&6PJHr)CM3NF8_4mqj za1!XA5g3tb?V;T%!fZ0vrmesDSxB)onws%q!0#VmsnjhBdq6s$jWM~PTUW! zw||1(Gy$T6rP4X;r$DdbPl0Nl>Yu`X#_{~w}xaSJK3wuwbtBoJ@a{*aJq+~Zl2?pkPwP~KNlH7+nDVx z1lh+Cmk4>~ennU^J&edh(8RWMXNIbh;=Yvu9rT3JP5G(g_9gx#Xar0VB5r3f zegA#&Fl*TT&X2N`Bdz+a;MZo5uqqW)M~$V}sDxGB$T#lu)!gR8(;+(AE6hFT#i9f? z+A5rT%)Z;UW!6l!OK>9+u8wS1?EzwwkjTAHqXZdDw4P@C)YZwoyMEI!@#ILhq&}2r ze~jc=1D1p?E5wx^Z@FlQ^$-KzTsKq?+Y-@afvvI5LTHNzF1*5w_G?|rO4O)Nr0yOl z`O12|aZY*aV{L{ikfM)z1ewukQ>CA{REE@+3n%iJ&TULqWG|XqK8a>Lh>B%S5VD&4 zm^9!462B(0#tAxk_&dzuzrrj%{GaWOeAiiK-v)9}mJgrp>_b_nKQ}8)UUD~2zujj( zF0F*vg*6Y~Nt7q_)VniP>>3DxB|m_^LT}=IZoN;qI>rm2qb7=%&$5a|6iAklxsfls zaS9!!OcQ%s0Fi=$!xJ13HvOR(lmYumc=*1c^6`n+?IwQVdtW4Q9f{Cb~1F zUdB(FT1xFXZfZSw^+GUEQXlANbejGXqjH4KbuFZrpzdpp2G~2@iy9BQwqIyQ+FT+z zCzkV^9uDl`0AA*>%`p*Q4PXVlAr)mn-sKelG=Ve&cDhwSHZusa))ZKGy?Z{wRjWD^ z;LI|Qr{xgz)qS@j7ga#t))`Bz^jw7BH6_yFjj?^`zWI*;D!AQSBxLa`Q5CE`wzHjb zCk@?yKG$D`WZ8pt1oanJw8p!ldph>0>>Fb0(Gql@kIrQmUxr=ZyImeQ=~F{zenp#E zRLfIR!OBbMn{*N%)Y|qeHjn7xZGsDQ(<)tg_-^TZ>nYLCW!ptRKu2^-s3o=*LagR5rO9Ft_{sZA z32OoX9W<*g0Z1kGFv5!KNnwgb#UgE>i_ID8!*K0S&7M9}Z;eEL`R?yEq0Ic#F2u_( z&<+*uJDGrf1hbfre(fXdRPaZ{O64VVnan)p($f{%Kn(zf{88EZGk|Q7i9O$apD#FiRgVASD3PGp*BmzhfSXla${cfP*4jE5{&lM zY~y3aLPPgs869XYc_+SnoM(RRv3J7j81=dUL8g8_sXNaiW}q){T`<5>6pB&9V@0T? z5+wju0KhArxtaj<2KhjEw8hNx2k5Lml@bOOm`SDV@Ond)0~Z?5q)_tYh}@1L;UOy5 zY~E~Iow-oRV?>)<=zKv$fd0iD66b)3nJGUmf)Wn$EE~%nt}KylpTQX{5F^I-rJZIU zKS~l7Xx_l_LPK?p1-26bOtI8!Krlt^HUKX1tJ))82Y@;Q*2Iu>bK;5J5+V31&&#P+ zy?~@emU67{A&`|}fq>siE`3_%wXbvGsaU>~nhtAYyOlPFB*lapPg;iV6NKpUR6Aox z<-!6|5i1u$5S1ZZ=dPF56&Sni6ZYbhPzjvn@i?;c4o_Y}dLt-N5qhF zD`hmFGtQ1ay_pI`Yi`#z)zqFREqlpRUZEKbqR)EZJet>ncffAl!`c&+#+$_6EFcU8 zwC<{<>ec#6T1V~PFgFM}UFfCH4*GI&iXfQMb3(6JdvY|^^8M8BHm^TSWFtsphk|wi z;Y`nV?{mp$hw1!~E%mCg9rReKV7)~`am|Oo3*-eJA2@I0I&2!|cqML)0f`yxx>bQ= zdQ|~p52^x%V;0W~>W4FHWC?T^kQVxb$Us)_P=8hBR4l4ZA_&Up-dM(rplxmD#;%ok zb2>^?m0X?m6q$Y0t+#R*fgN>LUcroW&=6XW!LKNDpYx zh?QL`d#DrX5GG7vsbKY7N-HKO#EAT~le+cqUHfOt)2EUEG?Ag?e*BiRo0iIWA2gKN zV#X{ty1KjU%?wnBBIj2BbB(X<+i`+QtmKLCD5ZAA+#3r z!mHiklyP=!$uj+Lp2#b+#n;*5EYD9XTyKlhQn(Yn^cPL=8NLlH;oRvG_i7@(41N)* zt*fn5Pvm_4@@A8ZAZaO3Ap>gu<#8^J=KOsAP3G(xEHmM}xw$WME>KjzZ@S4W z|0bODjYb4%VZkYYr==MB7nf`Wx*P=zF~;hmC1wO;E0GuI^MVlb#vM_e>WcbwlaR+= z52JaCF3(?+7yG!Lvh=Gn^PBa$@`(@2m{b*T=`q{8lD*v!tzLNtVr!|@UlMzh_F5?^ z?Gb%zR3OQw+aGY6UniSCO@731toia`NE6f*5YcL;!tN$vd^*l%npTdMJQx?cV%sm~ z6jz+{F*9wq4^YN)aFGbj0M%AaJ>|y^#`4xih$ODx55B~2@=bePzv3g}wWQ0J^CT(y zU7_TdoIhK@Kbri8$dTvqQ0$Oi)2JUWLQ@Ufm6$cRyR#pyxY(@}(#HAn;SJ`~G-Mu5 z@;uIl$TL_6G<%2c^+Q9v`!W!;w>mW7hKo!4iqCeNPAS!Vz-mPGHKymRD6hyg{%NND zQ{_)W+u%X7&}bWcLLLI#QIm10&eqHQgLIL}HxaLE3~Q^_%t=mKHVcV7%<5_dNCvz_ z5uz6o){yT{knzG4qzmiX`<@%sy`jw~3z;<&6yFC?z~)}K2{gd}!XSq0ustEAglo2# zzW3+4VXk_C4(7VIb)GC9EG{m;O+24}@sZZ2i@6gfl>Co)PIUul4tQwh8Mo;w6hO5* zLbz*9p7GRZb|8u!rzxWQIUzgvsdHS=zp&P^$mj*P(0v=C?85GuViQAs&?c#sODmn=*1L5t1=0Zt<>SNp_H-;zwKs^TqaEsOYwJeD+>Q}$Gq39n z5`+>z1hSjni{pQMw(V?X3NYROwzU1;;JlRS`F2MdnXsG<*>^K0Gito=tE-zFST3tE zKhs)?2Hm@%&uVxTL`M>_+;joxX~qDVxgi#WU>hGVmRMOpX*|W`8q}v6lF-o997eQEW?ul;c+sVdl(hDUo zuA!}%_mIyA8eJK3rd;3RT{~tM)=~=qO^cT&lhIC&`!l;GD=FrpAsS(Qj=Q;Uo_B8t z4~NWl+LA{AAo|~Zntx#B^eUbm8GJbP6uZT9qubR!TBZDrS`sBI_2G_UIi?R^2o?4U zMW`EVkh#1gKYdkZ2-w&P?Lb8+A{F&I%V?i0UaYKn-bc>xnQ=4d@ zChK2ST*Y=-u62p&Ga$a8tcKlc_s&Z|?)E6sH+|ub;&cV4$(5@XJ)a$TyCt1 zS|=^RyDkH_k5n66WuXM&WeDBp6w8K4z9Q@VCkGyhQ=ebIG+I0V=H4sNHpr=!QZ=su z{1>*~iv_nsgEMIb8bZdgTzfX$h z#;E7}H_1>%EE=U(*X^gOkKYEnC{<*zLDSKff0eKJ!!0~MF!+Hc^TDA|w zp17CD&JtQp0vAm)CJiOg=xcoB7J!)!3axPyxMU9D&Z#BH3PGWcu z1h^DVqG|tLAG{R}1j3qw=>^4P=_xMr3Z7+6NR%=0B&n%`V1~*EIO$3g_s0*}~;X zO|sJ7#-INLqP+KjyH2L>NhU=zBf_EU5ONx+w2Wfd@Dpj0;{2AXa&eOWx|%GqeTs&w z_g3=v!R;2DO#|a!*r>AIPr5(UG3}G3Bj=jZil&~=wDsPG%$k|2Whj3CN8v{Yn90<1Jd1w_hRCm;2c zW(`3|D2%xPeol$qML9m)BDJP%MPTPX+_1ymvw-trfXi{ ztA|U6AyuPeP{FZ$k1;1s$7OY3gn$@%0I5} zR_NC7Eo@0|30V}tWo}1f=MG+t5vZJ_J+Dq8MbY2JJubbO)pWq;*Bd@C77Ahdbh>!c z$r-ALWNkVDgc6P3$sU*DvDqk`;a1Z;uZ6u3gqYG|j#YWPyqM z^(*cs1B3>r@i7)6_W+uJrUt{j+ye(Kt|14nxZ)?gkJ7ZmYn4O`pf9X5d=7lx)sD6- zr)Prq`)++_^X`dw5bOMLhBZ2+RL?cwD!AP86fQr+PXGYt;Q;YcNR_mO6^ZL(_f>7i zR3;(H8L6De56V(OI~M9l*fAHrrNanPQQMJfJieWBAV$w(8u{wk9=~VjLt0xO9+2et z)aqamZt0*5R~Bq@@_L^a-noTh3^S9B@YTCnft8jm+*EB7F6qZ<3C~^+=ca3odK~-e zDkSSj^h;(tl$+o*+p+@$)M*&Q%V3PbZiroil7q8{`LXa~pT5X;8d@tAxRolYQfTr|MbVvV)0qKwY zv9CQquAT#UW~xV30YH_U!40Ms-~;U(#dda9n2Y6H&DIBFCRbO?9g?C*O&`V$lE}9X zcrI~5??$4jVjhj?L|;>uDXM-QsrsOfE&kQPO8Oiw)|)UkC4lV&muqe(h=dp|z!SP4 zbmrQZtx*SQvEaGDmGqs|Or@#yg++hJ9c3RJRU4GHNz`Wr9;Vn;8vJ?#?Kk4%acq58 zkX#)^I=I_;Q6R9t6GT%A1~9$GZ4y9Sb4uBCxrN=tV#AMvZgzf(QipAfl_^KUlXX_@ z5>2^jkXB)i=xKy}=*le=RoOZ0xlEkB37eNP^r6JF(bZBmPGw#4yYJ&`pI^U1vL+?e z(`Q2#h<5nOjbRKxT4NYl{6+zksGp3(BKt^_`wE-{kAl|VSkpV~n%ROhMoVWG7iV#f zt};~>_p^n@bd~4O?$a!1jX)<-c=O|1gj4vj;(5F$IzO^RCf#6k+Oj(HrAqOr85_+( zn8DilD6Attr`4i=T*8Mz$KYdAzd=7?+$K_LxXC?l0UzS<_UVHF@;9`Rb@K7l;n!l29fGKLPyvmCV_e10YKIY!Ce{spC~vInK8@+@W}O({<6bFPq5;TODG+ zt4ej+OH44t?vY-c$ERI{L%Slh2d0EBYlqGpc6_mekP%t%nYSl_P=oaN?a4`TB*f{9 zSaZZPugc9BQB@=E1DUAciRBeGztGm*_z{f z`h}x6Hl?ohrVv7LYXC1mH-sF>7ad~7D^zh1sVxZVlQNm7KYNZ{#_3`<&fo+wa^27{D0?#v(t4!ng0n=Zvg9MT8!yn;v2=iZwO1HteU^>=-5_*`*sjHkp|{`R(u%HFVTNy!JXqBVEaP7Bl5lCA19jzNL}bhIiL!FD(wC(^;|y##<*>wT0G zm_M>iPD%QkU06;QOyLCa@5Hez2SstcM>B>KLAc$7qOC=y$(?Fmx$6LJ*UbCf%n9>V?^7PA?RZ`geVwble5wZ;yP;Vr)T@9GmzJ{s6JKeDJ(b>>VXa0m252@)kWQyJ?{(wB{6jlAuRZQG|Pu z9kNrIl%ww0>?n}C|6DZd5rL*hPUJu7y#>D5-HyFD#l5DPbQun*|-{%SNXEei=?L0hILMq~l0Nv`c7`Gh> zi-3~RO`016tf>|&AIuw{MVIW{@(+CDB`B<=LM^iis4E694+S^Vj{`WXA0VS3b?iYb zb;g$?-!8%HZN{ep(r0D@-w0G*IbBG@Z@iWi49ufHK$Yw}FGV5}7xLkpgj-y1>*m({ zHpvd?cGp+KuES0kPPsy_AmRA5MO8eLNMN(*1|S_Y3P^2cv{k)Ay^~Q&6$3oJBWAX7 z$1$(hWx2q~pJ&VW_Je`6Nw(K;el~9qOK}z}xf~=~DXO;O@`HKdHyTnzE@rS;aHXg+?7jR&Q3nvcI5iew*Bsw5p<4PS3H_q^Fnwu4I#V@w=N zl9Y>?1uw*19rW`$DWK|Hq5~2zKKkIKH$0p9amKBHJ7a=3+G@v`@K+C4&AnFH=L&8j zJ{oY^lB$^ZTGT)Fxqy}j=>mSwZjz3=O7wD)MVmUue>afcu^gl>M%5oCNS4*Ic1!C7pp1T=!tr$8sL1;#AWIKvk`SIiI%`aDz^z285oDL4Y$d0Fc zYU7E7ar2S&-_f(STz~9i`_|NaQ_&4)VP(0!h4tO`EcbKs7n>SV$;YT_nST``(XNw*_rZoHu> zdpMK~qo30ddz`M-7NcPLwfjn!Aot+VvC4r@g`fb6>dVR{g$8M`hF#%L3`iLb#Q4EZx3!O zlCoa2IcpfU+ANCn26%X`i^&krBjT5CB$#*^w9og*OiYaUQ@-ee!+0tcHK@hWvUwU9 zsVl&QRfL@aa(a-Q%c$5SKE4|`AYNff5i_Qryn3u&T|HT5*T9?F`CupRW%DiK%MBs3 zkARKyJS?P;>cZNyjUtE8wo^9jd6#~GIPXxqD9prk`>XgsPu>DFNqcm7kq+R-p&HI* z%1DpM@8{CUh4CCZEpVVF&mSurus#_yoM?af;GTbLKsh$`ARI4=8{9Igz~99@k@>za zTB3q56>4Dxxc>05FTRL?Dy|Sa}%3*Q66VnwjybE2#qli-I*Y z+0p1PJIjKrCadplqfZgCYI%$s2plIF(vf@qU!OpDE*W=P3gY8F;e&cy?k7d>ep8rL z3a%037AfTw37guR0a7(j+#_{G?lq2-uGccI=AJ~7 zXYltIf~`-><$Y3lHS(IEfz=B~KEyykpB1a*fDHU+23_A8&j%$|aK-l?ywRMibc>`- zFYI~&GNJFwd=7cIM}aWc!rK9?A(P4ZJupDkD#B8JBN9F(=Y z5c9oQVkR4X2()BiW>wD)7(GN{m$(QXz9d~ny2Qcs=}FwD>WRlG8n(8mSF5i+4O0zs z+5R-;Ela6bG%;a?!|~gOyT(ZTq^Q!QQHyqTAW%z1&UyXK1;LV$w39aEok6Hg6gSq5ugf^@>^6ANoW;%it zZZHXV_ZmKQIo-I^+auHSjj0`zI?M}>NmrlMDN)ilmb-gDywvQemMmo8OTm5cgOe=P z(*!x}`i>e_5K|iYx&wv*WPjH%Qw9@cy<_*UH;Cb=)fCkAt?vfk`EWE$H3nuu*)#fQ zQdECXmcd==X7iSPtJ1J=@}ftj|M{HKQ`2=eoX!CvIe=8V<}Cj**5NLOafb~xndNc0Q8+Gxs!6}PZM=Ej>*Tn~;j*C`fgXCsk=1#Rj zqM>9+IoJx|vj*$QJ&O&L0iQN8MZ^qF_8we5Dk-vfWmO+GL=)o0WW~*Sith4NlB2Ta zy|6_Je86%aG|Z1~>S;Bc-tzh(lfBa|`r0HWf$ROw@45}2MI7H`J?qaOk&Rx8SYiOg zw>BjrQ_eLyNCf3orJT5jN1B_{n!8|3UkwVL54%%gLK2Yi^83!Q5J7m@PmZ97??7k9 z^0AM>-D>ay82Z~{Y_n^oZpTU;u%{vsoNq3N$J6AdoO?hj{YHZoJ5qe<}xppQOF?_8)4F1 z`}nlWq?&=L<+#?dhhyAB*J_gre_E1yR~%os-O3U*aa@%fZ;Jzn+Bz~%r}ivTPr-`6 zMMG|Ioy*TLH+kP^VIr5H+_k?Ia9%R;0mg87RoekoG1LJeB?z6oZFvH$j|!t_N2H%r z0qnx}g>&e3-6hzO82l+P6JvhCF)miAfvBFu|E)5^~J_je90AAORL* z;;*n}u>>TX+3(FPp)(`rTKyDo-RZdwPN~lBZf%)g4HM=99xfRqE-D+1(BA8NTX_3gc87Zm&4q`R3m$AUV*QAy-qu^IK*WMozX+Bv2vajYN?0V~3x~^R` zIj~hoWs-UG>8HTbEkQHqCreIEu<8P4*_jPv6{HGOJX6Dl-#2iz9c)A?tXz*Mc*gIzg9)E+62EmDpGf4_ znX&PR)X_4cwlw+zn>T%4t`MX1F#acJAk}Byl7*6Q#d4EZG@W72TzzySml2<$TOYeW z76SA`0vV{wK-kP3YrrR1@3{a#-24EX3;49ISl9daO;&~>yAJoikIc?DIlx?S{yLYW z6k0_%I7lr`jiVde`lEZm+!0zRQeyJ?td;oMg>* zxWL1p+DkbR$HyJR4(nIP=;RU|I4gs!s&k^+kkze1_s>^;uMvBn+syk?)1lL(Ahq5Q-AL9 zz~QoA-x4WBe!wNYU@L?l*X=1)Hsi)d*ZkfuIiGgz`fe*vPv8`ulTuRnu+I=Q0S1*x zD4s&(2T1tN0g4IWLHU+MB+&+_T<(#qUH*9wNh!9}qYG@Vb)Jb0H|T*xSl6du*2FZl zQZzIq2Sjt!xr`ovxq+~vUcDEk_bjubwiOyM+ethNG>b{qfC1)Qtz5$W`NhHKlH^_7 z3py8~2HAgVhFayfdN<66t&EfNqBjc&jQ}}XGl+2*@S0+S7P$ePUy0xpiBRGI z8pU?sV!?q83~NMH4IsmLcGjA9qtmO3TzF$=s%J=)&QU3BoU5jUU7RH{s4bJRa& zMZ9WT&!*?WjY^xm4y{NW)aEk+0yoUsWpA2)>EhT*d@K_BZFogye$lq2e1ZRvn|-bX#sc;lw{7k zMD@pVDZ9g27OxE$w&QQR$a5$h32yr-0@%W4;Ku_2KlZ!oAFMdX;Fy-r62JwP3sFS9 z>_4AVK}K3E#YoQeJ)v!>yk~o5S%Pa8aooPhWUhNxx2~>n%*y9@X8%NSZA;ay#^cO= zmGsKymHs>8OXxXE^Z@|C9)<$;+IH^;h>)o{O>qAKy5kwSVvvvF=Nmqbq zZ`6G${<1X?azK|`?ah>RWr&X}+m<5K2Ad`&?ix&p368^;N564TPb&_2=5;wG8Z$d` zzxqfES8iT0hcZJR0poOum7pyV*<_2Jff_be>Z%_3D&1`vZK=A1;n0#WXkS|p&%V=o zhN_*=;u!(l(U;@5h=E6X#8dfzaUH4ltdt$mZb0xCGk<^*K9lt-!;dc^X>bHfaI6`2 zYC5yM1~TKVd?dWH7V2!5|3G4f87AvvM_)s!oM#mj4-%1aFg$tHOzr@tm0k**@?)xs zZ99_2E!a)Uj_SdL)8}su)?S|P5V)V)eduBLtl2sd*6%6nEBCv-#r|3>&}#D;0t?;_ ztEu^Z#E;vKN;mRuqr=X1j8AIhR^MD6$*o#;V;5cJl7N8v4|m%AMWG!~T3{2OSE5r< zJUB;_H8kRzu8!#>EH7TCpiIKuL&AHvvdRBaXIgh%6j`voe2K)b7yP{)y8SqbA6hC8 z+rg}DD^OCz!x9+>4w34y+=g*@HTC|SPv*Ds=?+h4X`{$LSu% zhhmk%MF`q1qw9y)rY_lxNo-GQ^E1!hKO3Xf(f(0@^jTE4C`0Ex)UQLrH?{}5&kpEO z8A5)5M20CL5vnW*vThGQwlRWE?n%v3oA>*W#@F4BB2i|WidKqd{m6RufiExTXvFtL z$lvla-Nlr(m4*BOaaHM9P+?T#PVy-;J(3Qts5`5?TzxtJAUI`qb5g7H>~m6$J5z!| zab0fzyaZHBYRtrJ&Vk5Q?Ok+NeckMdEo$koJu`5yP&K*@mvnwGk9KWj__wtqt zr>Dl%^Twpf*p&k_JSVnr{ay<;Ka?&hWiaz3&d0N8$iGHCh z<+2v*=F&fH2C68+m6JG>?cOt0(V*^Ta%_j0{p4jmhkPCPf+c&VjhaKqmUVf^F6K!I z+pXt|H}iXMo{U8tz`0N#_yB#vSvg`Ftl-xv7huhr%(!B4k<7KwE+%u~r5V*mUMMjrg@V__sIz6WEc{BUKDUS+Yw z)qyv9{~#s$AVr2&E5?9!yrM2ZJp1nOt+H0yLqyqC2&Eq$f1KCjErVx;`4s)1zjkRNz=;DX35}t3IdMPg&G;pr$n2R`Yv=_OjY*&c5q3c<& zDOwCQrN91NI&whWxmWMz`?0cXs}){lE`L=Fe%w^Y9yRjjNEWa=9bF8m zdMZ{;%WH5Rxsf&Jm47=)cGNL=#d>vst7g=r=5lMGx-*0gD0SJh79QczQlh};QH!O| zHt_A8>)l6tIxRKk{%ntQQaQ6y`<{b%X<1a9)42Bh{%LnHs-_;e;>93s6L=6(lH8Jn z^t9U(k-7lzhkBhZ32B#-j>`M|@fvnCFV_1naRwaB{zdmwE3;#d+rf+vC;73yp$Fa$ zM*~1IojcRIu3YBZO&71)yTtGF`L77uy5(i+`tmuWetZZeHC$}CGAefi!|T&Eym4?e zFp^@-e#cJxl1GG<=acL&lXg_QBRY=X4=!Ft|HH}8E>=TFhjvnyiO9o|67{Uy~I6q@&1 zwFMVc@kw(Z0;~OW6c#=4sQ-%M&U2}+X^%)n{;F%0Ju$Z1$yj#GUc_TuSu{aOx?y7B z&Bo!Bw_kpNogT_2h?KU?+SRdEGN6??CkrFd{7` zX$mXeIb^liwwOupQ;t_ExAnB~w9;X|?T|j&Oid6SX+Bfd+6Q4YZwWB!wNN_d+E{H2 zo4eJ&9rd*-zIL!Hi2YJNg%-c{+rMmsDKvb00&BZGS?h^`lRR;0E4DNfPdf^E4NOy0 z&ePp%bQb^DeWU4Q7H%cmjf z0Z(W6skzSSL`{?S8v)lfn3Pt85S*jtHi&6(@o zDIpEh1?Z@8bCzBYSr}F2mO(D^Wsm=|Ey^&p+l^Sr%I&w0OYz4Yd#d^QGqTC7yXgg% z8*=pd_4AYQ+7DG4bsV)JjV`@X9svoN53u>c$_mSH`i*8rY)Cp~!kZ1Yky(=&bMX&Z zA(Fv{;Qq9D7j2=0d;fgG{fDqCyA|2deA(H&SK%l5MWkTehOjc!cpA{4*!baOY+K9Tu-L%+UMNL=tHuY7LmFAG% zHR{rr_b5&_%P*3q6_CC!`YR7?O|wlecm&_rzNip%HDt*IYm}rKp7jwfGpw3$xvx-eY_b@fAwt*8{GM^>1>pTiK&UsKaD*WigmN-SE9V+p+zv)Z*`> zGt;_G2OfjRv643$QK2xO(7zZ=AjBB)>H(lh#WvEizXG#(>=hec(qzgTox15Aldke^ zqAD8KmfuGnP0WNxDOuj6WT5HgiILw_QS?7`{>?vpKz@wG;bGD}aLGJJFK+^O)>8jlThDEXf=&eH1`j8(xD zw~QxtUzfit577Y#o|D-)_ybubgyI1NufX|B0N#T{2=lJ#0+6PQ_^O*^iiL!^l`+{J ze3fac_14{%8`hL6Y}6RNx?6}gHF>K*67X3a5!xleroOT?z0|d+7)V(i+XcGxl_%jf2EY?P87ZobzS3FgV3UViX6!R@8;n%!=X zG&h-9YJH*Luejm)TuSbA zR$R)_*m7-8*{n|&lz9w&`)$e6=7Fl{h@)j+*P$O(rdDjnY?FSUV$rpW9jp`0g0p!V z^ny|@`DgthMlgw|d+1~J;7()7N2U1til5v$4K&mr0Psopa%J|Wz0TXuBv^+}g*oVh`gs6>zVOx-#=5!F{C`FN(X{mH87&x)-U+gMAmc)tL{# zS%bv(Yyx&4)WnlFX*)K(YO^z;W=!H3G!5tg-SbDO4Q_Br$6vmuZ<-tfB6}1L0QXQ(vV+B!(DwQ(FxebReIlp&7tsf+>=4d55_BA$xYlzsaaX9hA&}v5Jh#WgOW}N~Hil)e_Tij?Lkza|RwgIr!~^V_BnrtrGBrH&;Ihy&ylQm0;TTQpi} z`7mrpSvTJzJ^ph_UTVp7>1zikhEw0^aspe~qKcLs%c2Muj;|rWxA3XxvN^8J72{f* zadNunLy_byBW{i0}h*5$Gn>sOH-AQ*8D zjC&u8Ym5_mK+o(_iB51qOa z?`^CDjmxY7q+!?zns^}3bY=+?Jeds+a+9F9=M$WYNzR3C(VvvPo$bqiGScLYJoAwy zaZ9)hlXNPl&^3+hTg&zpT;SG<#P$-p#N7PlQl}p;Gr|_iT-0-UyejSb&_%7n&95D+ zw|jew>0a?OMSzaJM4Zne{TCk$e@XxsO~6740lScGF#waa(Y@Bt`v*b0XcP|Ii3)9I z951edv*EKfMr7!9z}8jc?zBGIyDlEF7Zn~EB?wusQe}u%mi4#H1}$d<7vYUpz){T{ z_$yjK#E_9gT|Bi^yU1Qv4-#z9aa-$6q+V3Vd*NWMI&+jFrh zOpvndT$XR$G5}Sw8Z%R-0Vzt~%4EU*2+nukIaT!9;{j0&pJm3Gy9Xxt*URYw-5uRz zoh^(Kw<{e^oy+!h#+*4lA&`OAOqE)o4Zjh#-Re(;jRI0N|2ta-|EcgfA^Ri)h=XP% z9fh{fMU$=6Cxd*&`1~l7`EbB=|WpofJay5yV^QyzCAMZ0)h@#ndD~cGWRj#!1 zDUMam=|Vn^K03a{)X}mtR=Ov4eI0BqKdAUrS5O{WiXISl)f}R2cU9oj zq8h+UJ;aL|`WgHU_zFZ`c|k~LiEU@BA0Bx((wsOp0V9epnnSnrE%ey>%p)~ZOe{OQ z=-^D+=Pt=rWxA1dFOMMwPZE@QvH4v!M1?w>W+c+C#BNd|&(4$Y!i4H#gL^90x<)-l zST9L5o{@ZoQ|5q?a5e*oIA{J0_mZsxQAR}wnhrNbI0nLuU?8e=c9^O+lLTc0rX&v5 zrhLbqtH+2&i&~`akg1QC#jog=zbLoyF-bh%dxexWIeF&gJ!a>WT(sT{1U(f*WJC-t zXCxPF89eb*XdH*TbBC|jI!xz`uf$xq!BEr3RamTMgP#vdOBnWb2DV3RV_MdifH-vP zcOdf35c{VN!RZizyBW&0iDuRQTe zHCNedRHW|#5;heq)Mx~WdcFB&OD>LZ9Vdt=-Lw;bsJ*{%uW7JiV~>Ys_377zd)jM+ zd^(denYAsy)_>$r1@l)`$J-uXK!~7s4r)v77x{6J7@7B|n=pp0dpM)Ksly9-EsM3! z3cH!iqte(uEJr;D5~Xd2X68Dem7$?~gbM(H$!SES(Wv!JL$rh;s`cD~N^{V|`dr8w1EUu!)-Z{U)%9An$wOpTigK>{)C#_c2Bp@YHX zT)P(AV(yw$a49Q+(Lw<-#iBw5v7XQNp)_i~UT=HeY#hvbTW&JMTi!1z zc3|#P>W<64iFVm8$SM~hZBYC~oB`tL!; z;PWtFrnGTlsU`~p`AyCXLQk)qJC~@SFRN*!!8frEuF~AD#x@?L z;bC^zK8)gGk8Qpl#X!jGd~Fu9=$v=r?N*5Q!y;>#QqGV~5r~0;`Pl0_UQt3F zCog(u7*}V7P|_)qw5k~17pK{CJs|(QAU{*M{`ZW3@0kB5?LqRp*3o*3SW8TmkAfJa zQaZV*ud%OWY1Xw=b;?<|d*1ii$`J&%egxV1xn^f+0FFYCDX>z%GKk1kL2Rz9BgF@5)g!2BajAZ{o zeBy8K{ZDu%`|as2T$;13BY8945J_nIAQ81sCyheHE&O<5zXBMe|xYyKz*UQ^j4Mwm+SFBtD zX-=`Rb8vDApA$KM;i9yRtem`pqS_604NWcWn|JRS8X23Inpr=3Y-9Vx&fe9{-NO^% zxUUavWj8i@3dgNzjDB{DLgr^tbWf{NnjK}AjV$3gx7AE*8}Xn!8`e?NWz zKSBch2JmG{;6FVL70us2`q;5=@qA`PT$m<&sY^)m^rz7vx#z=t7`+ zUM#GLUT*Au8seccdYDj9TUAGu&zK1<(L74)=V>AjkZOWhy#Q2)UaL{B(<@R1d7Na_VV$WQL9-WdnIZ6Vy#or<&a1yP4 zGR<{k%AzG^o1RADYkI7WY)__?T;`oWc6m`9Ai;LEUrR_^b`$KYzpEu452VuP;3mTO z>UgFq?SP~JYm9dE%VOE@ReImF-?_|V3(nNqii|VlkW~QQ!q3&=27V7FO%$)XKvz*v z(RKmmD$gn98S!QIvTsDWYIc;HnUsYd+JbH7^~>P*fY9828lk@j^aGTaO-jQ3a^^$Z z_oCR7EOtFO*Rvb%2x%QS~M^Bj>AF*qPb` zn|@Jb0o`%-StrR=-Zb2(zgVQ3;e$)!H43d@tNMA89@m1Sm~0;Bt@H((?rU#{RNgn` zzBDj|SKhywTfXDNT*I+WLdD7VttW?z{M{a+s;=++#hzoDMagO10pVqGoCu=BJ6z`n$_hTG3Pi6i{Z z^C7%gZ{wQTY+$cK?b4k2!|JPG2bhrLvg*#WV{)qTjG&Hqv9pd3oD!KnGKD=rS?`7= zQ}td>4G;l)POW|~w?sca8+qSXQI3{ew%{Y^Jn7@G4|?B%#xj$}(uS#Y)LHbYfTgV( z2k+3m(#;iNZ=8~t|7e3Tp`zP8m;*Uq`=K*4H3mW0a_v}Ts>H5Fm|Syr_u>-BI<^ki z>(yR3ygEPgJ&b4B*jOEO@0drv`vZ=+TzJrM-{bWU5aKI5E{F1|g6>j#GWa4xN44F^ zRaW|(8%)&-02ut9vx$&#w6~CpnIt$VbHSg%g&mAIR4CflC;6jPzb#zfQ}S-6DT6>i zAB_KD;qrWJ^|xi~=SM$}zdiq7U$)TyVc9DAd8PmEvQ+{?|L?N($8!9?%hrE)*<$={ z*&_V;_NzOy(~qxuLU4GuT1VcU)6h&wL0r&0)L7o2JaO@wG9801=;_Fvrs3|9oS1^q za;=WjwC^aw?#%BPI4P0(+28qjkOn#QAru58l#sap_I>~RzW3gb z&+(7(?=dEW#Te^huC@2vYp%8Dd}d5F(2crP@vPGwmM9FRlJf+>~LB+|G)2yRfrH`qE9oH`PC6}NckAS<6CbguICYe&4Vw=KK ziQ+RR9yJ-anBP+%uY+7m1J(5hNz_$X>ve@Mo^5Td>DS}y47HKX{$r>tRV}=hh}`JT zW@1v<(|(0q_lYYrcO)-GkLk2K-iBQ10FO(@)C5W@9IDtKaoQbvyZ^B*X5 zzIgZe=GwqWN#2*=z%%tDP`)|b^3gyjRyMN=#9TG%8ygbcdGG=0Gsf%6QhG1W$q!#tSat(t&UYu4To-|=p1 z#>vbY>JTX^NpL~wnO1MSQR?Z=44ptcGuEF7e-@P-dSP~r3V zNG#XASi!CYqU`CErX%&lTPSwW2)$u>SON9*TFly^xPSc*|DQM}f1s>h$efp;r(f2i zb8)pgJx5_L)GU9{PINOr3(yHO0$(Tmftf}Y{j+`7^3|%M@BhOyaM>Ppu5f8;0GvsM zu3iJN>3^U^Ro*`jK6{$58xACN(shI^-VbnE|W&zgKu*OI?}f z$9k@BV$)BVX6hJ3#)M(G)o>E`jq@c)^ugys?p?0)&l_jm%iPG^h`O&P*4w9uMTHpy zEpF>-Sa#+_H|c1CU_|k&u1QZI74gXl3ZcLRP~+uHE%{usr)4#qck5DP6Iuv?$g^B( zRK+!OSjwxcXent4kp}4JNU^UG5-!=(R02^_;UX9N~#^3hb4|988ZkHlo8JiM~lz!Dw6Wu~AcZY%BKc5<^HYY~s8=RA? zbtqFQ!+C0;AimcK1W>Ey%4g2&USfXAkt}+b$zi;W7d;4D!7Yf?v5DU&;(l>iW#svM z0{e~K3XxjT>zxP7G1V+J@2)dvgd*Q1!nHh}TD%x6t6UObI5BAqzrpQ@`0gbN`Cz>2 z8-{#X{ytLRt#WJtue5WQH$9>1(YJ6=?O8DJp*r8I<5BB;C9FSJ`n7)@pIHVCcg7r2 z30nP5I0GnD)2~U*GQZG4_>ILB7lG;^>394!ffRIf#D3|9nYeCXiYG<;TvX0y;~~wG zou7`qxtcBM-ik9GRnyqu!UyLP5N$Xb@Dl0@rrve_zdUuPFKg~x!^=3L9-#1Nv`xYLT3#n=a3bEwM2m=`OS457 zoUcl1n=1bDbLg0--65=N=p8-wUS^W<{n036^lcU3V03SiI|gcpAtS)@9DHICfMtJ$ zb;vO7=(Y|mM}PkzWb!HNC-BOKW{yw9c1lV>s*+EJ_&1E_>+;Ben){2UXy@`j*>c8_ z6p2y}cb0_vt7;;QH8~`hzM`teu0^AExFzi?(S1rwe#%3 zG(Vp@yq7VEV=JKzRlS7VDRR^-xoTh}G3RYPuOFJ|?1v9anM-U+kpg4y(K_kGP=!BJ zfBrh=kwbEBmUpgnysF)xq4V>24!P}h03)c?h)#!-(n>i{+fLn|)w-vPI@I@4EXxOA z6ql`Ql4*{A&3>i~JXZ0U9qZ4|^|@Weuh?63$zD#gwQasZX!{e2Kc zgm=zylSV-#bwXJfS+!VV)KYm1m!_J+o8uZw?iI*yYvRD+G@n~*r2B@Q`-_ty9QX_& zmr4#+Bf-`IF_oq5Nv<%qH@ohlPda@Onf-i75dzlK{9BaY&PtShJzhVT3U zpIhlYL#?C$g_7hssB3b8UP&|JG^ zsF$9#mrXCpzSkq22+VQ6|5-`{jTj`|d_D1)avDnZ_d^)EO!#kTzx$2}>fc_`EA#}%5_RyE5@G=yK&K#8_sVaq!= z>s+)5IpZSzj4wM#g%RAlcry$TTR|(z_=!cQ*|J2Qbhf+K^s~eU3m(r21PtoE(8bb< zBFY04%cczV#e6^+j?|CXEisBXzDow)gaZ#Snr71V!Gn374pieG1&~-L>PMu$t>4$q zCCN6eU4uUgaluG##sPvgh+#vCd(U+?ek9fq?+e!KvvKFq$y%vtLDp!JH|=hE&Qv}r zq0_zdg5?E6cpT`GxJVH?_*L#pw82AeAY<#NN3I=PLGjm9{nNRKsUfMKFIilef{dc; z);Q25B;u6$RY4l$mp zsCyrE`pM+coU|CEu?SBdA4ni^eiJ9gW2|Q}@MC4~tFMOq zVYzgN4F#|l)r;cHW76&DtiRvN@(T>h;S#(V1%OF z3_sswp(xg|Fak_cBs9n;wKhPkOw%aYSrM*t{iezY zrF217wmP=*4HL0kgF;#sfHOtlH}euZvdyH>ONkK6A+^@N@!2DxrOxV`uVTYC$HQS< zVO#3ab0YdSUER4IHy~qU@sNEy1!`%l`9s2sb9jKXi$Chkgodlv@p*=2kQP!T9+JwY zW07cW)z^5>cZ_V3gL&^O>7%l@@(PTHGW*0Nc^{6*JmE}_r=*NGt60u3>G&x3I$FYH zCyUY9_&GBL?wJbu_!Id)n{fkpYRGoJu79*XD`@kHa4S)S{(CK9~{q+t4Mwl z5j7ZJ(iYASr4~p!Z^Z_D?J;ZkX5xOZ(#kW8IK$LC+7?4c;y^k&4Um@5@WCHN*_&lA zK*5T8DUHy=&dsBy6MOJvq^aV^0%{j)`_n;yc7eQVD&vNB#j%yniC`SlqZQ@pkxYP}jHU~TmutUjRj=hL&(C1)aYBR*{C);=pq?dSqEN;L4Zg*wf$?8LMLm0^ztoC!%LcS+7v6tGgHt0?B7k}GIit%^l z->$fu^OCR2bBx|48|Q`DQiz;L<>lC*+}O1^`2sEV=>&PLRd#=Xr{GA6|&LG_N#PwciFrZZQbNQpM$HL5GQ zLOW+uO{#`?$A}vpTmig}6gs#?Rd;TB%u$l;JtLoW{y6xKfrr>L#vtxu(MZ0v)(2VH ziB#Fd!`Hdjs>AvgcG;o2g?ltxN$UWk02zt8S21a*ZNgWfq0lGPM6I;$)&xRrl}stF z__;PZXu*(nj`O36FF!ALS~PtlP8w@YRc>s&sNU{kyTV8P zD6>zE9DM6}4^u6LxPOSZX4pa^0hc}`v44jqc(c&pEDbe9lZt^}V?0P&e97yD928k= zRXjSMV+lgAd8JA?Ic8%Br|Zk!sEgmB+b6DjZ_c%k8w_0oA%q?(dH>+2kn?u@#;Edq z*1Dd%Su@>}ie)gFm`)ahi2Q^MW-YSMej0p~TFKfgcqIWx81C_ZV^+%*5|~e|aBB1$JdZSE25?WN0@Hnv8Y7fs&-!>b~Ee`0jf%Ros z!ww+s8uRecRwCtqMI*}Bp^?5-5NcS}_sfW26L0uH>qpwE9_r)i`&SOguONg?zo&ln zi0k3Wp5y5_e+Ea!`bs66L=+{og7~?97sxh&lNr-tZ&?h1&~{-)3wNj0xMu}fD9=~9vvi%(m>3wDVkwxbbVo&MKKk58?!45d_{+RB`kLjT^VE%QkUv6r5>aU zyHNR7=Ps%H+Rq(%Lx2AM74p>+rOCp>J&(weFP#2fs%qQDOGEfm4}#2z(~*L2 z1^KAzjuI1xP=509{{Y{7xzS@)ru+#6RJr+c!T*!+@~!AbcyJ? zP=y%|=JicAN|mB!{`8px;s9#HSqt!v`2(d6)Qu-Yy5c3Hb(E}cT#@bWZ{tZm2c27i z3Npagz&wd%_9cyiQ1eAgAj6VK77mLyz4K&T&7Vy4q-&c$%?hJYlUv!Nft86^e#Idx z9H%5J65IJg+P=X5^1d(4%t1vxfm)Y`xVUGlM&C@MIKK<0zKy^8@xL~dB?iOo zr04X9Bb_hn3+vZGc!(W?2BIt<&#>(c;{L(O4GUpLN%~|#olZfZ%#)t4Oq$j`(z*p0 z@ja_~HglORq~<9Hy4WRBGx+<3yDgt+)&^TNi@;L82aH)HX=sb7n`G(Y^C%|m@N#`1 zL5w~Ii1vooq&I2dDJWW>zVBcej-iP;FIMIwT|6v zZ%%SdmD5MBk9<<4l&wT-fADcK0Kc^(z5}<++K{hJ&xJ15zVVImN3HJVjO4-2MJxF| z>sOuRTHr7C{RKdg_JdgJT*KKP5S)-SqKh;d$D=o?bGkvg_|PgNtHdXjJhF7N`^szY zdzOunYURq^r%6LX7)kES{qtH#butj=Qm50#HVU_uEIBZW>F$=4#OX>AJez=ib5y57 zB|UMFgQN+HyM@d*JWhPgCvhC;;^6b@HF{Vd?%D^LUP|6_FwZ3K>(nu_j3CjJ^os-z z9E<0J16wX<;BxCDoAB=r%i=vRQ!8CCf6OK{D;~R&^j8nDk8_0dhr)4<&;@vyeQmI6 zMf^jgu_r{+rR4I@UmytN7tZ>`7y0Nai26(Gk6W4LAE_vP3Y0|KoQt`^ne>&D&Z@LW zs6SbS808ZW^RvaDSy7p#pp}|gCCWWlF`}14{RA97`+A>0lN*l^MHy)lqJOY<-*!Tc ziCnCCm5$}{*VqwU65^`u%4fc|=Pp)E{VR+gvPN?p3^P~yjiwwT==zTyO)d%zv8_25 zJ>H@XGr)QSLiMBB2lg^Jz1YqS)iX{bB%R#V=8Ms7&mZk)kK+&v3I^0$+>rVABztGh zch9BDyMG$8@^-PK>W${pxi3{0+t#PQ6d*npvIUt@9gnc~E^yWzB(8p|wnrIgJYP6G*w@>4FITk^QXuAh|G3LC zW9ngkv?DqlyuZeOTxge;y0CFTCN$E_qF5#>pJ-R0ps(=&*Cr0!79#lwBk1E@vh{{y zM<~YJY4%}h*H68@m!YYFXiJZn4Hv#Su`X;WZgOf}21sk&QK5zwzfRT>+&m{g{HUeg zPF&@ku2N$nI@*7rEr_Klw0U!*agJDA+7b%iWFf-;;wN*(*`g^l-rLy7@DXY-Se2$LAaS=F%zk@=CYVjmRB=*5)-L?;{$GjGHmd9_6@)5!8_R6G^Alba6r=lIb zgt!i2BN|gbO0y#C%X!_o`MEaDVP{De)x};bz+u+RWT2xsO*X}An92L#)YfGpJf%Rl~;J=1Y>~5^FC^s^$X5lO(v!u96#Drk9VP z4>YYSb1VnWZAvzJTy_PGhWzO_ne;DaJ)eSm@+^5`CufA<`7v?z$Dpo`Xb^>z2~v37 zG$IG@)g8-erBdF-u;8KC;XXP-Tp^@QvPut0;#Tp2#7{pEiPyM%)nUv%`srt98Z9j! zZl=BVS(>dB+w{0w#P2<3@Gj7|di9N@AL}zU%KDGWK+2chcBSmmWrBr<#tU2zU&qoF zJ08mU%-murtum(X|vy3XBF>yA{M4S$hG_E4W zTmu3*G6LM*pPf3RI8Qr>{cU|(_vII)MCq6$9g2AnulUw2yr<^8)d7Y$TWX@Ed;ujT z=^0kObR7HZZ@r*6bmO+L5rxFM&DQp)<*-0V?S(88uv~pdy^5hanmin_go=SM$@{u2up8FU1vo8SVNlMJ`HaOEHj zqCdSF)!i?txXvLxpW7DZUE*gE&Of7YMIsqrw42$~dwMM4ddJ}?-mx1w z(mYM0(TJHm$9+@@6E+#&l#qL{^oZOdKIS?wa^gwamWVyH0n@ES!wd427fYnMJG^P_E?h3@6ZLD_aD#_=MmRKYYu zq(Wy@E@3DqF(83M&tB7b*bRCme0SWVsD8nty`x-(PybrFfUk=x~I) zI#kw*?Stol@p!Zd2vxc0Tx?>+o{Kllw!x?0a1k|Kj<)~!UNCAH>XMfZ2YP?~YT&%_ zwbE^!Zg0p zPaY8suxw55!)fdNhTmP=rF48zW;AaRn|K@Uhs?tnMRf=fqDG*)=}hg}kK`Id@y;z%RR# z%c~@ID8zo9>BJfUA*9davI03Cvs^m9RoRNowDX${gS%&0^9301_0JX?!x$CF_cz7% zL|W$q%i*|E#W8^+S2ZPKUDQG>>GD(DN_pg2r|wN~VY(cl8lCx@2ZLxEM=p8dSu9ZB{DLC`UpU`U_8CO~S<@CX6*r~qf0}_prTEj6CWnZ(5 zLQdiKSzM;>XkwjFR_npzPbh?W07Iv4?m_&Pj;`|`C?%R_%E!h33D!sd703^KmE}9% z=)Q+JuQ4B8PdSa8abm6y4Ene`#oLtF=*_iAOspo{PAogb)c&?IQ<~k2yXQvWNd3im zv|8<~QoK9;K78eowTcr#Q~c81Zb zQU1_g{Q+*9Z_DIEj7yllybNF8KHfilV|Pyi3#;3~*c9<(UDtu`#;L|}Grc!0*Rl!X zxmeU!NU3B_qewa$d&~{uIp}vL^k~O8f8s5j_$DT!R14yI z3T<$9un;Wmg5R7Is<^m{=7yIUb7roo9LeE=LndogaJlP4j{3o0w}BeBL}aJ~zQX5U zfdr=BhSPiGGfsWiV~I2H{w=FGGka>?W`;T=%mD7Tsslk&`7b%V6K#Tp=P<>YCtC1V zPRJc*FBS_j=KUe3NeZ)d`VH{|=2pv9xIvm$}SDD;tv3vEd$lBX^jl=q;Hi#D`v<~lc(C8t<&5e;7 z!)I17JqP+QuZ+EBXxa#B&|_aIapnNG9y`aa})a+7=@BL=_5KvClsaPI5a{0&A=O9I*!yM<8zTxr9fiy`mV@r zT4&)iV{^ez9rX6g17SC03u?R{mg7U7!wnDaJ%Zy|TF2%(j><7?yj+i$?ZL*-!WLg& zjRz67X_kJnqj_rFL;t9M;;C>vLzhV53iSwYk9Znycb!@&Z zigOSGhPoCHJscZ7JxyI79&_DPX1=H{ecaIkS3yuMH-x3dw@`-{+qaV+Dpl;emfN+{ zw>mz>f^Q=@35U1A#}KK~t=uLFc5G3ydlZM5h@}OHT|0HUhE%Bwna4!K&ehu*EbS{l zwS>-->Nqd9fcsgwaelb<)Bg3Qnn!ruHHx$)%pw6JXiHXFnk`x-DliV|JCgpTN-o1a zm%3L>nFrhg?s-$=1kFj#w%VKKHKa^S$(*p5;awy7gkeLv`LdNSt9O}cUhY!dP|A@g zrJ~v9nG~~_5t}XfeSP#s_Sqd2Y_wA2bG3EoOx1_fjCF~8#dFcwkQzv#RX%#6j-~lo8s|fb21n&!|zQFXIZ3 z@i<=Q5SjgDB?r^}WmP-^8KI}**)GnB5lNdLm-_;iKA|MwmMt#Jtj87Glicv*E<+Ng zQF%N*W?47U<|f5}U%X>K&!^ieeb;(88`t5?I`{or==%HD*`_*&EPs*3kCD_y%)Hq# zI2go1IM`KrcS|oH5Pk#lLIX+uKsnOW`2$5W#Bhn|!PdgEfBIViG z3lmZFZ>8m~ay~cDw|u@9UsJlV8s8G$2LX(;>WZtX{zFsCOrj`To1Q?AZE9$bq)1{i z0fQdTn^o*B9T!=Uu!Dc~c#!)lsr`*m^AUUG^Evn81E&f;Uf)(XO3GI0X(nYlRmy!_ zGENR1bQYC1*X*o6P!`13w{DU=3mzVnoMJ{ z?N;l_+a~Ni=No>;r@XXmnugvRo|Ay~mqIyItP<5w5H2~Ol_rLwp{1@t?BXllb9b}D zO6878fGf+wNbOo4Dpxpb@;+58nQQM!09wGis-YpN`56%5w@F`i+d}G(EG;{v#6YbS z5+8#;;Ls`_A+C2Mnlc~nR?e+?I8$0Q;6lO?^^+|~DQ-$$YMy-`6{7%cU(uI><<8IJ zZhoTi!?#G#9htOJDbJwUV5SDZRRed|1tva?3FWyH)+MEd&0c;*Gv%JqrnR9n^E|qb zi)5R>s)ykb-;@CUB#foCTA#OFKvwA~x}ove-q&>knAY?U3!joM@Aqo1&b4^9=_4Wq zz6~kr5PI`RaSsceC-a^O^-j;ZjU$xSMP{ep=MZCtmKm&=%tj3fa}U}ejM>n3f)ygA z4I2hHI(b627Qd|4gR;oZ8mH>+@>6UhB=#`6G6hOmgdK78(qUm@u^tp0qj|VESoPrm z5lSguk(CL=z}CVr@tvBAnFmoRPP!UC#}13r)@*WsA+u0zo_(&)b>3|c#?HpPuVa#L-|R3 z@eXYwzV{S@Prur3q#pQa6V#L}s`(TF|897&B>0;OnnmI0nKgS%_2KwFPdh28sRJc1 z5~CrGMdg4em73ilV|6TrMqE$jts!xcN?*!yyZKwO>6@6RXgD#=_z7L0Rrqk!3loYiDfyGBjVOwo!ZAu!z&Nx7(yn?qxoTyPs(05tGX$68ea@=3)LD)M()<9tVZq zpQii#-jxpr!kzjG-Wbks=1j=4LA>DXpUl0b3R;Xdn@tw;Ly?Au!<};ZUaqInZCQJn z?Zw_UP~N79k4}5f3{4KoYq>78e5aHt5xHiV^!Ta}XDbxicE;G2Q5IZou|dJ#5J4Nxr(Pi-o5&C*Fao&+?#z-2O;TDA9lQ4 zo=ME2&7p_0tfyN`Fy0(ZI%w$SbDEv51}(D>$Y5xTv<`!K=}TCm3_RG!Uu9_`?$-(n z5VW8RVFkn1R}q1}PZ_dIO!vrIW-0fX_i|hnSe#O!Rqs%@0%?P^4${0VAN5pWt>j)x zdfn^ph6<^b+uy8gi8hs`SPxnr8z znEp}BX-~)rEqR${9<*gFFVpS=hv>@4p_xyrVxm?K9+YTa^M9J$O8_-Sx@q^ zJwb<2^XNZqP*p+=7vHO2r%h{U$}6)FFxcz=kF!ztF%pP5yp#< zUcl?yj@IVu?g_5ZwRC(bz%ZZi#UEEB9`D&sX0Q0ql=)MNgiL6i4x%4b&C4cAXo|;N z9kVHoyA@wG2_BGZb0lwHbMC1fuW;hGGB<_i&!mD(8)c4-=W4TGUFH+}T!GEpclFTb zsKEUp{gnad&3MCv4uRH1!x-IJH2#WXjxlG_n72BnYL%jH%HtOW0n$N#22E-A{NJ_s zKg3Ujzw(?b<8K~bX&yFq@4uJ=Hq4%s3XqOy%|?o1(xwE6cRmntk=o7J&9+0e#szoS zyK^y)WSt8&LneBbuPhkJAk3rszR^%E?vr#DH(;eP?n>(T#8Z$ z*H<>j<@f%OOGoHMmSvT z1XnOX9F*p)lOI53a{vlQc;u{*)>$`%B(cu3iL&2Fvz%6Dy5&Z7+!bAf;El2O(^!qZ z%wGNEcsfSpeV|?=%lzm$U1};d`Qs%)g&?m=heM#opX8gJ7K88~ulyu=mCm1zLmim% zyqPb(8kRcvnLp-;NF6>U?bkrDy^=jDOj>)W+;jTGPHcLh+$7pFQ`rzhZM%nfA^j7W zfz&(4i1V_j0NMkSW-jrY`YD}O_H-w9J(`+#t);b5?fVBp`wqlY9R1;@|1{3QM~?ykr6i4!<7h<7#mnEb>zZ%6C*oU1C_Gqx?=D&A1WyMB zu3h7SGtxYSNn)@!BM=1%1YY+}V2|aHpMNdz${ld=65=O7yw&hJ9rC2_Oc>0O%P?Vb zaASRo(BBs0njmRjZfTF07FoW(GnbF(28YR9Sa&Snn}zMADI@~52G0(FF*M;yxvy*7 z)tjh?kto^~LF`V?Y8F+B=y?mk3oQNPO^RhprwijOmgww#9Yi89T(3p7!|b_4rz4>B z*Hh6hw>Y_a_UB9y{g3jf#0EVpdU&3S-AL8;6RR>> z?adTGbXfbZnIOz4^AlUzZ4mz%m$o({S@eDJq3Tbsxib#h-qa#uX`|V~RI@k3^i_-(aI98Ee27<9&O|4M(F|rP8MYbGklO@Q)gDgMU${iO)1X79;PJN@D5n+jSZfWHkk+k#9U)EOfQY@R zE%SoyXQmcVk)P9}NhF<)o#>?ZfXL6)arS|$q$mXu*ugo@pq(gfXKGPiWrf7sd3hB<35gK3-7qk$1`wZqnbVgbQgANwia03 z3Q+ha%YU^ONU6mn{7>uMzBoYOzj}7Wbxnq<@MnYLQsdjzMdS6AYKJ0<)_)qu@g!G_ zho-Ub>t>`N>nE?g?GxD3`Emq?@L%*=Jdbg2l9ZBMxHS$AH+&dF7(I9Py>No zN10vY1C!ah9r76{X&t4sdI^;UCyQfQnIw^1rOZ@2`MHB!OI^p5$YRmw=`zL8w6 z2?I3BEZR5wuisdLE%h8Nap~^XfBmk7&a6{Z@-hH>OA}zZ`IGeX|C0^mU#uLcXwpC$ z^RMd{FGs+sHC{hJn(<3W{`J?t{s22!T6yt5f?2pjt(@HW>^#l1)c)QdLrt6V9U2PC zFCqPFSCmr#@!$RR0ius5Zf0&)w*gEit$XMZqoDi}roRCU)Bg#eVCHDy?r7#_2Xj(% zvaxfr;*}5(6}T^U8(vkOUMv+h3d%2``x~Aq|DSleX6BAouKc=oj{imy61)v5+}X`! z1wi;E41Yta7W)U%BQrNMbvswLf9WM8^iQ-|V4_cB@9NP4D8JzDjpH~-(GiT)Gq*GONMl5-=@^>Q@zSR~g2OFe#0JLB7cN@h9s1*MF()g#1 zir;DncZ9b&ZyzP}pGbeRQStv_2fv=RW|#5v+tK=ek9Mmays_hKxg8Dk@E@c6yKcAI z!5t&a%iGbsevfvm9fa-P>A4+k^7m-B+QHEa{?OaexTJqO(p&A|ZNSebx1$CB7VZA6 zc2Jzu8FM?@((lp!haLQSLY%rtcy31%mHFLB@84<%sN6z7Z%2#!J=(3d(3iE`aXZ@Q z-=p1X3qQYyZYcux`AfI~`R^qw`;U>TSeaQ`y?EjVdtqi{CGT$GVD+zsP*CvJDZKmB zTEYfE`z3z|{`mh4eCuq2&*jl?AHSd6KQ#WUy$K55I-5KgzNplIiofLVYR>-??SC8p z?T!F!91(Uqu!Q_S)cjw8Z`IhAwG#FA@n`)L_;2GEy7m4yJ{^^_DFAL0Ab)>HfBz5K zpN`=ZH*dh7vbC~uyKN;(`_!dN3C!Xz;Q-{nSIU<^2Q2601Oq%oz`>Jqce924`7r(4 z&%5>Q>P`tl)c~M=3E*k|Yw^)Sh<;50xsG=wfp7!gg__pBY->lOaATvd+z+H z-S7IBo<8{Gg9`Xgfc(0x|GoIRQBnTv$*=VS=4|!C&Cbe|&)E_16#wc+|9Y{Q(u6gz z0DXVSubcSa>j%$YVE!Bt*b?x^?X2yrUi=m4*LXxpIMXhG-oJ$DzbL?O*1UfKl6SXr zwA8nH;R;N-3ZM_{h4=qd>=)kS5`kIH3RIL|g7-JPT0Yc2Y5aaMA^lU4zcc>*wI}s5 v+MgZ&%m4S!?tkZ9`fK;8jsJH4zbs5zYMB3`4CDq(bq*f|rIO(n```ZokCU1@ literal 0 HcmV?d00001 diff --git a/tests/routers/scores.csv b/tests/routers/scores.csv deleted file mode 100644 index edf2b364..00000000 --- a/tests/routers/scores.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,err,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp,0.00221984947284538,0.0005666107418204864,3.0 -p.Met1Glu,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_hgvs_nt_not_match_pro.csv b/tests/routers/scores_hgvs_nt_not_match_pro.csv deleted file mode 100644 index b20d21e5..00000000 --- a/tests/routers/scores_hgvs_nt_not_match_pro.csv +++ /dev/null @@ -1,3 +0,0 @@ -hgvs_nt,hgvs_pro,score,err,ambler -c.1A>C,p.Met1Leu,0.00201791436463821,0.000294291714898736,3.0 -c.3G>A,p.Met1Ile,0.0030227552110695657,0.000521690342044468,3.0 diff --git a/tests/routers/scores_hgvs_pro_has_same_values.csv b/tests/routers/scores_hgvs_pro_has_same_values.csv deleted file mode 100644 index c35273e0..00000000 --- a/tests/routers/scores_hgvs_pro_has_same_values.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,err,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Cys,0.00221984947284538,0.0005666107418204864,3.0 -p.Met1Glu,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_with_duplicate_columns.csv b/tests/routers/scores_with_duplicate_columns.csv deleted file mode 100644 index 1f7ad984..00000000 --- a/tests/routers/scores_with_duplicate_columns.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,score,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp,0.00221984947284538,0.0005666107418204864,3.0 -p.Met1Glu,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_with_hgvs_nt_and_pro.csv b/tests/routers/scores_with_hgvs_nt_and_pro.csv deleted file mode 100644 index e49cac44..00000000 --- a/tests/routers/scores_with_hgvs_nt_and_pro.csv +++ /dev/null @@ -1,3 +0,0 @@ -hgvs_nt,hgvs_pro,score,err,ambler -c.1A>T,p.Met1Leu,0.00201791436463821,0.000294291714898736,3.0 -c.3G>A,p.Met1Ile,0.0030227552110695657,0.000521690342044468,3.0 diff --git a/tests/routers/scores_with_invalid_hgvs_nt_prefix.csv b/tests/routers/scores_with_invalid_hgvs_nt_prefix.csv deleted file mode 100644 index e518cedc..00000000 --- a/tests/routers/scores_with_invalid_hgvs_nt_prefix.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_nt,score,err,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp,0.00221984947284538,0.0005666107418204864,3.0 -c.2C>T,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_with_invalid_hgvs_pro_prefix.csv b/tests/routers/scores_with_invalid_hgvs_pro_prefix.csv deleted file mode 100644 index be2aaddf..00000000 --- a/tests/routers/scores_with_invalid_hgvs_pro_prefix.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,err,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp,0.00221984947284538,0.0005666107418204864,3.0 -c.2C>T,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_with_nan_column_name.csv b/tests/routers/scores_with_nan_column_name.csv deleted file mode 100644 index 9d50cc85..00000000 --- a/tests/routers/scores_with_nan_column_name.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score, ,ambler -p.Met1Ala,0.00201791436463821,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp,0.00221984947284538,0.0005666107418204864,3.0 -p.Met1Glu,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_with_string.csv b/tests/routers/scores_with_string.csv deleted file mode 100644 index b4b56e37..00000000 --- a/tests/routers/scores_with_string.csv +++ /dev/null @@ -1,12 +0,0 @@ -hgvs_pro,score,err,ambler -p.Met1Ala, 0.0030227552110695611 ,0.000294291714898736,3.0 -p.Met1Cys,0.0030227552110695657,0.000521690342044468,3.0 -p.Met1Asp, abc,0.0005666107418204864,3.0 -p.Met1Glu,0.00237828918977636,0.00042051167207546845,3.0 -p.Met1Phe,0.005702414661461012,0.0015618903633585822,3.0 -p.Met1Gly,0.0012076958364638844,0.0001735283520462529,3.0 -p.Met1His,0.0016630080489589568,0.0004115364012988436,3.0 -p.Met1Ile,0.37803241907317636,0.04914421447951293,3.0 -p.Met1Lys,0.002639860787342766,0.0003765768113237344,3.0 -p.Met1Leu,0.3928550107047532,0.05107115139161792,3.0 -p.Met1Met,NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_without_hgvs_column.csv b/tests/routers/scores_without_hgvs_column.csv deleted file mode 100644 index b45245ef..00000000 --- a/tests/routers/scores_without_hgvs_column.csv +++ /dev/null @@ -1,5 +0,0 @@ -score,err,ambler -0.00201791436463821,0.000294291714898736,3.0 -0.0030227552110695657,0.000521690342044468,3.0 -0.00221984947284538,0.0005666107418204864,3.0 -NA,NA,3.0 \ No newline at end of file diff --git a/tests/routers/scores_without_score_column.csv b/tests/routers/scores_without_score_column.csv deleted file mode 100644 index 707dcaab..00000000 --- a/tests/routers/scores_without_score_column.csv +++ /dev/null @@ -1,3 +0,0 @@ -hgvs_pro,err -p.Met1Ala,0.1 -p.Met1Cys,0.2 diff --git a/tests/routers/test_score_set.py b/tests/routers/test_score_set.py index 8a38952e..dc6e142d 100644 --- a/tests/routers/test_score_set.py +++ b/tests/routers/test_score_set.py @@ -2089,6 +2089,26 @@ def test_score_set_not_found_for_non_existent_score_set_when_adding_score_calibr assert "score_calibrations" not in response_data +######################################################################################################################## +# Score set upload files +######################################################################################################################## + +# Not sure why scores_non_utf8_encoded.csv file has a wrong encoding problem, but it's good for this test. +def test_upload_a_non_utf8_file(session, client, setup_router_db, data_files): + experiment = create_experiment(client) + score_set = create_seq_score_set(client, experiment["urn"]) + scores_csv_path = data_files / "scores_non_utf8_encoded.csv" + with open(scores_csv_path, "rb") as scores_file: + response = client.post( + f"/api/v1/score-sets/{score_set['urn']}/variants/data", + files={"scores_file": (scores_csv_path.name, scores_file, "text/csv")}, + ) + assert response.status_code == 400 + response_data = response.json() + assert f"Error decoding file: 'utf-8' codec can't decode byte 0xdd in position 10: invalid continuation byte. " \ + f"Ensure the file has correct values." in response_data["detail"] + + ######################################################################################################################## # Score set download files ######################################################################################################################## From f55d8d4a6dc2dc6d01ea2df444da09e41122f0f1 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Tue, 4 Mar 2025 00:12:06 -0800 Subject: [PATCH 03/20] Add statistics router for counts of published records --- src/mavedb/routers/statistics.py | 38 +++++++++++++++++++- tests/routers/test_statistics.py | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index ad720526..c49f2515 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -1,5 +1,7 @@ +import itertools +from collections import OrderedDict from enum import Enum -from typing import Union +from typing import Union, Optional from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import Table, func, select @@ -77,6 +79,11 @@ class RecordFields(str, Enum): createdBy = "created-by" +class GroupBy(str, Enum): + month = "month" + year = "year" + + def _target_from_field_and_model( db: Session, model: Union[type[TargetAccession], type[TargetSequence]], @@ -344,3 +351,32 @@ def record_object_statistics( count_data = _record_from_field_and_model(db, model, field) return {field_val: count for field_val, count in count_data if field_val is not None} + + +@router.get("/record/{model}/published/count", status_code=200, response_model=dict[str, int]) +def record_counts(model: RecordNames, group: Optional[GroupBy] = None, db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the number of records in each table. + """ + models: dict[RecordNames, Union[type[Experiment], type[ScoreSet]]] = { + RecordNames.experiment: Experiment, + RecordNames.scoreSet: ScoreSet, + } + + queried_model = models[model] + + # Protects against Nonetype publication dates with where clause and ignore mypy typing errors in dictcomps. + objs = db.scalars( + select(queried_model.published_date) + .where(queried_model.published_date.isnot(None)) + .order_by(queried_model.published_date) + ).all() + + if group == GroupBy.month: + grouped = {k: len(list(g)) for k, g in itertools.groupby(objs, lambda t: t.strftime("%Y-%m"))} # type: ignore + elif group == GroupBy.year: + grouped = {k: len(list(g)) for k, g in itertools.groupby(objs, lambda t: t.strftime("%Y"))} # type: ignore + else: + grouped = {"all": len(objs)} + + return OrderedDict(sorted(grouped.items())) diff --git a/tests/routers/test_statistics.py b/tests/routers/test_statistics.py index 249c86a7..0cdf6ca6 100644 --- a/tests/routers/test_statistics.py +++ b/tests/routers/test_statistics.py @@ -367,3 +367,64 @@ def test_record_statistics_invalid_record_and_field(client): assert response.json()["detail"][0]["ctx"]["enum_values"] == RECORD_MODELS assert response.json()["detail"][1]["loc"] == ["path", "field"] assert response.json()["detail"][1]["ctx"]["enum_values"] == RECORD_SHARED_FIELDS + + +# Test record counts statistics +@pytest.mark.parametrize("model_value", RECORD_MODELS) +def test_record_counts_no_published_data(client, model_value, setup_router_db): + """Test record counts endpoint for published experiments and score sets.""" + response = client.get(f"/api/v1/statistics/record/{model_value}/published/count") + assert response.status_code == 200 + assert "all" in response.json() + assert response.json()["all"] == 0 + + +@pytest.mark.parametrize("model_value", RECORD_MODELS) +def test_record_counts(client, model_value, setup_router_db, setup_seq_scoreset): + """Test record counts endpoint for published experiments and score sets.""" + response = client.get(f"/api/v1/statistics/record/{model_value}/published/count") + assert response.status_code == 200 + assert "all" in response.json() + assert response.json()["all"] == 1 + + +@pytest.mark.parametrize("model_value", RECORD_MODELS) +@pytest.mark.parametrize("group_value", ["month", "year"]) +def test_record_counts_grouped_no_published_data(client, model_value, group_value, setup_router_db): + """Test record counts endpoint grouped by month and year for published experiments and score sets.""" + response = client.get(f"/api/v1/statistics/record/{model_value}/published/count?group={group_value}") + assert response.status_code == 200 + assert isinstance(response.json(), dict) + for key, value in response.json().items(): + assert isinstance(key, str) + assert isinstance(value, int) + + +@pytest.mark.parametrize("model_value", RECORD_MODELS) +@pytest.mark.parametrize("group_value", ["month", "year"]) +def test_record_counts_grouped( + session, client, model_value, group_value, setup_router_db, setup_seq_scoreset, setup_acc_scoreset +): + """Test record counts endpoint grouped by month and year for published experiments and score sets.""" + response = client.get(f"/api/v1/statistics/record/{model_value}/published/count?group={group_value}") + assert response.status_code == 200 + assert isinstance(response.json(), dict) + for key, value in response.json().items(): + assert isinstance(key, str) + assert value == 2 + + +def test_record_counts_invalid_model(client): + """Test record counts endpoint with an invalid model.""" + response = client.get("/api/v1/statistics/record/invalid-model/published/count") + assert response.status_code == 422 + assert response.json()["detail"][0]["loc"] == ["path", "model"] + assert response.json()["detail"][0]["ctx"]["enum_values"] == RECORD_MODELS + + +def test_record_counts_invalid_group(client): + """Test record counts endpoint with an invalid group.""" + response = client.get("/api/v1/statistics/record/experiment/published/count?group=invalid-group") + assert response.status_code == 422 + assert response.json()["detail"][0]["loc"] == ["query", "group"] + assert response.json()["detail"][0]["ctx"]["enum_values"] == ["month", "year"] From b8b2b06c2a172185ab0f4553e6bd10291f0c247b Mon Sep 17 00:00:00 2001 From: EstelleDa Date: Tue, 4 Mar 2025 19:14:36 +1100 Subject: [PATCH 04/20] Remove extraneous `f` prefix --- tests/routers/test_score_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/routers/test_score_set.py b/tests/routers/test_score_set.py index dc6e142d..738143f7 100644 --- a/tests/routers/test_score_set.py +++ b/tests/routers/test_score_set.py @@ -2105,8 +2105,8 @@ def test_upload_a_non_utf8_file(session, client, setup_router_db, data_files): ) assert response.status_code == 400 response_data = response.json() - assert f"Error decoding file: 'utf-8' codec can't decode byte 0xdd in position 10: invalid continuation byte. " \ - f"Ensure the file has correct values." in response_data["detail"] + assert "Error decoding file: 'utf-8' codec can't decode byte 0xdd in position 10: invalid continuation byte. " \ + "Ensure the file has correct values." in response_data["detail"] ######################################################################################################################## From 8076cf5155de9770805dede953cb2a5d09e01792 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Wed, 5 Mar 2025 14:34:53 -0800 Subject: [PATCH 05/20] Refactor statistics endpoints for simplicity The previous version of these statistics endpoints featured code that was overly complex for the task at hand. This change refactors statistics code in a way that slightly increases duplicated code (mostly API decorators) while decreasing the complexity of shared functions and logic switches. The result is much clearer and concise endpoints for existing routes. --- src/mavedb/routers/statistics.py | 564 +++++++++++++++++-------------- tests/routers/test_statistics.py | 77 +++-- 2 files changed, 357 insertions(+), 284 deletions(-) diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index c49f2515..137d97f2 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -1,10 +1,10 @@ import itertools from collections import OrderedDict from enum import Enum -from typing import Union, Optional +from typing import Any, Union, Optional from fastapi import APIRouter, Depends, HTTPException -from sqlalchemy import Table, func, select +from sqlalchemy import Table, func, select, Select from sqlalchemy.orm import Session from mavedb.deps import get_db @@ -43,27 +43,20 @@ responses={404: {"description": "Not found"}}, ) -## Enum classes hold valid endpoints for different statistics routes. - - -class TargetGeneFields(str, Enum): - category = "category" - organism = "organism" +TARGET_ACCESSION_TAXONOMY = "Homo sapiens" - ensemblIdentifier = "ensembl-identifier" - refseqIdentifier = "refseq-identifier" - uniprotIdentifier = "uniprot-identifier" +## Union types +RecordModels = Union[type[Experiment], type[ScoreSet]] +RecordAssociationTables = Union[ + Table, + type[ExperimentControlledKeywordAssociation], + type[ExperimentPublicationIdentifierAssociation], + type[ScoreSetPublicationIdentifierAssociation], +] -class TargetAccessionFields(str, Enum): - accession = "accession" - assembly = "assembly" - gene = "gene" - -class TargetSequenceFields(str, Enum): - sequence = "sequence" - sequenceType = "sequence-type" +## Enum classes hold valid endpoints for different statistics routes. class RecordNames(str, Enum): @@ -84,288 +77,189 @@ class GroupBy(str, Enum): year = "year" -def _target_from_field_and_model( - db: Session, - model: Union[type[TargetAccession], type[TargetSequence]], - field: Union[TargetAccessionFields, TargetSequenceFields], -): +def _model_and_association_from_record_field( + record: RecordNames, field: Optional[RecordFields] +) -> tuple[RecordModels, Optional[RecordAssociationTables]]: """ - Given either the target accession or target sequence model, generate counts that can be used to create - a statistic for those fields. + Given a member of the RecordNames and RecordFields Enums, generate the model and association table that can be used + to generate statistics for those fields. + + This function should be used for generating statistics for fields shared between Experiments and Score Sets. + If necessary, Experiment Sets can be handled in a similar manner in the future. """ - # Protection from this case occurs via FastApi/pydantic Enum validation on endpoints that reference this function. - # If we are careful with our enumeration definitons, we should not end up here. - if (model == TargetAccession and field not in TargetAccessionFields) or ( - model == TargetSequence and field not in TargetSequenceFields - ): - raise HTTPException(422, f"Field `{field.name}` is incompatible with target model `{model}`.") + record_to_model_map: dict[RecordNames, RecordModels] = { + RecordNames.experiment: Experiment, + RecordNames.scoreSet: ScoreSet, + } + record_to_assc_map: dict[RecordNames, dict[RecordFields, RecordAssociationTables]] = { + RecordNames.experiment: { + RecordFields.doiIdentifiers: experiments_doi_identifiers_association_table, + RecordFields.publicationIdentifiers: ExperimentPublicationIdentifierAssociation, + RecordFields.rawReadIdentifiers: experiments_raw_read_identifiers_association_table, + RecordFields.keywords: ExperimentControlledKeywordAssociation, + }, + RecordNames.scoreSet: { + RecordFields.doiIdentifiers: score_sets_doi_identifiers_association_table, + RecordFields.publicationIdentifiers: ScoreSetPublicationIdentifierAssociation, + RecordFields.rawReadIdentifiers: score_sets_raw_read_identifiers_association_table, + }, + } - published_score_sets_stmt = select(ScoreSet).where(ScoreSet.published_date.is_not(None)).subquery() + queried_model = record_to_model_map[record] + queried_model_assc = record_to_assc_map[record] - # getattr obscures MyPy errors by coercing return type to Any - model_field = field.value.replace("-", "_") - column_field = getattr(model, model_field) - query = ( - select(column_field, func.count(column_field)) - .join(TargetGene) - .group_by(column_field) - .join_from(TargetGene, published_score_sets_stmt) - ) + if field is None or field not in queried_model_assc: + return queried_model, None - return db.execute(query).all() + return queried_model, queried_model_assc[field] -# Accession based targets only. -@router.get("/target/accession/{field}", status_code=200, response_model=dict[str, int]) -def target_accessions_by_field(field: TargetAccessionFields, db: Session = Depends(get_db)) -> dict[str, int]: - """ - Returns a dictionary of counts for the distinct values of the provided `field` (member of the `target_accessions` table). - Don't include any NULL field values. - """ - return { - field_val: count - for field_val, count in _target_from_field_and_model(db, TargetAccession, field) - if field_val is not None - } +def _join_model_and_filter_unpublished(query: Select, model: RecordModels) -> Select: + return query.join(model).where(model.published_date.is_not(None)) -# Sequence based targets only. -@router.get("/target/sequence/{field}", status_code=200, response_model=dict[str, int]) -def target_sequences_by_field(field: TargetSequenceFields, db: Session = Depends(get_db)) -> dict[str, int]: - """ - Returns a dictionary of counts for the distinct values of the provided `field` (member of the `target_sequences` table). - Don't include any NULL field values. - """ - return { - field_val: count - for field_val, count in _target_from_field_and_model(db, TargetSequence, field) - if field_val is not None - } +def _count_for_identifier_in_query(db: Session, query: Select[tuple[Any, int]]) -> dict[Any, int]: + return {value: count for value, count in db.execute(query).all() if value is not None} + + +######################################################################################## +# Record statistics +######################################################################################## -# Statistics on fields relevant to both accession and sequence based targets. Generally, these require custom logic to harmonize both target sub types. -@router.get("/target/gene/{field}", status_code=200, response_model=dict[str, int]) -def target_genes_by_field(field: TargetGeneFields, db: Session = Depends(get_db)) -> dict[str, int]: +@router.get( + "/record/{record}/keywords", status_code=200, response_model=Union[dict[str, int], dict[str, dict[str, int]]] +) +def experiment_keyword_statistics( + record: RecordNames, db: Session = Depends(get_db) +) -> Union[dict[str, int], dict[str, dict[str, int]]]: """ - Returns a dictionary of counts for the distinct values of the provided `field` (member of the `target_sequences` table). - Don't include any NULL field values. Each field here is handled individually because of the unique structure of this - target gene object- fields might require information from both TargetGene subtypes (accession and sequence). + Returns a dictionary of counts for the distinct values of the `value` field (member of the `controlled_keywords` table). + Don't include any NULL field values. Don't include any keywords from unpublished experiments. """ - association_tables: dict[TargetGeneFields, Union[type[EnsemblOffset], type[RefseqOffset], type[UniprotOffset]]] = { - TargetGeneFields.ensemblIdentifier: EnsemblOffset, - TargetGeneFields.refseqIdentifier: RefseqOffset, - TargetGeneFields.uniprotIdentifier: UniprotOffset, - } - identifier_models: dict[ - TargetGeneFields, Union[type[EnsemblIdentifier], type[RefseqIdentifier], type[UniprotIdentifier]] - ] = { - TargetGeneFields.ensemblIdentifier: EnsemblIdentifier, - TargetGeneFields.refseqIdentifier: RefseqIdentifier, - TargetGeneFields.uniprotIdentifier: UniprotIdentifier, - } + if record == RecordNames.scoreSet: + raise HTTPException( + 422, + "The 'keywords' field can only be used with the 'experiment' model. Score sets do not have associated keywords.", + ) - # All targets linked to a published score set. - published_score_sets_stmt = select(TargetGene).join(ScoreSet).where(ScoreSet.published_date.is_not(None)).subquery() + queried_model, queried_assc = _model_and_association_from_record_field(record, RecordFields.keywords) - # Assumes identifiers cannot be duplicated within a Target. - if field in identifier_models.keys(): - # getattr obscures MyPy errors by coercing return type to Any - attr_for_identifier = getattr(identifier_models[field], "identifier") + if queried_assc is None: + raise HTTPException(500, "No association table associated with the keywords field when one was expected.") - query = ( - select(attr_for_identifier, func.count(attr_for_identifier)) - .join(association_tables[field]) - .join(published_score_sets_stmt) - .group_by(attr_for_identifier) - ) + query = _join_model_and_filter_unpublished( + select(ControlledKeyword.value, func.count(ControlledKeyword.value)).join(queried_assc), queried_model + ).group_by(ControlledKeyword.value) - return {identifier: count for identifier, count in db.execute(query).all() if identifier is not None} + return _count_for_identifier_in_query(db, query) - # Can't join a TargetGene query to TargetGene query, so just select the desired columns directly from the subquery. - elif field is TargetGeneFields.category: - query = select(published_score_sets_stmt.c.category, func.count(published_score_sets_stmt.c.category)).group_by( - published_score_sets_stmt.c.category - ) - return {category: count for category, count in db.execute(query).all() if category is not None} +@router.get("/record/{record}/publication-identifiers", status_code=200, response_model=dict[str, dict[str, int]]) +def experiment_publication_identifier_statistics( + record: RecordNames, db: Session = Depends(get_db) +) -> dict[str, dict[str, int]]: + """ + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `publication_identifiers` table). + Don't include any publication identifiers from unpublished experiments. + """ + queried_model, queried_assc = _model_and_association_from_record_field(record, RecordFields.publicationIdentifiers) - # Target gene organism needs special handling: it is stored differently between accession and sequence Targets. - elif field is TargetGeneFields.organism: - sequence_based_targets_query = ( - select(Taxonomy.organism_name, func.count(Taxonomy.organism_name)) - .join(TargetSequence) - .join(published_score_sets_stmt) - .group_by(Taxonomy.organism_name) + if queried_assc is None: + raise HTTPException( + 500, "No association table associated with the publication identifiers field when one was expected." ) - accession_based_targets_query = select(func.count(TargetAccession.id)).join(published_score_sets_stmt) - organisms: dict[str, int] = { - organism: count - for organism, count in db.execute(sequence_based_targets_query).all() - if organism is not None - } - accession_count = db.execute(accession_based_targets_query).scalar_one_or_none() + query = _join_model_and_filter_unpublished( + select( + PublicationIdentifier.identifier, + PublicationIdentifier.db_name, + func.count(PublicationIdentifier.identifier), + ).join(queried_assc), + queried_model, + ).group_by(PublicationIdentifier.identifier, PublicationIdentifier.db_name) - # NOTE: For now (forever?), all accession based targets are human genomic sequences. It is possible this - # assumption changes if we add mouse (or other non-human) genomes to MaveDB. - if "Homo sapiens" in organisms and accession_count: - organisms["Homo sapiens"] += accession_count - elif accession_count: - organisms["Homo sapiens"] = accession_count + publication_identifiers: dict[str, dict[str, int]] = {} - return organisms + for identifier, db_name, count in db.execute(query).all(): + # We don't need to worry about overwriting existing identifiers within these internal dictionaries because + # of the SQL group by clause. + if db_name in publication_identifiers: + publication_identifiers[db_name][identifier] = count + else: + publication_identifiers[db_name] = {identifier: count} - # Protection from this case occurs via FastApi/pydantic Enum validation. - else: - raise ValueError(f"Unknown field: {field}") + return publication_identifiers -def _record_from_field_and_model( - db: Session, - model: RecordNames, - field: RecordFields, -): +@router.get("/record/{record}/raw-read-identifiers", status_code=200, response_model=dict[str, int]) +def experiment_raw_read_identifier_statistics(record: RecordNames, db: Session = Depends(get_db)) -> dict[str, int]: """ - Given a member of the RecordNames and RecordFields Enums, generate counts that can be used to create a - statistic for those enums. - - This function should be used for generating statistics for fields shared between Experiments and Score Sets. - If necessary, Experiment Sets can be handled in a similar manner in the future. + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `raw_read_identifiers` table). + Don't include any raw read identifiers from unpublished experiments. """ - association_tables: dict[ - RecordNames, - dict[ - RecordFields, - Union[ - Table, - type[ExperimentControlledKeywordAssociation], - type[ExperimentPublicationIdentifierAssociation], - type[ScoreSetPublicationIdentifierAssociation], - ], - ], - ] = { - RecordNames.experiment: { - RecordFields.doiIdentifiers: experiments_doi_identifiers_association_table, - RecordFields.publicationIdentifiers: ExperimentPublicationIdentifierAssociation, - RecordFields.rawReadIdentifiers: experiments_raw_read_identifiers_association_table, - RecordFields.keywords: ExperimentControlledKeywordAssociation, - }, - RecordNames.scoreSet: { - RecordFields.doiIdentifiers: score_sets_doi_identifiers_association_table, - RecordFields.publicationIdentifiers: ScoreSetPublicationIdentifierAssociation, - RecordFields.rawReadIdentifiers: score_sets_raw_read_identifiers_association_table, - }, - } - - models: dict[RecordNames, Union[type[Experiment], type[ScoreSet]]] = { - RecordNames.experiment: Experiment, - RecordNames.scoreSet: ScoreSet, - } - - queried_model = models[model] - - # created-by field does not operate on association tables and is defined directly on score set / experiment - # records, so we operate directly on those records. - # getattr obscures MyPy errors by coercing return type to Any - model_created_by_field = getattr(queried_model, "created_by_id") - model_published_data_field = getattr(queried_model, "published_date") - if field is RecordFields.createdBy: - query = ( - select(User.username, func.count(User.id)) - .join(queried_model, model_created_by_field == User.id) - .where(model_published_data_field.is_not(None)) - .group_by(User.id) - ) + queried_model, queried_assc = _model_and_association_from_record_field(record, RecordFields.rawReadIdentifiers) - return db.execute(query).all() - else: - # All assc table identifiers which are linked to a published model. - queried_assc_table = association_tables[model][field] - published_score_sets_statement = ( - select(queried_assc_table).join(queried_model).where(model_published_data_field.is_not(None)).subquery() + if queried_assc is None: + raise HTTPException( + 500, "No association table associated with the raw read identifiers field when one was expected." ) - # Assumes any identifiers / keywords may not be duplicated within a record. - if field is RecordFields.doiIdentifiers: - query = select(DoiIdentifier.identifier, func.count(DoiIdentifier.identifier)).group_by( - DoiIdentifier.identifier - ) - elif field is RecordFields.keywords: - query = select(ControlledKeyword.value, func.count(ControlledKeyword.value)).group_by(ControlledKeyword.value) - elif field is RecordFields.rawReadIdentifiers: - query = select(RawReadIdentifier.identifier, func.count(RawReadIdentifier.identifier)).group_by( - RawReadIdentifier.identifier - ) + query = _join_model_and_filter_unpublished( + select(RawReadIdentifier.identifier, func.count(RawReadIdentifier.identifier)).join(queried_assc), queried_model + ).group_by(RawReadIdentifier.identifier) - # Handle publication identifiers separately since they may have duplicated identifiers - elif field is RecordFields.publicationIdentifiers: - publication_query = ( - select( - PublicationIdentifier.identifier, - PublicationIdentifier.db_name, - func.count(PublicationIdentifier.identifier), - ) - .join(published_score_sets_statement) - .group_by(PublicationIdentifier.identifier, PublicationIdentifier.db_name) - ) + return _count_for_identifier_in_query(db, query) - publication_identifiers: dict[str, dict[str, int]] = {} - for identifier, db_name, count in db.execute(publication_query).all(): - # We don't need to worry about overwriting existing identifiers within these internal dictionaries because - # of the SQL group by clause. - if db_name in publication_identifiers: - publication_identifiers[db_name][identifier] = count - else: - publication_identifiers[db_name] = {identifier: count} +@router.get("/record/{record}/doi-identifiers", status_code=200, response_model=dict[str, int]) +def experiment_doi_identifiers_statistics(record: RecordNames, db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `doi_identifiers` table). + Don't include any DOI identifiers from unpublished experiments. + """ + queried_model, queried_assc = _model_and_association_from_record_field(record, RecordFields.doiIdentifiers) - return [(db_name, identifiers) for db_name, identifiers in publication_identifiers.items()] + if queried_assc is None: + raise HTTPException( + 500, "No association table associated with the doi identifiers field when one was expected." + ) - # Protection from this case occurs via FastApi/pydantic Enum validation on methods which reference this one. - else: - return [] + query = _join_model_and_filter_unpublished( + select(DoiIdentifier.identifier, func.count(DoiIdentifier.identifier)).join(queried_assc), queried_model + ).group_by(DoiIdentifier.identifier) - return db.execute(query.join(published_score_sets_statement)).all() + return _count_for_identifier_in_query(db, query) -# Model based statistics for shared fields. -# -# NOTE: If custom logic is needed for record models with more specific endpoint paths, -# i.e. non-shared fields, define them above this route so as not to obscure them. -@router.get("/record/{model}/{field}", status_code=200, response_model=Union[dict[str, int], dict[str, dict[str, int]]]) -def record_object_statistics( - model: RecordNames, field: RecordFields, db: Session = Depends(get_db) -) -> Union[dict[str, int], dict[str, dict[str, int]]]: +@router.get("/record/{record}/created-by", status_code=200, response_model=dict[str, int]) +def experiment_created_by_statistics(record: RecordNames, db: Session = Depends(get_db)) -> dict[str, int]: """ - Resolve a dictionary of statistics based on the provided model name and model field. - - Model names and fields should be members of the Enum classes defined above. Providing an invalid model name or - model field will yield a 422 Unprocessable Entity error with details about valid enum values. + Returns a dictionary of counts for the distinct values of the `username` field (member of the `users` table). + Don't include any usernames from unpublished experiments. """ - # Validation to ensure 'keywords' is only used with 'experiment'. - if model == RecordNames.scoreSet and field == RecordFields.keywords: - raise HTTPException( - status_code=422, detail="The 'keywords' field can only be used with the 'experiment' model." - ) + queried_model, queried_assc = _model_and_association_from_record_field(record, RecordFields.createdBy) - count_data = _record_from_field_and_model(db, model, field) + query = ( + select(User.username, func.count(User.id)) + .join(queried_model, queried_model.created_by_id == User.id) + .filter(queried_model.published_date.is_not(None)) + .group_by(User.id) + ) - return {field_val: count for field_val, count in count_data if field_val is not None} + return _count_for_identifier_in_query(db, query) @router.get("/record/{model}/published/count", status_code=200, response_model=dict[str, int]) def record_counts(model: RecordNames, group: Optional[GroupBy] = None, db: Session = Depends(get_db)) -> dict[str, int]: """ - Returns a dictionary of counts for the number of records in each table. + Returns a dictionary of counts for the number of published records of the `model` parameter. + Optionally, group the counts by the published month or year. """ - models: dict[RecordNames, Union[type[Experiment], type[ScoreSet]]] = { - RecordNames.experiment: Experiment, - RecordNames.scoreSet: ScoreSet, - } - - queried_model = models[model] + queried_model, queried_assc = _model_and_association_from_record_field(model, None) - # Protects against Nonetype publication dates with where clause and ignore mypy typing errors in dictcomps. + # Protect against Nonetype publication dates with where clause. + # We can safely ignore Mypy Nonetype errors in the following dictcomps. objs = db.scalars( select(queried_model.published_date) .where(queried_model.published_date.isnot(None)) @@ -380,3 +274,173 @@ def record_counts(model: RecordNames, group: Optional[GroupBy] = None, db: Sessi grouped = {"all": len(objs)} return OrderedDict(sorted(grouped.items())) + + +######################################################################################## +# Target statistics +######################################################################################## + + +##### Accession based targets ##### + + +@router.get("/target/accession/accession", status_code=200, response_model=dict[str, int]) +def target_accessions_accession_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `accession` field (member of the `target_accessions` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetAccession.accession, func.count(TargetAccession.accession)).join(TargetGene), ScoreSet + ).group_by(TargetAccession.accession) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/accession/assembly", status_code=200, response_model=dict[str, int]) +def target_accessions_assembly_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `assembly` field (member of the `target_accessions` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetAccession.assembly, func.count(TargetAccession.assembly)).join(TargetGene), ScoreSet + ).group_by(TargetAccession.assembly) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/accession/gene", status_code=200, response_model=dict[str, int]) +def target_accessions_gene_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `gene` field (member of the `target_accessions` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetAccession.gene, func.count(TargetAccession.gene)).join(TargetGene), ScoreSet + ).group_by(TargetAccession.gene) + + return _count_for_identifier_in_query(db, query) + + +##### Sequence based targets ##### + + +@router.get("/target/sequence/sequence", status_code=200, response_model=dict[str, int]) +def target_sequences_sequence_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `sequence` field (member of the `target_sequences` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetSequence.sequence, func.count(TargetSequence.sequence)).join(TargetGene), ScoreSet + ).group_by(TargetSequence.sequence) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/sequence/sequence-type", status_code=200, response_model=dict[str, int]) +def target_sequences_sequence_type_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `sequence_type` field (member of the `target_sequences` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetSequence.sequence_type, func.count(TargetSequence.sequence_type)).join(TargetGene), ScoreSet + ).group_by(TargetSequence.sequence_type) + + return _count_for_identifier_in_query(db, query) + + +##### Target genes ##### + + +@router.get("/target/gene/category", status_code=200, response_model=dict[str, int]) +def target_genes_category_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `category` field (member of the `target_sequences` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetGene.category, func.count(TargetGene.category)), ScoreSet + ).group_by(TargetGene.category) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/gene/organism", status_code=200, response_model=dict[str, int]) +def target_genes_organism_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `organism` field (member of the `taxonomies` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + + NOTE: For now (and perhaps forever), all accession based targets are human genomic sequences (ie: of taxonomy `Homo sapiens`). + It is possible this assumption changes if we add mouse (or other non-human) genomes to MaveDB. + """ + target_sequence_query = _join_model_and_filter_unpublished( + select(Taxonomy.organism_name, func.count(Taxonomy.organism_name)).join(TargetSequence).join(TargetGene), + ScoreSet, + ).group_by(Taxonomy.organism_name) + target_accession_query = _join_model_and_filter_unpublished( + select(func.count(TargetAccession.id)).join(TargetGene), ScoreSet + ) + + # Ensure the `Homo sapiens` key exists in the organisms counts dictionary. + organisms = _count_for_identifier_in_query(db, target_sequence_query) + organisms.setdefault(TARGET_ACCESSION_TAXONOMY, 0) + + count_accession_based_targets = db.execute(target_accession_query).scalar_one_or_none() + if count_accession_based_targets: + organisms[TARGET_ACCESSION_TAXONOMY] += count_accession_based_targets + else: + organisms.pop(TARGET_ACCESSION_TAXONOMY) + + return organisms + + +@router.get("/target/gene/ensembl-identifier", status_code=200, response_model=dict[str, int]) +def target_genes_ensembl_identifier_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `ensembl_identifiers` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(EnsemblIdentifier.identifier, func.count(EnsemblIdentifier.identifier)) + .join(EnsemblOffset) + .join(TargetGene), + ScoreSet, + ).group_by(EnsemblIdentifier.identifier) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/gene/refseq-identifier", status_code=200, response_model=dict[str, int]) +def target_genes_refseq_identifier_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `refseq_identifiers` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(RefseqIdentifier.identifier, func.count(RefseqIdentifier.identifier)) + .join(RefseqOffset) + .join(TargetGene), + ScoreSet, + ).group_by(RefseqIdentifier.identifier) + + return _count_for_identifier_in_query(db, query) + + +@router.get("/target/gene/uniprot-identifier", status_code=200, response_model=dict[str, int]) +def target_genes_uniprot_identifier_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `identifier` field (member of the `uniprot_identifiers` table). + Don't include any NULL field values. Don't include any targets from unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(UniprotIdentifier.identifier, func.count(UniprotIdentifier.identifier)) + .join(UniprotOffset) + .join(TargetGene), + ScoreSet, + ).group_by(UniprotIdentifier.identifier) + + return _count_for_identifier_in_query(db, query) diff --git a/tests/routers/test_statistics.py b/tests/routers/test_statistics.py index 0cdf6ca6..7196196d 100644 --- a/tests/routers/test_statistics.py +++ b/tests/routers/test_statistics.py @@ -53,11 +53,14 @@ def assert_statistic(desired_field_value, response): ), f"Target accession statistic {desired_field_value} should appear on one (and only one) test score set." -# Test base case empty database responses for each statistic endpoint. +#################################################################################################### +# Test empty database statistics +#################################################################################################### -def test_empty_database_statistics(client): - stats_endpoints = ( +@pytest.mark.parametrize( + "stats_endpoint", + ( "target/accession/accession", "target/accession/assembly", "target/accession/gene", @@ -77,14 +80,19 @@ def test_empty_database_statistics(client): "record/score-set/doi-identifiers", "record/score-set/raw-read-identifiers", "record/score-set/created-by", - ) - for endpoint in stats_endpoints: - response = client.get(f"/api/v1/statistics/{endpoint}") - assert response.status_code == 200, f"Non-200 status code for endpoint {endpoint}." - assert response.json() == {}, f"Non-empty response for endpoint {endpoint}." + ), +) +def test_empty_database_statistics(client, stats_endpoint): + response = client.get(f"/api/v1/statistics/{stats_endpoint}") + assert response.status_code == 200, f"Non-200 status code for endpoint {stats_endpoint}." + assert response.json() == {}, f"Non-empty response for endpoint {stats_endpoint}." +#################################################################################################### # Test target accession statistics +#################################################################################################### + + @pytest.mark.parametrize( "field_value", TARGET_ACCESSION_FIELDS, @@ -100,19 +108,20 @@ def test_target_accession_statistics(client, field_value, setup_acc_scoreset): def test_target_accession_invalid_field(client): """Test target accession statistic response for an invalid target accession field.""" response = client.get("/api/v1/statistics/target/accession/invalid-field") - assert response.status_code == 422 - assert response.json()["detail"][0]["loc"] == ["path", "field"] - assert response.json()["detail"][0]["ctx"]["enum_values"] == TARGET_ACCESSION_FIELDS + assert response.status_code == 404 def test_target_accession_empty_field(client): """Test target accession statistic response for an empty field.""" response = client.get("/api/v1/statistics/target/accession/") assert response.status_code == 404 - assert response.json()["detail"] == "Not Found" +#################################################################################################### # Test target sequence statistics +#################################################################################################### + + @pytest.mark.parametrize( "field_value", TARGET_SEQUENCE_FIELDS, @@ -128,19 +137,18 @@ def test_target_sequence_statistics(client, field_value, setup_seq_scoreset): def test_target_sequence_invalid_field(client): """Test target sequence statistic response for an invalid field.""" response = client.get("/api/v1/statistics/target/sequence/invalid-field") - assert response.status_code == 422 - assert response.json()["detail"][0]["loc"] == ["path", "field"] - assert response.json()["detail"][0]["ctx"]["enum_values"] == TARGET_SEQUENCE_FIELDS + assert response.status_code == 404 def test_target_sequence_empty_field(client): """Test target sequence statistic response for an empty field.""" response = client.get("/api/v1/statistics/target/sequence/") assert response.status_code == 404 - assert response.json()["detail"] == "Not Found" -# Test target gene statistics. +#################################################################################################### +# Test target gene statistics +#################################################################################################### # Desired values live in different spots for fields on target genes because of the differing target sequence @@ -213,19 +221,20 @@ def test_target_gene_identifier_statistiscs( def test_target_gene_invalid_field(client): """Test target gene statistic response for an invalid field.""" response = client.get("/api/v1/statistics/target/gene/invalid-field") - assert response.status_code == 422 - assert response.json()["detail"][0]["loc"] == ["path", "field"] - assert response.json()["detail"][0]["ctx"]["enum_values"] == TARGET_GENE_FIELDS + TARGET_GENE_IDENTIFIER_FIELDS + assert response.status_code == 404 def test_target_gene_empty_field(client): """Test target gene statistic response for an empty field.""" response = client.get("/api/v1/statistics/target/gene/") assert response.status_code == 404 - assert response.json()["detail"] == "Not Found" -# Test Experiment and Score Set statistics +#################################################################################################### +# Test record statistics +#################################################################################################### + + @pytest.mark.parametrize("model_value", RECORD_MODELS) @pytest.mark.parametrize( "mock_publication_fetch", @@ -340,13 +349,20 @@ def test_record_raw_read_identifier_statistics( assert response.json() == {} +@pytest.mark.parametrize("field_value", RECORD_SHARED_FIELDS) +def test_record_statistics_invalid_record(client, field_value): + """Test record model statistic response for a record we don't provide statisticss on.""" + response = client.get(f"/api/v1/statistics/record/invalid-record/{field_value}") + assert response.status_code == 422 + assert response.json()["detail"][0]["loc"] == ["path", "record"] + assert response.json()["detail"][0]["ctx"]["enum_values"] == RECORD_MODELS + + @pytest.mark.parametrize("model_value", RECORD_MODELS) def test_record_statistics_invalid_field(client, model_value): - """Test record model statistic response for an invalid field.""" + """Test record model statistic response for a field we don't provide statisticss on.""" response = client.get(f"/api/v1/statistics/record/{model_value}/invalid-field") - assert response.status_code == 422 - assert response.json()["detail"][0]["loc"] == ["path", "field"] - assert response.json()["detail"][0]["ctx"]["enum_values"] == RECORD_SHARED_FIELDS + assert response.status_code == 404 @pytest.mark.parametrize("model_value", RECORD_MODELS) @@ -360,16 +376,9 @@ def test_record_statistics_empty_field(client, model_value): def test_record_statistics_invalid_record_and_field(client): """Test record model statistic response for an invalid model and field.""" response = client.get("/api/v1/statistics/record/invalid-model/invalid-field") - - # The order of this list should be reliable. - assert response.status_code == 422 - assert response.json()["detail"][0]["loc"] == ["path", "model"] - assert response.json()["detail"][0]["ctx"]["enum_values"] == RECORD_MODELS - assert response.json()["detail"][1]["loc"] == ["path", "field"] - assert response.json()["detail"][1]["ctx"]["enum_values"] == RECORD_SHARED_FIELDS + assert response.status_code == 404 -# Test record counts statistics @pytest.mark.parametrize("model_value", RECORD_MODELS) def test_record_counts_no_published_data(client, model_value, setup_router_db): """Test record counts endpoint for published experiments and score sets.""" From e407383b617969684c2790aacc142e7eb43c5181 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Wed, 5 Mar 2025 17:49:44 -0800 Subject: [PATCH 06/20] Script for populating mapped gene targets via ClinGen For historical data, we do not always have the genes that we mapped a target to. This script can be used to infer the mapped gene from the HGVS string of a mapped variant. --- .../mapped_gene_from_mapped_variant.py | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/mavedb/scripts/mapped_gene_from_mapped_variant.py diff --git a/src/mavedb/scripts/mapped_gene_from_mapped_variant.py b/src/mavedb/scripts/mapped_gene_from_mapped_variant.py new file mode 100644 index 00000000..f1cb641b --- /dev/null +++ b/src/mavedb/scripts/mapped_gene_from_mapped_variant.py @@ -0,0 +1,126 @@ +import json +import logging +import requests +from typing import Sequence, Optional + +import click +from sqlalchemy import select +from sqlalchemy.orm import Session + +from mavedb.models.score_set import ScoreSet +from mavedb.models.mapped_variant import MappedVariant +from mavedb.models.target_gene import TargetGene +from mavedb.models.variant import Variant + +from mavedb.scripts.environment import script_environment, with_database_session + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +CLINGEN_API_URL = "https://reg.test.genome.network/allele" + + +def get_gene_symbol_from_clingen(hgvs_string: str) -> Optional[str]: + response = requests.get(f"{CLINGEN_API_URL}?hgvs={hgvs_string}") + if response.status_code != 200: + logger.error(f"Failed to query ClinGen API for {hgvs_string}: {response.status_code}") + return None + + data = response.json() + if "aminoAcidAlleles" in data: + return data["aminoAcidAlleles"][0].get("geneSymbol") + elif "transcriptAlleles" in data: + return data["transcriptAlleles"][0].get("geneSymbol") + + return None + + +@script_environment.command() +@with_database_session +@click.argument("urns", nargs=-1) +@click.option("--all", help="Generate gene mappings for every score set in MaveDB.", is_flag=True) +def generate_gene_mappings(db: Session, urns: Sequence[Optional[str]], all: bool): + score_set_ids: Sequence[Optional[int]] + if all: + score_set_ids = db.scalars(select(ScoreSet.id)).all() + logger.info( + f"Command invoked with --all. Routine will generate gene mappings for {len(score_set_ids)} score sets." + ) + else: + score_set_ids = db.scalars(select(ScoreSet.id).where(ScoreSet.urn.in_(urns))).all() + logger.info(f"Generating gene mappings for the provided score sets ({len(score_set_ids)}).") + + for ss_id in score_set_ids: + if not ss_id: + continue + + score_set = db.scalar(select(ScoreSet).where(ScoreSet.id == ss_id)) + if not score_set: + logger.warning(f"Could not fetch score set with id={ss_id}.") + continue + + try: + mapped_variant = db.scalars( + select(MappedVariant) + .join(Variant) + .where( + Variant.score_set_id == ss_id, + MappedVariant.current.is_(True), + MappedVariant.post_mapped.isnot(None), + ) + .limit(1) + ).one_or_none() + + if not mapped_variant: + logger.info(f"No current mapped variant found for score set {score_set.urn}.") + continue + + # From line 69, this object must not be None. + hgvs_string = mapped_variant.post_mapped.get("expressions", {})[0].get("value") # type: ignore + if not hgvs_string: + logger.warning(f"No HGVS string found in post_mapped for variant {mapped_variant.id}.") + continue + + gene_symbol = get_gene_symbol_from_clingen(hgvs_string) + if not gene_symbol: + logger.warning(f"No gene symbol found for HGVS string {hgvs_string}.") + continue + + # This script has been designed to work prior to the introduction of multi-target mapping. + # This .one() call reflects those assumptions. + target_gene = db.scalars(select(TargetGene).where(TargetGene.score_set_id == ss_id)).one() + + if target_gene.post_mapped_metadata is None: + logger.warning( + f"Target gene for score set {score_set.urn} has no post_mapped_metadata despite containing current mapped variants." + ) + continue + + # Cannot update JSONB fields directly. They can be converted to dictionaries over Mypy's objections. + post_mapped_metadata = json.loads(json.dumps(dict(target_gene.post_mapped_metadata.copy()))) # type: ignore + if "genomic" in post_mapped_metadata: + key = "genomic" + elif "protein" in post_mapped_metadata: + key = "protein" + else: + logger.warning(f"Unknown post_mapped type for variant {mapped_variant.id}.") + + if "sequence_genes" not in post_mapped_metadata[key]: + post_mapped_metadata[key]["sequence_genes"] = [] + post_mapped_metadata[key]["sequence_genes"].append(gene_symbol) + + target_gene.post_mapped_metadata = post_mapped_metadata + + db.add(target_gene) + db.commit() + logger.info(f"Gene symbol {gene_symbol} added to target gene for score set {score_set.urn}.") + + except Exception as e: + logger.error(f"Failed to generate gene mappings for score set {score_set.urn}: {str(e)}") + db.rollback() + + logger.info("Done generating gene mappings.") + + +if __name__ == "__main__": + generate_gene_mappings() From 9acd2abfbb05e04be39bf9d03d6e1247b37ed668 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Wed, 5 Mar 2025 17:50:52 -0800 Subject: [PATCH 07/20] Statistics count endpoints for variants, mapped variants, and mapped gene targets --- src/mavedb/routers/statistics.py | 86 ++++++++++++++++++++- tests/routers/test_statistics.py | 124 +++++++++++++++++++++++++------ 2 files changed, 184 insertions(+), 26 deletions(-) diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index 137d97f2..bb4b9ea6 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -1,5 +1,5 @@ import itertools -from collections import OrderedDict +from collections import OrderedDict, Counter from enum import Enum from typing import Any, Union, Optional @@ -19,6 +19,7 @@ ) from mavedb.models.experiment_controlled_keyword import ExperimentControlledKeywordAssociation from mavedb.models.experiment_publication_identifier import ExperimentPublicationIdentifierAssociation +from mavedb.models.mapped_variant import MappedVariant from mavedb.models.publication_identifier import PublicationIdentifier from mavedb.models.raw_read_identifier import RawReadIdentifier from mavedb.models.refseq_identifier import RefseqIdentifier @@ -36,6 +37,7 @@ from mavedb.models.uniprot_identifier import UniprotIdentifier from mavedb.models.uniprot_offset import UniprotOffset from mavedb.models.user import User +from mavedb.models.variant import Variant router = APIRouter( prefix="/api/v1/statistics", @@ -271,7 +273,7 @@ def record_counts(model: RecordNames, group: Optional[GroupBy] = None, db: Sessi elif group == GroupBy.year: grouped = {k: len(list(g)) for k, g in itertools.groupby(objs, lambda t: t.strftime("%Y"))} # type: ignore else: - grouped = {"all": len(objs)} + grouped = {"count": len(objs)} return OrderedDict(sorted(grouped.items())) @@ -444,3 +446,83 @@ def target_genes_uniprot_identifier_counts(db: Session = Depends(get_db)) -> dic ).group_by(UniprotIdentifier.identifier) return _count_for_identifier_in_query(db, query) + + +# TODO: Test coverage for this route. +@router.get("/target/mapped/gene") +def mapped_target_gene_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the distinct values of the `gene` property within the `post_mapped_metadata` + field (member of the `target_gene` table). Don't include any NULL field values. Don't include any targets from + unpublished score sets. + """ + query = _join_model_and_filter_unpublished( + select(TargetGene.post_mapped_metadata), + ScoreSet, + ).where(TargetGene.post_mapped_metadata.isnot(None)) + + mapping_metadata = db.scalars(query).all() + gene_counts = Counter( + gene + for metadata in mapping_metadata + for key in ("genomic", "protein") + if key in metadata + for gene in metadata[key].get("sequence_genes", []) + ) + + # The gene will always be a string + return dict(gene_counts) # type: ignore + + +######################################################################################## +# Variant (and mapped variant) statistics +######################################################################################## + + +@router.get("/variant/count", status_code=200, response_model=dict[str, int]) +def variant_counts(group: Optional[GroupBy] = None, db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the number of published and distinct variants in the database. + Optionally, group the counts by the day on which the score set (and by extension, the variant) was published. + """ + query = _join_model_and_filter_unpublished(select(ScoreSet.published_date, func.count(Variant.id)), ScoreSet) + + variants = db.execute(query.group_by(ScoreSet.published_date).order_by(ScoreSet.published_date)).all() + if group == GroupBy.month: + grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y-%m"))} + elif group == GroupBy.year: + grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y"))} + else: + grouped = {"count": sum(count for _, count in variants)} + + return OrderedDict(sorted(grouped.items())) + + +@router.get("/mapped-variant/count", status_code=200, response_model=dict[str, int]) +def mapped_variant_counts( + group: Optional[GroupBy] = None, onlyCurrent: bool = True, db: Session = Depends(get_db) +) -> dict[str, int]: + """ + Returns a dictionary of counts for the number of published and distinct variants in the database. + Optionally, group the counts by the day on which the score set (and by extension, the variant) was published. + Optionally, return the count of all mapped variants, not just the current/most up to date ones. + """ + query = _join_model_and_filter_unpublished( + select(ScoreSet.published_date, func.count(MappedVariant.id)).join( + Variant, Variant.id == MappedVariant.variant_id + ), + ScoreSet, + ) + + if onlyCurrent: + query = query.where(MappedVariant.current.is_(True)) + + variants = db.execute(query.group_by(ScoreSet.published_date).order_by(ScoreSet.published_date)).all() + if group == GroupBy.month: + grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y-%m"))} + elif group == GroupBy.year: + grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y"))} + else: + grouped = {"count": sum(count for _, count in variants)} + + return OrderedDict(sorted(grouped.items())) diff --git a/tests/routers/test_statistics.py b/tests/routers/test_statistics.py index 7196196d..e39987e4 100644 --- a/tests/routers/test_statistics.py +++ b/tests/routers/test_statistics.py @@ -53,6 +53,14 @@ def assert_statistic(desired_field_value, response): ), f"Target accession statistic {desired_field_value} should appear on one (and only one) test score set." +def add_query_param(url, query_name, query_value): + """Add a group value to the URL if one is provided.""" + if query_name and query_value: + return f"{url}?{query_name}={query_value}" + + return url + + #################################################################################################### # Test empty database statistics #################################################################################################### @@ -380,42 +388,29 @@ def test_record_statistics_invalid_record_and_field(client): @pytest.mark.parametrize("model_value", RECORD_MODELS) -def test_record_counts_no_published_data(client, model_value, setup_router_db): - """Test record counts endpoint for published experiments and score sets.""" - response = client.get(f"/api/v1/statistics/record/{model_value}/published/count") - assert response.status_code == 200 - assert "all" in response.json() - assert response.json()["all"] == 0 - - -@pytest.mark.parametrize("model_value", RECORD_MODELS) -def test_record_counts(client, model_value, setup_router_db, setup_seq_scoreset): - """Test record counts endpoint for published experiments and score sets.""" - response = client.get(f"/api/v1/statistics/record/{model_value}/published/count") - assert response.status_code == 200 - assert "all" in response.json() - assert response.json()["all"] == 1 - - -@pytest.mark.parametrize("model_value", RECORD_MODELS) -@pytest.mark.parametrize("group_value", ["month", "year"]) -def test_record_counts_grouped_no_published_data(client, model_value, group_value, setup_router_db): +@pytest.mark.parametrize("group_value", ["month", "year", None]) +def test_record_counts_no_published_data(client, model_value, group_value, setup_router_db): """Test record counts endpoint grouped by month and year for published experiments and score sets.""" - response = client.get(f"/api/v1/statistics/record/{model_value}/published/count?group={group_value}") + response = client.get( + add_query_param(f"/api/v1/statistics/record/{model_value}/published/count", "group", group_value) + ) + assert response.status_code == 200 assert isinstance(response.json(), dict) for key, value in response.json().items(): assert isinstance(key, str) - assert isinstance(value, int) + assert value == 0 @pytest.mark.parametrize("model_value", RECORD_MODELS) -@pytest.mark.parametrize("group_value", ["month", "year"]) +@pytest.mark.parametrize("group_value", ["month", "year", None]) def test_record_counts_grouped( session, client, model_value, group_value, setup_router_db, setup_seq_scoreset, setup_acc_scoreset ): """Test record counts endpoint grouped by month and year for published experiments and score sets.""" - response = client.get(f"/api/v1/statistics/record/{model_value}/published/count?group={group_value}") + response = client.get( + add_query_param(f"/api/v1/statistics/record/{model_value}/published/count", "group", group_value) + ) assert response.status_code == 200 assert isinstance(response.json(), dict) for key, value in response.json().items(): @@ -437,3 +432,84 @@ def test_record_counts_invalid_group(client): assert response.status_code == 422 assert response.json()["detail"][0]["loc"] == ["query", "group"] assert response.json()["detail"][0]["ctx"]["enum_values"] == ["month", "year"] + + +#################################################################################################### +# Test variant statistics +#################################################################################################### + + +@pytest.mark.parametrize("group_value", ["month", "year", None]) +def test_variant_counts(client, group_value, setup_router_db, setup_seq_scoreset): + """Test variant counts endpoint for published variants.""" + response = client.get(add_query_param("/api/v1/statistics/variant/count", "group", group_value)) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert value == 3 + + +@pytest.mark.parametrize("group_value", ["month", "year", None]) +def test_variant_counts_no_published_data(client, group_value, setup_router_db): + """Test variant counts endpoint with no published variants.""" + response = client.get(add_query_param("/api/v1/statistics/variant/count", "group", group_value)) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert value == 0 + + +@pytest.mark.parametrize("group_value", ["month", "year", None]) +def test_mapped_variant_counts_groups(client, group_value, setup_router_db, setup_seq_scoreset): + """Test variant counts endpoint for published variants.""" + url_with_group = add_query_param("/api/v1/statistics/mapped-variant/count", "group", group_value) + response = client.get(url_with_group) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert isinstance(value, int) + + +@pytest.mark.parametrize("group_value", ["month", "year", None]) +def test_mapped_variant_counts_groups_no_published_data(client, group_value, setup_router_db): + """Test variant counts endpoint with no published variants.""" + url_with_group = add_query_param("/api/v1/statistics/mapped-variant/count", "group", group_value) + response = client.get(url_with_group) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert value == 0 + + +@pytest.mark.parametrize("current_value", [True, False]) +def test_mapped_variant_counts_current(client, current_value, setup_router_db, setup_seq_scoreset): + """Test variant counts endpoint for published variants.""" + url_with_current = add_query_param("/api/v1/statistics/mapped-variant/count", "current", current_value) + response = client.get(url_with_current) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert isinstance(value, int) + + +@pytest.mark.parametrize("current_value", [True, False]) +def test_mapped_variant_counts_current_no_published_data(client, current_value, setup_router_db): + """Test variant counts endpoint with no published variants.""" + url_with_current = add_query_param("/api/v1/statistics/mapped-variant/count", "current", current_value) + response = client.get(url_with_current) + assert response.status_code == 200 + assert isinstance(response.json(), dict) + + for key, value in response.json().items(): + assert isinstance(key, str) + assert value == 0 From c6a53bab684a10cc0fafb7d599593fd33097b5be Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Thu, 6 Mar 2025 11:08:25 -0800 Subject: [PATCH 08/20] Test utility for inserting mapped variants to DB --- tests/helpers/constants.py | 25 +++++++++++++++++++++++++ tests/helpers/util.py | 26 ++++++++++++++++++++++++++ tests/routers/conftest.py | 2 ++ 3 files changed, 53 insertions(+) diff --git a/tests/helpers/constants.py b/tests/helpers/constants.py index a0aeb42e..03abc856 100644 --- a/tests/helpers/constants.py +++ b/tests/helpers/constants.py @@ -637,6 +637,20 @@ } +TEST_MINIMAL_PRE_MAPPED_METADATA = { + "genomic": {"sequence_id": "ga4gh:SQ.em9khDCUYXrVWBfWr9r8fjBUrTjj1aig", "sequence_type": "dna"} +} + + +TEST_MINIMAL_POST_MAPPED_METADATA = { + "genomic": { + "sequence_id": "ga4gh:SQ.em9khDCUYXrVWBfWr9r8fjBUrTjj1aig", + "sequence_type": "dna", + "sequence_accessions": [VALID_ACCESSION], + "sequence_genes": [VALID_GENE], + } +} + TEST_VARIANT_MAPPING_SCAFFOLD = { "metadata": {}, "computed_genomic_reference_sequence": { @@ -656,6 +670,17 @@ } +TEST_MINIMAL_MAPPED_VARIANT = { + "pre_mapped": {}, + "post_mapped": {}, + "modification_date": datetime.isoformat(datetime.now()), + "mapped_date": datetime.isoformat(datetime.now()), + "current": True, + "vrs_version": "2.0", + "mapping_api_version": "pytest.0.0", +} + + TEST_SCORESET_RANGE = { "wt_score": 1.0, "ranges": [ diff --git a/tests/helpers/util.py b/tests/helpers/util.py index f4df4586..0cbfe4c9 100644 --- a/tests/helpers/util.py +++ b/tests/helpers/util.py @@ -11,9 +11,13 @@ from mavedb.lib.validation.dataframe import validate_and_standardize_dataframe_pair from mavedb.models.contributor import Contributor from mavedb.models.enums.processing_state import ProcessingState +from mavedb.models.enums.mapping_state import MappingState +from mavedb.models.mapped_variant import MappedVariant from mavedb.models.score_set import ScoreSet as ScoreSetDbModel from mavedb.models.license import License +from mavedb.models.target_gene import TargetGene from mavedb.models.user import User +from mavedb.models.variant import Variant from mavedb.view_models.collection import Collection from mavedb.view_models.experiment import Experiment, ExperimentCreate from mavedb.view_models.score_set import ScoreSet, ScoreSetCreate @@ -23,7 +27,10 @@ TEST_COLLECTION, TEST_MINIMAL_ACC_SCORESET, TEST_MINIMAL_EXPERIMENT, + TEST_MINIMAL_PRE_MAPPED_METADATA, + TEST_MINIMAL_POST_MAPPED_METADATA, TEST_MINIMAL_SEQ_SCORESET, + TEST_MINIMAL_MAPPED_VARIANT, ) @@ -185,6 +192,25 @@ def mock_worker_variant_insertion(client, db, data_provider, score_set, scores_c return client.get(f"/api/v1/score-sets/{score_set['urn']}").json() +def create_mapped_variants_for_score_set(db, score_set_urn): + score_set = db.scalar(select(ScoreSetDbModel).where(ScoreSetDbModel.urn == score_set_urn)) + targets = db.scalars(select(TargetGene).where(TargetGene.score_set_id == score_set.id)) + variants = db.scalars(select(Variant).where(Variant.score_set_id == score_set.id)).all() + + for variant in variants: + mv = MappedVariant(**TEST_MINIMAL_MAPPED_VARIANT, variant_id=variant.id) + db.add(mv) + + for target in targets: + target.pre_mapped_metadata = TEST_MINIMAL_PRE_MAPPED_METADATA + target.post_mapped_metadata = TEST_MINIMAL_POST_MAPPED_METADATA + db.add(target) + + score_set.mapping_state = MappingState.complete + db.commit() + return + + def create_seq_score_set_with_variants( client, db, data_provider, experiment_urn, scores_csv_path, update=None, counts_csv_path=None ): diff --git a/tests/routers/conftest.py b/tests/routers/conftest.py index f16ff93b..d5a69cd9 100644 --- a/tests/routers/conftest.py +++ b/tests/routers/conftest.py @@ -28,6 +28,7 @@ create_acc_score_set_with_variants, create_experiment, create_seq_score_set_with_variants, + create_mapped_variants_for_score_set, publish_score_set, ) @@ -76,6 +77,7 @@ def setup_seq_scoreset(setup_router_db, session, data_provider, client, data_fil score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) + create_mapped_variants_for_score_set(session, score_set["urn"]) publish_score_set(client, score_set["urn"]) From 9aedb21b3e230b4e22a666eff10e96b89df435fb Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Thu, 6 Mar 2025 11:08:49 -0800 Subject: [PATCH 09/20] Add test for statistics mapped target gene counts --- src/mavedb/routers/statistics.py | 1 - tests/routers/test_statistics.py | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index bb4b9ea6..a1308a25 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -448,7 +448,6 @@ def target_genes_uniprot_identifier_counts(db: Session = Depends(get_db)) -> dic return _count_for_identifier_in_query(db, query) -# TODO: Test coverage for this route. @router.get("/target/mapped/gene") def mapped_target_gene_counts(db: Session = Depends(get_db)) -> dict[str, int]: """ diff --git a/tests/routers/test_statistics.py b/tests/routers/test_statistics.py index e39987e4..279147e6 100644 --- a/tests/routers/test_statistics.py +++ b/tests/routers/test_statistics.py @@ -12,6 +12,7 @@ TEST_MINIMAL_ACC_SCORESET, TEST_MINIMAL_SEQ_SCORESET, TEST_PUBMED_IDENTIFIER, + VALID_GENE, ) from tests.helpers.util import ( create_acc_score_set_with_variants, @@ -238,6 +239,20 @@ def test_target_gene_empty_field(client): assert response.status_code == 404 +#################################################################################################### +# Test mapped target gene statistics +#################################################################################################### + + +def test_mapped_target_gene_counts(client, setup_router_db, setup_seq_scoreset): + """Test mapped target gene counts endpoint for published score sets.""" + response = client.get("/api/v1/statistics/target/mapped/gene") + assert response.status_code == 200 + assert isinstance(response.json(), dict) + assert len(response.json().keys()) == 1 + assert response.json()[VALID_GENE] == 1 + + #################################################################################################### # Test record statistics #################################################################################################### @@ -473,7 +488,7 @@ def test_mapped_variant_counts_groups(client, group_value, setup_router_db, setu for key, value in response.json().items(): assert isinstance(key, str) - assert isinstance(value, int) + assert value == 3 @pytest.mark.parametrize("group_value", ["month", "year", None]) @@ -499,7 +514,7 @@ def test_mapped_variant_counts_current(client, current_value, setup_router_db, s for key, value in response.json().items(): assert isinstance(key, str) - assert isinstance(value, int) + assert value == 3 @pytest.mark.parametrize("current_value", [True, False]) From 9ad50d80bc07dc135d8a5068388e12f0a8883a12 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Thu, 6 Mar 2025 17:13:24 -0800 Subject: [PATCH 10/20] Fixes #358: Literal 'null' inserted for NULL score ranges. --- src/mavedb/routers/score_sets.py | 21 ++++---- tests/lib/test_score_set.py | 22 ++++++++ tests/routers/test_score_set.py | 93 +++++++++++++++++++++++++------- 3 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/mavedb/routers/score_sets.py b/src/mavedb/routers/score_sets.py index be990f35..748cef62 100644 --- a/src/mavedb/routers/score_sets.py +++ b/src/mavedb/routers/score_sets.py @@ -9,7 +9,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.exceptions import HTTPException from fastapi.responses import StreamingResponse -from sqlalchemy import or_, select +from sqlalchemy import null, or_, select from sqlalchemy.exc import MultipleResultsFound, NoResultFound from sqlalchemy.orm import Session @@ -312,10 +312,10 @@ def get_score_set_mapped_variants( mapped_variants = ( db.query(MappedVariant) - .filter(ScoreSet.urn == urn) - .filter(ScoreSet.id == Variant.score_set_id) - .filter(Variant.id == MappedVariant.variant_id) - .all() + .filter(ScoreSet.urn == urn) + .filter(ScoreSet.id == Variant.score_set_id) + .filter(Variant.id == MappedVariant.variant_id) + .all() ) if not mapped_variants: @@ -482,10 +482,9 @@ async def create_score_set( for identifier in item_create.primary_publication_identifiers or [] ] publication_identifiers = [ - await find_or_create_publication_identifier(db, identifier.identifier, - identifier.db_name) - for identifier in item_create.secondary_publication_identifiers or [] - ] + primary_publication_identifiers + await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name) + for identifier in item_create.secondary_publication_identifiers or [] + ] + primary_publication_identifiers # create a temporary `primary` attribute on each of our publications that indicates # to our association proxy whether it is a primary publication or not @@ -595,6 +594,7 @@ async def create_score_set( "secondary_publication_identifiers", "superseded_score_set_urn", "target_genes", + "score_ranges", }, ), experiment=experiment, @@ -608,6 +608,7 @@ async def create_score_set( processing_state=ProcessingState.incomplete, created_by=user_data.user, modified_by=user_data.user, + score_ranges=item_create.score_ranges.dict() if item_create.score_ranges else null(), ) # type: ignore db.add(item) @@ -809,7 +810,7 @@ async def update_score_set( if item_update.score_ranges: item.score_ranges = item_update.score_ranges.dict() else: - item.score_ranges = None + item.score_ranges = null() # Delete the old target gene, WT sequence, and reference map. These will be deleted when we set the score set's # target_gene to None, because we have set cascade='all,delete-orphan' on ScoreSet.target_gene. (Since the diff --git a/tests/lib/test_score_set.py b/tests/lib/test_score_set.py index c4a98b6a..d95ad6f1 100644 --- a/tests/lib/test_score_set.py +++ b/tests/lib/test_score_set.py @@ -21,6 +21,7 @@ ) from mavedb.models.score_set import ScoreSet from mavedb.models.variant import Variant +from tests.helpers.constants import TEST_SAVED_SCORESET_RANGE from tests.helpers.util import create_acc_score_set, create_experiment, create_seq_score_set @@ -307,3 +308,24 @@ def test_create_variants_acc_score_set(setup_lib_db, client, session): assert db_variant.urn.split("#")[0] == score_set.urn session.commit() + + +def test_create_null_score_range(setup_lib_db, client, session): + experiment = create_experiment(client) + create_seq_score_set(client, experiment["urn"]) + score_set = session.scalar(select(ScoreSet).where(ScoreSet.score_ranges.is_(None))) + + assert score_set is not None + + +def test_update_null_score_range(setup_lib_db, client, session): + experiment = create_experiment(client) + score_set = create_seq_score_set(client, experiment["urn"], update={"scoreRanges": TEST_SAVED_SCORESET_RANGE}) + db_score_set = session.scalar(select(ScoreSet).where(ScoreSet.score_ranges.is_(None))) + assert db_score_set is None + + score_set.pop("scoreRanges") + score_set = client.put(f"/api/v1/score-sets/{score_set['urn']}", json=score_set) + db_score_set = session.scalar(select(ScoreSet).where(ScoreSet.score_ranges.is_(None))) + + assert db_score_set is not None diff --git a/tests/routers/test_score_set.py b/tests/routers/test_score_set.py index 8a38952e..95a768b6 100644 --- a/tests/routers/test_score_set.py +++ b/tests/routers/test_score_set.py @@ -155,6 +155,39 @@ def test_create_score_set_with_score_range(client, setup_router_db): assert response.status_code == 200 +def test_remove_score_range_from_score_set(client, setup_router_db): + experiment = create_experiment(client) + score_set = deepcopy(TEST_MINIMAL_SEQ_SCORESET) + score_set["experimentUrn"] = experiment["urn"] + score_set.update({"score_ranges": TEST_SCORESET_RANGE}) + + response = client.post("/api/v1/score-sets/", json=score_set) + assert response.status_code == 200 + response_data = response.json() + + jsonschema.validate(instance=response_data, schema=ScoreSet.schema()) + assert isinstance(MAVEDB_TMP_URN_RE.fullmatch(response_data["urn"]), re.Match) + + expected_response = update_expected_response_for_created_resources( + deepcopy(TEST_MINIMAL_SEQ_SCORESET_RESPONSE), experiment, response_data + ) + expected_response["scoreRanges"] = TEST_SAVED_SCORESET_RANGE + + assert sorted(expected_response.keys()) == sorted(response_data.keys()) + for key in expected_response: + assert (key, expected_response[key]) == (key, response_data[key]) + + score_set.pop("score_ranges") + response = client.put(f"/api/v1/score-sets/{response_data['urn']}", json=score_set) + assert response.status_code == 200 + response_data = response.json() + + jsonschema.validate(instance=response_data, schema=ScoreSet.schema()) + assert isinstance(MAVEDB_TMP_URN_RE.fullmatch(response_data["urn"]), re.Match) + + assert "scoreRanges" not in response_data.keys() + + def test_cannot_create_score_set_without_email(client, setup_router_db): experiment = create_experiment(client) score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) @@ -1284,7 +1317,7 @@ def test_cannot_add_score_set_to_meta_analysis_experiment(session, data_provider meta_score_set_1 = (client.post(f"/api/v1/score-sets/{meta_score_set_1['urn']}/publish")).json() assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set_1["urn"]), re.Match) score_set_2 = deepcopy(TEST_MINIMAL_SEQ_SCORESET) - score_set_2["experimentUrn"] = meta_score_set_1['experiment']['urn'] + score_set_2["experimentUrn"] = meta_score_set_1["experiment"]["urn"] jsonschema.validate(instance=score_set_2, schema=ScoreSetCreate.schema()) response = client.post("/api/v1/score-sets/", json=score_set_2) @@ -1293,7 +1326,9 @@ def test_cannot_add_score_set_to_meta_analysis_experiment(session, data_provider assert "Score sets may not be added to a meta-analysis experiment." in response_data["detail"] -def test_create_single_score_set_meta_analysis_to_others_score_set(session, data_provider, client, setup_router_db, data_files): +def test_create_single_score_set_meta_analysis_to_others_score_set( + session, data_provider, client, setup_router_db, data_files +): experiment = create_experiment(client) score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" @@ -1380,6 +1415,7 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets_with_differen assert meta_score_set["urn"] == "urn:mavedb:00000003-0-1" assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) + ######################################################################################################################## # Score set search ######################################################################################################################## @@ -1494,7 +1530,9 @@ def test_search_others_private_score_sets_urn_match(session, data_provider, clie # There is space in the end of test urn. The search result returned nothing before. -def test_search_others_private_score_sets_urn_with_space_match(session, data_provider, client, setup_router_db, data_files): +def test_search_others_private_score_sets_urn_with_space_match( + session, data_provider, client, setup_router_db, data_files +): experiment_1 = create_experiment(client) score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" @@ -1552,7 +1590,7 @@ def test_search_public_score_sets_urn_with_space_match(session, data_provider, c client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - published_score_set = score_set_response.json() + published_score_set = score_set_response.json() assert score_set_response.status_code == 200 urn_with_space = published_score_set["urn"] + " " search_payload = {"urn": urn_with_space} @@ -1620,7 +1658,9 @@ def test_search_others_public_score_sets_urn_match(session, data_provider, clien assert response.json()[0]["urn"] == publish_score_set["urn"] -def test_search_others_public_score_sets_urn_with_space_match(session, data_provider, client, setup_router_db, data_files): +def test_search_others_public_score_sets_urn_with_space_match( + session, data_provider, client, setup_router_db, data_files +): experiment_1 = create_experiment(client) score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" @@ -1637,7 +1677,9 @@ def test_search_others_public_score_sets_urn_with_space_match(session, data_prov assert response.json()[0]["urn"] == published_score_set["urn"] -def test_search_private_score_sets_not_showing_public_score_set(session, data_provider, client, setup_router_db, data_files): +def test_search_private_score_sets_not_showing_public_score_set( + session, data_provider, client, setup_router_db, data_files +): experiment_1 = create_experiment(client) score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" @@ -1654,14 +1696,14 @@ def test_search_private_score_sets_not_showing_public_score_set(session, data_pr assert response.json()[0]["urn"] == score_set_1_2["urn"] -def test_search_public_score_sets_not_showing_private_score_set(session, data_provider, client, setup_router_db, data_files): +def test_search_public_score_sets_not_showing_private_score_set( + session, data_provider, client, setup_router_db, data_files +): experiment_1 = create_experiment(client) score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) - create_seq_score_set_with_variants( - client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" - ) + create_seq_score_set_with_variants(client, session, data_provider, experiment_1["urn"], data_files / "scores.csv") score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") assert score_set_response.status_code == 200 published_score_set = score_set_response.json() @@ -1672,7 +1714,6 @@ def test_search_public_score_sets_not_showing_private_score_set(session, data_pr assert response.json()[0]["urn"] == published_score_set["urn"] - ######################################################################################################################## # Score set deletion ######################################################################################################################## @@ -1913,6 +1954,7 @@ def test_can_modify_metadata_for_score_set_with_inactive_license(session, client # Supersede score set ######################################################################################################################## + def test_create_superseding_score_set(session, data_provider, client, setup_router_db, data_files): experiment = create_experiment(client) score_set = create_seq_score_set_with_variants( @@ -1927,6 +1969,7 @@ def test_create_superseding_score_set(session, data_provider, client, setup_rout superseding_score_set_response = client.post("/api/v1/score-sets/", json=score_set_post_payload) assert superseding_score_set_response.status_code == 200 + def test_can_view_unpublished_superseding_score_set(session, data_provider, client, setup_router_db, data_files): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( @@ -1947,7 +1990,10 @@ def test_can_view_unpublished_superseding_score_set(session, data_provider, clie assert score_set["urn"] == superseding_score_set["supersededScoreSet"]["urn"] assert score_set["supersedingScoreSet"]["urn"] == superseding_score_set["urn"] -def test_cannot_view_others_unpublished_superseding_score_set(session, data_provider, client, setup_router_db, data_files): + +def test_cannot_view_others_unpublished_superseding_score_set( + session, data_provider, client, setup_router_db, data_files +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" @@ -1969,6 +2015,7 @@ def test_cannot_view_others_unpublished_superseding_score_set(session, data_prov # Other users can't view the unpublished superseding score set. assert "supersedingScoreSet" not in score_set + def test_can_view_others_published_superseding_score_set(session, data_provider, client, setup_router_db, data_files): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( @@ -2001,7 +2048,9 @@ def test_can_view_others_published_superseding_score_set(session, data_provider, # The superseding score set is unpublished so the newest version to its owner is the unpublished one. -def test_show_correct_score_set_version_with_superseded_score_set_to_its_owner(session, data_provider, client, setup_router_db, data_files): +def test_show_correct_score_set_version_with_superseded_score_set_to_its_owner( + session, data_provider, client, setup_router_db, data_files +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" @@ -2019,7 +2068,7 @@ def test_show_correct_score_set_version_with_superseded_score_set_to_its_owner(s score_set = score_set_response.json() assert score_set_response.status_code == 200 assert score_set["urn"] == superseding_score_set["urn"] - + def test_anonymous_user_cannot_add_score_calibrations_to_score_set(client, setup_router_db, anonymous_app_overrides): experiment = create_experiment(client) @@ -2093,6 +2142,7 @@ def test_score_set_not_found_for_non_existent_score_set_when_adding_score_calibr # Score set download files ######################################################################################################################## + # Test file doesn't have hgvs_splice so its values are all NA. def test_download_scores_file(session, data_provider, client, setup_router_db, data_files): experiment = create_experiment(client) @@ -2105,7 +2155,9 @@ def test_download_scores_file(session, data_provider, client, setup_router_db, d publish_score_set = publish_score_set_response.json() print(publish_score_set) - download_scores_csv_response = client.get(f"/api/v1/score-sets/{publish_score_set['urn']}/scores?drop_na_columns=true") + download_scores_csv_response = client.get( + f"/api/v1/score-sets/{publish_score_set['urn']}/scores?drop_na_columns=true" + ) assert download_scores_csv_response.status_code == 200 download_scores_csv = download_scores_csv_response.text csv_header = download_scores_csv.split("\n")[0] @@ -2118,15 +2170,20 @@ def test_download_scores_file(session, data_provider, client, setup_router_db, d def test_download_counts_file(session, data_provider, client, setup_router_db, data_files): experiment = create_experiment(client) score_set = create_seq_score_set_with_variants( - client, session, data_provider, experiment["urn"], + client, + session, + data_provider, + experiment["urn"], scores_csv_path=data_files / "scores.csv", - counts_csv_path = data_files / "counts.csv" + counts_csv_path=data_files / "counts.csv", ) publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") assert publish_score_set_response.status_code == 200 publish_score_set = publish_score_set_response.json() - download_counts_csv_response = client.get(f"/api/v1/score-sets/{publish_score_set['urn']}/counts?drop_na_columns=true") + download_counts_csv_response = client.get( + f"/api/v1/score-sets/{publish_score_set['urn']}/counts?drop_na_columns=true" + ) assert download_counts_csv_response.status_code == 200 download_counts_csv = download_counts_csv_response.text csv_header = download_counts_csv.split("\n")[0] From d1f097d351a47ff3922852aa5bb48bac4061faae Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 01:49:49 -0700 Subject: [PATCH 11/20] (Materialized) view utilities Adds utilities for managing materialized and non-materialized views with SQLAlchemy. These ORM methods aren't perfect and will still require knowledge of the underlying view, but make accessing them easier and make their creation automated for test cases. Might also be useful for #89. --- src/mavedb/db/view.py | 147 ++++++++++++++++++++++++++++++++++++++++++ tests/conftest.py | 4 ++ 2 files changed, 151 insertions(+) create mode 100644 src/mavedb/db/view.py diff --git a/src/mavedb/db/view.py b/src/mavedb/db/view.py new file mode 100644 index 00000000..3c64ee5c --- /dev/null +++ b/src/mavedb/db/view.py @@ -0,0 +1,147 @@ +""" +Utilities for managing views via SQLAlchemy. +""" + +from functools import partial + +import sqlalchemy as sa +from sqlalchemy.ext import compiler +from sqlalchemy.schema import DDLElement, MetaData +from sqlalchemy.orm import Session + +from mavedb.db.base import Base +from mavedb.db.session import SessionLocal + +# See: https://github.com/sqlalchemy/sqlalchemy/wiki/Views, https://github.com/jeffwidman/sqlalchemy-postgresql-materialized-views?tab=readme-ov-file + + +class CreateView(DDLElement): + def __init__(self, name: str, selectable: sa.Select, materialized: bool): + self.name = name + self.selectable = selectable + self.materialized = materialized + + +class DropView(DDLElement): + def __init__(self, name: str, materialized: bool): + self.name = name + self.materialized = materialized + + +class MaterializedView(Base): + __abstract__ = True + + @classmethod + def refresh(cls, concurrently=True): + """Refresh this materialized view.""" + refresh_mat_view(cls.__table__.fullname, concurrently) + + +@compiler.compiles(CreateView) +def _create_view(element: CreateView, compiler, **kw): + return "CREATE %s %s AS %s" % ( + "MATERIALIZED VIEW" if element.materialized else "VIEW", + element.name, + compiler.sql_compiler.process(element.selectable, literal_binds=True), + ) + + +@compiler.compiles(DropView) +def _drop_view(element: DropView, compiler, **kw): + return "DROP %s %s" % ("MATERIALIZED VIEW" if element.materialized else "VIEW", element.name) + + +def view_exists(ddl: CreateView, target, connection: Session, materialized: bool, **kw): + inspector = sa.inspect(connection) + if inspector is None: + return False + + view_names = inspector.get_materialized_view_names() if ddl.materialized else inspector.get_view_names() + return ddl.name in view_names + + +def view_doesnt_exist(ddl: CreateView, target, connection: Session, materialized: bool, **kw): + return not view_exists(ddl, target, connection, materialized, **kw) + + +def view(name: str, selectable: sa.Select, metadata: MetaData = Base.metadata, materialized: bool = False): + """ + Register a view or materialized view to SQLAlchemy. Use this function to define a view on some arbitrary + model class. + + ``` + class MyView(Base): + __table__ = view( + "my_view", + select( + MyModel.id.label("id"), + MyModel.name.label("name"), + ), + materialized=False, + ) + ``` + + When registered in this manner, SQLAlchemy will create and destroy the view along with other tables. + """ + t = sa.table( + name, + *(sa.Column(c.name, c.type, primary_key=c.primary_key) for c in selectable.selected_columns), + ) + t.primary_key.update(c for c in t.c if c.primary_key) # type: ignore + + if materialized: + sa.event.listen( + metadata, + "after_create", + CreateView(name, selectable, True).execute_if(callable_=partial(view_doesnt_exist, materialized=True)), + ) + sa.event.listen( + metadata, + "before_drop", + DropView(name, True).execute_if(callable_=partial(view_exists, materialized=True)), + ) + + else: + sa.event.listen( + metadata, + "after_create", + CreateView(name, selectable, False).execute_if(callable_=partial(view_doesnt_exist, materialized=False)), + ) + sa.event.listen( + metadata, + "before_drop", + DropView(name, False).execute_if(callable_=partial(view_exists, materialized=False)), + ) + + return t + + +# TODO: untested. +def refresh_mat_view(name, concurrently=True): + """ + Refreshes a single materialized view, given by `name`. + """ + db = SessionLocal() + try: + # since session.execute() bypasses autoflush, must manually flush in order + # to include newly-created/modified objects in the refresh + db.flush() + _con = "CONCURRENTLY " if concurrently else "" + db.execute("REFRESH MATERIALIZED VIEW " + _con + name) + finally: + db.close() + + +# TODO: untested. +def refresh_all_mat_views(concurrently=True): + """ + Refreshes all materialized views. Views are refreshed in non-deterministic order, + so view definitions can't depend on each other. + """ + db = SessionLocal() + try: + mat_views = db.inspect(db.engine).get_view_names() + for v in mat_views: + refresh_mat_view(v, concurrently) + finally: + db.close() diff --git a/tests/conftest.py b/tests/conftest.py index 429c6cca..16ac097c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import os +import logging import sys from concurrent import futures from inspect import getsourcefile @@ -42,6 +43,9 @@ @pytest.fixture() def session(postgresql): + # Un-comment this line to log all database queries: + logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) + connection = ( f"postgresql+psycopg2://{postgresql.info.user}:" f"@{postgresql.info.host}:{postgresql.info.port}/{postgresql.info.dbname}" From f8c6b738c2616f785fd12da44473795f3d602d07 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 01:52:48 -0700 Subject: [PATCH 12/20] Add 'alembic-utils' to help manage materialized view migrations --- poetry.lock | 2499 +++++++++++++++++++++++++----------------------- pyproject.toml | 3 +- 2 files changed, 1282 insertions(+), 1220 deletions(-) diff --git a/poetry.lock b/poetry.lock index a06e32e7..3cdd937f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -18,26 +18,48 @@ SQLAlchemy = ">=1.3.0" [package.extras] tz = ["python-dateutil"] +[[package]] +name = "alembic-utils" +version = "0.8.1" +description = "A sqlalchemy/alembic extension for migrating procedures and views" +optional = true +python-versions = ">=3.7" +files = [ + {file = "alembic_utils-0.8.1.tar.gz", hash = "sha256:073626217c8d8bdc66d1f66f8866d4f743969ac08502ba3bc15bcd60190460d7"}, +] + +[package.dependencies] +alembic = ">=1.5.7" +flupy = "*" +parse = ">=1.8.4" +sqlalchemy = ">=1.4" +typing_extensions = "*" + +[package.extras] +dev = ["black", "mkdocs", "mypy", "pre-commit", "psycopg2-binary", "pylint", "pytest", "pytest-cov"] +docs = ["mkautodoc", "mkdocs", "pygments", "pymdown-extensions"] +nvim = ["neovim", "python-language-server"] + [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] @@ -61,49 +83,46 @@ watch = ["watchfiles (>=0.16)"] [[package]] name = "asttokens" -version = "2.4.1" +version = "3.0.0" description = "Annotate AST trees with source code positions" optional = true -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, + {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, + {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] -[package.dependencies] -six = ">=1.12.0" - [package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +astroid = ["astroid (>=2,<4)"] +test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] name = "attrs" -version = "24.2.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] @@ -123,17 +142,18 @@ cryptography = "*" [[package]] name = "beautifulsoup4" -version = "4.12.3" +version = "4.13.3" description = "Screen-scraping library" optional = true -python-versions = ">=3.6.0" +python-versions = ">=3.7.0" files = [ - {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, - {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, + {file = "beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16"}, + {file = "beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b"}, ] [package.dependencies] soupsieve = ">1.2" +typing-extensions = ">=4.0.0" [package.extras] cchardet = ["cchardet"] @@ -668,13 +688,13 @@ crt = ["awscrt (==0.21.2)"] [[package]] name = "botocore-stubs" -version = "1.35.43" +version = "1.37.12" description = "Type annotations and code completion for botocore" optional = false python-versions = ">=3.8" files = [ - {file = "botocore_stubs-1.35.43-py3-none-any.whl", hash = "sha256:b4c7fc22125dc05b3280b9b03ae7b826dab072cac4cc8f93566671988c60fcd7"}, - {file = "botocore_stubs-1.35.43.tar.gz", hash = "sha256:f72326ddc0d79baea615d26cbe87d07a6496469bd9d704a9cab8e7a79e6b0b22"}, + {file = "botocore_stubs-1.37.12-py3-none-any.whl", hash = "sha256:474ed3dd1e07e60da16b5be229d5f61fe3563eb7d815ff29e58a0e855623e195"}, + {file = "botocore_stubs-1.37.12.tar.gz", hash = "sha256:db834e6c5f0043a7dcb39f2c5f12c7434a835c477d91aa20bc2ce7fac588dadb"}, ] [package.dependencies] @@ -719,13 +739,13 @@ requests = "*" [[package]] name = "certifi" -version = "2024.8.30" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -820,127 +840,114 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = true python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -976,88 +983,93 @@ cron = ["capturer (>=2.4)"] [[package]] name = "configparser" -version = "7.1.0" +version = "7.2.0" description = "Updated configparser from stdlib for earlier Pythons." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "configparser-7.1.0-py3-none-any.whl", hash = "sha256:98e374573c4e10e92399651e3ba1c47a438526d633c44ee96143dec26dad4299"}, - {file = "configparser-7.1.0.tar.gz", hash = "sha256:eb82646c892dbdf773dae19c633044d163c3129971ae09b49410a303b8e0a5f7"}, + {file = "configparser-7.2.0-py3-none-any.whl", hash = "sha256:fee5e1f3db4156dcd0ed95bc4edfa3580475537711f67a819c966b389d09ce62"}, + {file = "configparser-7.2.0.tar.gz", hash = "sha256:b629cc8ae916e3afbd36d1b3d093f34193d851e11998920fdcfc4552218b7b70"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "types-backports"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pytest (>=6,!=8.1.*)", "types-backports"] +type = ["pytest-mypy"] [[package]] name = "coverage" -version = "7.6.3" +version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, - {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, - {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, - {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, - {file = "coverage-7.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b"}, - {file = "coverage-7.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f"}, - {file = "coverage-7.6.3-cp311-cp311-win32.whl", hash = "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97"}, - {file = "coverage-7.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6"}, - {file = "coverage-7.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6"}, - {file = "coverage-7.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167"}, - {file = "coverage-7.6.3-cp312-cp312-win32.whl", hash = "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd"}, - {file = "coverage-7.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6"}, - {file = "coverage-7.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6"}, - {file = "coverage-7.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4"}, - {file = "coverage-7.6.3-cp313-cp313-win32.whl", hash = "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f"}, - {file = "coverage-7.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce"}, - {file = "coverage-7.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3"}, - {file = "coverage-7.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91"}, - {file = "coverage-7.6.3-cp313-cp313t-win32.whl", hash = "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43"}, - {file = "coverage-7.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0"}, - {file = "coverage-7.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2"}, - {file = "coverage-7.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13"}, - {file = "coverage-7.6.3-cp39-cp39-win32.whl", hash = "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3"}, - {file = "coverage-7.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d"}, - {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, - {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, + {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, + {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, ] [package.dependencies] @@ -1068,38 +1080,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = true python-versions = ">=3.7" files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -1112,18 +1124,18 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "decorator" -version = "5.1.1" +version = "5.2.1" description = "Decorators for Humans" optional = true -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, + {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, + {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, ] [[package]] @@ -1159,13 +1171,13 @@ wmi = ["wmi (>=1.5.1)"] [[package]] name = "ecdsa" -version = "0.19.0" +version = "0.19.1" description = "ECDSA cryptographic signature library (pure python)" optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6" files = [ - {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, - {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, + {file = "ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3"}, + {file = "ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61"}, ] [package.dependencies] @@ -1225,13 +1237,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.1.0" +version = "2.2.0" description = "Get the currently executing AST node of a frame, and other information" optional = true python-versions = ">=3.8" files = [ - {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, - {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, + {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, + {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, ] [package.extras] @@ -1282,20 +1294,36 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6 [[package]] name = "filelock" -version = "3.16.1" +version = "3.18.0" description = "A platform independent file lock." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] typing = ["typing-extensions (>=4.12.2)"] +[[package]] +name = "flupy" +version = "1.2.1" +description = "Method chaining built on generators" +optional = true +python-versions = "*" +files = [ + {file = "flupy-1.2.1.tar.gz", hash = "sha256:42aab3b4b3eb1984a4616c40d8f049ecdee546eaad9467470731d456dbff7fa4"}, +] + +[package.dependencies] +typing_extensions = ">=4" + +[package.extras] +dev = ["black", "mypy", "pre-commit", "pylint", "pytest", "pytest-benchmark", "pytest-cov"] + [[package]] name = "fqfa" version = "1.3.1" @@ -1433,105 +1461,120 @@ dev = ["black", "flake8", "ipython", "isort", "jupyter", "pytest (>=5.3)", "pyte [[package]] name = "hiredis" -version = "3.0.0" +version = "3.1.0" description = "Python wrapper for hiredis" optional = true python-versions = ">=3.8" files = [ - {file = "hiredis-3.0.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:4b182791c41c5eb1d9ed736f0ff81694b06937ca14b0d4dadde5dadba7ff6dae"}, - {file = "hiredis-3.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:13c275b483a052dd645eb2cb60d6380f1f5215e4c22d6207e17b86be6dd87ffa"}, - {file = "hiredis-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1018cc7f12824506f165027eabb302735b49e63af73eb4d5450c66c88f47026"}, - {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83a29cc7b21b746cb6a480189e49f49b2072812c445e66a9e38d2004d496b81c"}, - {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e241fab6332e8fb5f14af00a4a9c6aefa22f19a336c069b7ddbf28ef8341e8d6"}, - {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fb8de899f0145d6c4d5d4bd0ee88a78eb980a7ffabd51e9889251b8f58f1785"}, - {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b23291951959141173eec10f8573538e9349fa27f47a0c34323d1970bf891ee5"}, - {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e421ac9e4b5efc11705a0d5149e641d4defdc07077f748667f359e60dc904420"}, - {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:77c8006c12154c37691b24ff293c077300c22944018c3ff70094a33e10c1d795"}, - {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:41afc0d3c18b59eb50970479a9c0e5544fb4b95e3a79cf2fbaece6ddefb926fe"}, - {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:04ccae6dcd9647eae6025425ab64edb4d79fde8b9e6e115ebfabc6830170e3b2"}, - {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fe91d62b0594db5ea7d23fc2192182b1a7b6973f628a9b8b2e0a42a2be721ac6"}, - {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:99516d99316062824a24d145d694f5b0d030c80da693ea6f8c4ecf71a251d8bb"}, - {file = "hiredis-3.0.0-cp310-cp310-win32.whl", hash = "sha256:562eaf820de045eb487afaa37e6293fe7eceb5b25e158b5a1974b7e40bf04543"}, - {file = "hiredis-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a1c81c89ed765198da27412aa21478f30d54ef69bf5e4480089d9c3f77b8f882"}, - {file = "hiredis-3.0.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:4664dedcd5933364756d7251a7ea86d60246ccf73a2e00912872dacbfcef8978"}, - {file = "hiredis-3.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:47de0bbccf4c8a9f99d82d225f7672b9dd690d8fd872007b933ef51a302c9fa6"}, - {file = "hiredis-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e43679eca508ba8240d016d8cca9d27342d70184773c15bea78a23c87a1922f1"}, - {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13c345e7278c210317e77e1934b27b61394fee0dec2e8bd47e71570900f75823"}, - {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00018f22f38530768b73ea86c11f47e8d4df65facd4e562bd78773bd1baef35e"}, - {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ea3a86405baa8eb0d3639ced6926ad03e07113de54cb00fd7510cb0db76a89d"}, - {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c073848d2b1d5561f3903879ccf4e1a70c9b1e7566c7bdcc98d082fa3e7f0a1d"}, - {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a8dffb5f5b3415a4669d25de48b617fd9d44b0bccfc4c2ab24b06406ecc9ecb"}, - {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22c17c96143c2a62dfd61b13803bc5de2ac526b8768d2141c018b965d0333b66"}, - {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c3ece960008dab66c6b8bb3a1350764677ee7c74ccd6270aaf1b1caf9ccebb46"}, - {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f75999ae00a920f7dce6ecae76fa5e8674a3110e5a75f12c7a2c75ae1af53396"}, - {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e069967cbd5e1900aafc4b5943888f6d34937fc59bf8918a1a546cb729b4b1e4"}, - {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0aacc0a78e1d94d843a6d191f224a35893e6bdfeb77a4a89264155015c65f126"}, - {file = "hiredis-3.0.0-cp311-cp311-win32.whl", hash = "sha256:719c32147ba29528cb451f037bf837dcdda4ff3ddb6cdb12c4216b0973174718"}, - {file = "hiredis-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:bdc144d56333c52c853c31b4e2e52cfbdb22d3da4374c00f5f3d67c42158970f"}, - {file = "hiredis-3.0.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:484025d2eb8f6348f7876fc5a2ee742f568915039fcb31b478fd5c242bb0fe3a"}, - {file = "hiredis-3.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:fcdb552ffd97151dab8e7bc3ab556dfa1512556b48a367db94b5c20253a35ee1"}, - {file = "hiredis-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bb6f9fd92f147ba11d338ef5c68af4fd2908739c09e51f186e1d90958c68cc1"}, - {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa86bf9a0ed339ec9e8a9a9d0ae4dccd8671625c83f9f9f2640729b15e07fbfd"}, - {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e194a0d5df9456995d8f510eab9f529213e7326af6b94770abf8f8b7952ddcaa"}, - {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a1df39d74ec507d79c7a82c8063eee60bf80537cdeee652f576059b9cdd15c"}, - {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f91456507427ba36fd81b2ca11053a8e112c775325acc74e993201ea912d63e9"}, - {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9862db92ef67a8a02e0d5370f07d380e14577ecb281b79720e0d7a89aedb9ee5"}, - {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d10fcd9e0eeab835f492832b2a6edb5940e2f1230155f33006a8dfd3bd2c94e4"}, - {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:48727d7d405d03977d01885f317328dc21d639096308de126c2c4e9950cbd3c9"}, - {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e0bb6102ebe2efecf8a3292c6660a0e6fac98176af6de67f020bea1c2343717"}, - {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:df274e3abb4df40f4c7274dd3e587dfbb25691826c948bc98d5fead019dfb001"}, - {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:034925b5fb514f7b11aac38cd55b3fd7e9d3af23bd6497f3f20aa5b8ba58e232"}, - {file = "hiredis-3.0.0-cp312-cp312-win32.whl", hash = "sha256:120f2dda469b28d12ccff7c2230225162e174657b49cf4cd119db525414ae281"}, - {file = "hiredis-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:e584fe5f4e6681d8762982be055f1534e0170f6308a7a90f58d737bab12ff6a8"}, - {file = "hiredis-3.0.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:122171ff47d96ed8dd4bba6c0e41d8afaba3e8194949f7720431a62aa29d8895"}, - {file = "hiredis-3.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ba9fc605ac558f0de67463fb588722878641e6fa1dabcda979e8e69ff581d0bd"}, - {file = "hiredis-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a631e2990b8be23178f655cae8ac6c7422af478c420dd54e25f2e26c29e766f1"}, - {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63482db3fadebadc1d01ad33afa6045ebe2ea528eb77ccaabd33ee7d9c2bad48"}, - {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f669212c390eebfbe03c4e20181f5970b82c5d0a0ad1df1785f7ffbe7d61150"}, - {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a49ef161739f8018c69b371528bdb47d7342edfdee9ddc75a4d8caddf45a6e"}, - {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98a152052b8878e5e43a2e3a14075218adafc759547c98668a21e9485882696c"}, - {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50a196af0ce657fcde9bf8a0bbe1032e22c64d8fcec2bc926a35e7ff68b3a166"}, - {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f2f312eef8aafc2255e3585dcf94d5da116c43ef837db91db9ecdc1bc930072d"}, - {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:6ca41fa40fa019cde42c21add74aadd775e71458051a15a352eabeb12eb4d084"}, - {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6eecb343c70629f5af55a8b3e53264e44fa04e155ef7989de13668a0cb102a90"}, - {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:c3fdad75e7837a475900a1d3a5cc09aa024293c3b0605155da2d42f41bc0e482"}, - {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8854969e7480e8d61ed7549eb232d95082a743e94138d98d7222ba4e9f7ecacd"}, - {file = "hiredis-3.0.0-cp38-cp38-win32.whl", hash = "sha256:f114a6c86edbf17554672b050cce72abf489fe58d583c7921904d5f1c9691605"}, - {file = "hiredis-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7d99b91e42217d7b4b63354b15b41ce960e27d216783e04c4a350224d55842a4"}, - {file = "hiredis-3.0.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:4c6efcbb5687cf8d2aedcc2c3ed4ac6feae90b8547427d417111194873b66b06"}, - {file = "hiredis-3.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5b5cff42a522a0d81c2ae7eae5e56d0ee7365e0c4ad50c4de467d8957aff4414"}, - {file = "hiredis-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:82f794d564f4bc76b80c50b03267fe5d6589e93f08e66b7a2f674faa2fa76ebc"}, - {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7a4c1791d7aa7e192f60fe028ae409f18ccdd540f8b1e6aeb0df7816c77e4a4"}, - {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2537b2cd98192323fce4244c8edbf11f3cac548a9d633dbbb12b48702f379f4"}, - {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fed69bbaa307040c62195a269f82fc3edf46b510a17abb6b30a15d7dab548df"}, - {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:869f6d5537d243080f44253491bb30aa1ec3c21754003b3bddeadedeb65842b0"}, - {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d435ae89073d7cd51e6b6bf78369c412216261c9c01662e7008ff00978153729"}, - {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:204b79b30a0e6be0dc2301a4d385bb61472809f09c49f400497f1cdd5a165c66"}, - {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3ea635101b739c12effd189cc19b2671c268abb03013fd1f6321ca29df3ca625"}, - {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f359175197fd833c8dd7a8c288f1516be45415bb5c939862ab60c2918e1e1943"}, - {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac6d929cb33dd12ad3424b75725975f0a54b5b12dbff95f2a2d660c510aa106d"}, - {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:100431e04d25a522ef2c3b94f294c4219c4de3bfc7d557b6253296145a144c11"}, - {file = "hiredis-3.0.0-cp39-cp39-win32.whl", hash = "sha256:e1a9c14ae9573d172dc050a6f63a644457df5d01ec4d35a6a0f097f812930f83"}, - {file = "hiredis-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:54a6dd7b478e6eb01ce15b3bb5bf771e108c6c148315bf194eb2ab776a3cac4d"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50da7a9edf371441dfcc56288d790985ee9840d982750580710a9789b8f4a290"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b285ef6bf1581310b0d5e8f6ce64f790a1c40e89c660e1320b35f7515433672"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dcfa684966f25b335072115de2f920228a3c2caf79d4bfa2b30f6e4f674a948"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a41be8af1fd78ca97bc948d789a09b730d1e7587d07ca53af05758f31f4b985d"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:038756db735e417ab36ee6fd7725ce412385ed2bd0767e8179a4755ea11b804f"}, - {file = "hiredis-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fcecbd39bd42cef905c0b51c9689c39d0cc8b88b1671e7f40d4fb213423aef3a"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a131377493a59fb0f5eaeb2afd49c6540cafcfba5b0b3752bed707be9e7c4eaf"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d22c53f0ec5c18ecb3d92aa9420563b1c5d657d53f01356114978107b00b860"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a91e9520fbc65a799943e5c970ffbcd67905744d8becf2e75f9f0a5e8414f0"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dc8043959b50141df58ab4f398e8ae84c6f9e673a2c9407be65fc789138f4a6"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51b99cfac514173d7b8abdfe10338193e8a0eccdfe1870b646009d2fb7cbe4b5"}, - {file = "hiredis-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:fa1fcad89d8a41d8dc10b1e54951ec1e161deabd84ed5a2c95c3c7213bdb3514"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:898636a06d9bf575d2c594129085ad6b713414038276a4bfc5db7646b8a5be78"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:466f836dbcf86de3f9692097a7a01533dc9926986022c6617dc364a402b265c5"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23142a8af92a13fc1e3f2ca1d940df3dcf2af1d176be41fe8d89e30a837a0b60"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:793c80a3d6b0b0e8196a2d5de37a08330125668c8012922685e17aa9108c33ac"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:467d28112c7faa29b7db743f40803d927c8591e9da02b6ce3d5fadc170a542a2"}, - {file = "hiredis-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dc384874a719c767b50a30750f937af18842ee5e288afba95a5a3ed703b1515a"}, - {file = "hiredis-3.0.0.tar.gz", hash = "sha256:fed8581ae26345dea1f1e0d1a96e05041a727a45e7d8d459164583e23c6ac441"}, + {file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:2892db9db21f0cf7cc298d09f85d3e1f6dc4c4c24463ab67f79bc7a006d51867"}, + {file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:93cfa6cc25ee2ceb0be81dc61eca9995160b9e16bdb7cca4a00607d57e998918"}, + {file = "hiredis-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2af62070aa9433802cae7be7364d5e82f76462c6a2ae34e53008b637aaa9a156"}, + {file = "hiredis-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:072c162260ebb1d892683107da22d0d5da7a1414739eae4e185cac22fe89627f"}, + {file = "hiredis-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b232c43e89755ba332c2745ddab059c0bc1a0f01448a3a14d506f8448b1ce6"}, + {file = "hiredis-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb5316c9a65c4dde80796aa245b76011bab64eb84461a77b0a61c1bf2970bcc9"}, + {file = "hiredis-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e812a4e656bbd1c1c15c844b28259c49e26bb384837e44e8d2aa55412c91d2f7"}, + {file = "hiredis-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93a6c9230e5a5565847130c0e1005c8d3aa5ca681feb0ed542c4651323d32feb"}, + {file = "hiredis-3.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a5f65e89ce50a94d9490d5442a649c6116f53f216c8c14eb37cf9637956482b2"}, + {file = "hiredis-3.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b2d6e33601c67c074c367fdccdd6033e642284e7a56adc130f18f724c378ca8"}, + {file = "hiredis-3.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bad3b1e0c83849910f28c95953417106f539277035a4b515d1425f93947bc28f"}, + {file = "hiredis-3.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9646de31f5994e6218311dcf216e971703dbf804c510fd3f84ddb9813c495824"}, + {file = "hiredis-3.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59a9230f3aa38a33d09d8171400de202f575d7a38869e5ce2947829bca6fe359"}, + {file = "hiredis-3.1.0-cp310-cp310-win32.whl", hash = "sha256:0322d70f3328b97da14b6e98b18f0090a12ed8a8bf7ae20932e2eb9d1bb0aa2c"}, + {file = "hiredis-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:802474c18e878b3f9905e160a8b7df87d57885758083eda76c5978265acb41aa"}, + {file = "hiredis-3.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:c339ff4b4739b2a40da463763dd566129762f72926bca611ad9a457a9fe64abd"}, + {file = "hiredis-3.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:0ffa2552f704a45954627697a378fc2f559004e53055b82f00daf30bd4305330"}, + {file = "hiredis-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9acf7f0e7106f631cd618eb60ec9bbd6e43045addd5310f66ba1177209567e59"}, + {file = "hiredis-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea4f5ecf9dbea93c827486f59c606684c3496ea71c7ba9a8131932780696e61a"}, + {file = "hiredis-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39efab176fca3d5111075f6ba56cd864f18db46d858289d39360c5672e0e5c3e"}, + {file = "hiredis-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1110eae007f30e70a058d743e369c24430327cd01fd97d99519d6794a58dd587"}, + {file = "hiredis-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b390f63191bcccbb6044d4c118acdf4fa55f38e5658ac4cfd5a33a6f0c07659"}, + {file = "hiredis-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72a98ccc7b8ec9ce0100ecf59f45f05d2023606e8e3676b07a316d1c1c364072"}, + {file = "hiredis-3.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c76e751fd1e2f221dec09cdc24040ee486886e943d5d7ffc256e8cf15c75e51"}, + {file = "hiredis-3.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7d3880f213b6f14e9c69ce52beffd1748eecc8669698c4782761887273b6e1bd"}, + {file = "hiredis-3.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:87c2b3fe7e7c96eba376506a76e11514e07e848f737b254e0973e4b5c3a491e9"}, + {file = "hiredis-3.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d3cfb4089e96f8f8ee9554da93148a9261aa6612ad2cc202c1a494c7b712e31f"}, + {file = "hiredis-3.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f12018e5c5f866a1c3f7017cb2d88e5c6f9440df2281e48865a2b6c40f247f4"}, + {file = "hiredis-3.1.0-cp311-cp311-win32.whl", hash = "sha256:107b66ce977bb2dff8f2239e68344360a75d05fed3d9fa0570ac4d3020ce2396"}, + {file = "hiredis-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f1240bde53d3d1676f0aba61b3661560dc9a681cae24d9de33e650864029aa4"}, + {file = "hiredis-3.1.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:f7c7f89e0bc4246115754e2eda078a111282f6d6ecc6fb458557b724fe6f2aac"}, + {file = "hiredis-3.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:3dbf9163296fa45fbddcfc4c5900f10e9ddadda37117dbfb641e327e536b53e0"}, + {file = "hiredis-3.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af46a4be0e82df470f68f35316fa16cd1e134d1c5092fc1082e1aad64cce716d"}, + {file = "hiredis-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc63d698c43aea500a84d8b083f830c03808b6cf3933ae4d35a27f0a3d881652"}, + {file = "hiredis-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:676b3d88674134bfaaf70dac181d1790b0f33b3187bfb9da9221e17e0e624f83"}, + {file = "hiredis-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aed10d9df1e2fb0011db2713ac64497462e9c2c0208b648c97569da772b959ca"}, + {file = "hiredis-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b5bd8adfe8742e331a94cccd782bffea251fa70d9a709e71f4510f50794d700"}, + {file = "hiredis-3.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fc4e35b4afb0af6da55495dd0742ad32ab88150428a6ecdbb3085cbd60714e8"}, + {file = "hiredis-3.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:89b83e76eb00ab0464e7b0752a3ffcb02626e742e9509bc141424a9c3202e8dc"}, + {file = "hiredis-3.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:98ebf08c907836b70a8f40e030df8ab6f174dc7f6fa765251d813e89f14069d8"}, + {file = "hiredis-3.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6c840b9cec086328f2ee2cfee0038b5d6bbb514bac7b5e579da6e346eaac056c"}, + {file = "hiredis-3.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c5c44e9fa6f4462d0330cb5f5d46fa652512fc86b41d4d1974d0356f263e9105"}, + {file = "hiredis-3.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e665b14ab50aa175cfa306fcb00fffd4e3ff02ceb36ca6a4df00b1246d6a73c4"}, + {file = "hiredis-3.1.0-cp312-cp312-win32.whl", hash = "sha256:bd33db977ac7af97e8d035ffadb163b00546be22e5f1297b2123f5f9bf0f8a21"}, + {file = "hiredis-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:37aed4aa9348600145e2d019c7be27855e503ecc4906c6976ff2f3b52e3d5d97"}, + {file = "hiredis-3.1.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:b87cddd8107487863fed6994de51e5594a0be267b0b19e213694e99cdd614623"}, + {file = "hiredis-3.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:d302deff8cb63a7feffc1844e4dafc8076e566bbf10c5aaaf0f4fe791b8a6bd0"}, + {file = "hiredis-3.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a018340c073cf88cb635b2bedff96619df2f666018c655e7911f46fa2c1c178"}, + {file = "hiredis-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1e8ba6414ac1ae536129e18c069f3eb497df5a74e136e3566471620a4fa5f95"}, + {file = "hiredis-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a86b9fef256c2beb162244791fdc025aa55f936d6358e86e2020e512fe2e4972"}, + {file = "hiredis-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7acdc68e29a446ad17aadaff19c981a36b3bd8c894c3520412c8a7ab1c3e0de7"}, + {file = "hiredis-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7e06baea05de57e1e7548064f505a6964e992674fe61b8f274afe2ac93b6371"}, + {file = "hiredis-3.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35b5fc061c8a0dbfdb440053280504d6aaa8d9726bd4d1d0e1cfcbbdf0d60b73"}, + {file = "hiredis-3.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c89d2dcb271d24c44f02264233b75d5db8c58831190fa92456a90b87fa17b748"}, + {file = "hiredis-3.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:aa36688c10a08f626fddcf68c2b1b91b0e90b070c26e550a4151a877f5c2d431"}, + {file = "hiredis-3.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3982a9c16c1c4bc05a00b65d01ffb8d80ea1a7b6b533be2f1a769d3e989d2c0"}, + {file = "hiredis-3.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d1a6f889514ee2452300c9a06862fceedef22a2891f1c421a27b1ba52ef130b2"}, + {file = "hiredis-3.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8a45ff7915392a55d9386bb235ea1d1eb9960615f301979f02143fc20036b699"}, + {file = "hiredis-3.1.0-cp313-cp313-win32.whl", hash = "sha256:539e5bb725b62b76a5319a4e68fc7085f01349abc2316ef3df608ea0883c51d2"}, + {file = "hiredis-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9020fd7e58f489fda6a928c31355add0e665fd6b87b21954e675cf9943eafa32"}, + {file = "hiredis-3.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:b621a89fc29b3f4b01be6640ec81a6a94b5382bc78fecb876408d57a071e45aa"}, + {file = "hiredis-3.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:363e21fba55e1a26349dc9ca7da6b14332123879b6359bcee4a9acecb40ca33b"}, + {file = "hiredis-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c156156798729eadc9ab76ffee96c88b93cc1c3b493f4dd0a4341f53939194ee"}, + {file = "hiredis-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e38d8a325f9a6afac1b1c72d996d1add9e1b99696ce9410538ba5e9aa8fdba02"}, + {file = "hiredis-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3004ef7436feb7bfa61c0b36d422b8fb8c29aaa1a514c9405f0fdee5e9694dd3"}, + {file = "hiredis-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13f5b16f97d0bbd1c04ce367c49097d1214d60e11f9fee7ef2a9b54e0a6645c8"}, + {file = "hiredis-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:230dd0e77cb0f525f58a1306a7b4aaf078037fc5229110922332ca46f90821bb"}, + {file = "hiredis-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d968116caddd19d63120d1298e62b1bbc694db3360ed0d5df8c3a97edbc12552"}, + {file = "hiredis-3.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:511e36a6fa41d3efab3cd5cd70ac388ed825993b9e66fa3b0e47cf27a2f5ffee"}, + {file = "hiredis-3.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c5cd20804e3cb0d31e7d899d8dd091f569c33fe40d4bade670a067ab7d31c2ac"}, + {file = "hiredis-3.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:09e89e7d34cfe5ca8f7a869fca827d1af0afe8aaddb26b38c01058730edb79ad"}, + {file = "hiredis-3.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:570cbf31413c77fe5e7c157f2943ca4400493ddd9cf2184731cfcafc753becd7"}, + {file = "hiredis-3.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b9b4da8162cf289781732d6a5ba01d820c42c05943fcdb7de307d03639961db3"}, + {file = "hiredis-3.1.0-cp38-cp38-win32.whl", hash = "sha256:bc117a04bcb461d3bb1b2c5b417aee3442e1e8aa33ebc800481431f4c09fe0c5"}, + {file = "hiredis-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:34f3f5f0354db2d6797a6fb08d2c036a50af62a1d919d122c1c784304ef49347"}, + {file = "hiredis-3.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:a26fa888025badb5563f283cc19594c215a413e905729e59a5f7cf3f46d66c32"}, + {file = "hiredis-3.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f50763cd819d4a52a47b5966d4bb47dee34b637c5fa6402509800eee6ecb61e6"}, + {file = "hiredis-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6d1c9e1fce5e0a94072667ae2bf0142b89ebbb1917d3531184e060a43f3ee11"}, + {file = "hiredis-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e38d7a56b1a79ed0bbb9e6fe376d82e3f4dcc646ae47472f2c858e19a597c112"}, + {file = "hiredis-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ef5ad8b91530e4d10a68562b0a380ea22705a60e88cecee086d7c63a38564ce"}, + {file = "hiredis-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf3d2299b054e57a9f97ca08704c2843e44f29b57dc69b76a2592ecd212efe1a"}, + {file = "hiredis-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93811d60b0f73d0f049c86f4373a3833b4a38fce374ab151074d929553eb4304"}, + {file = "hiredis-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e703ff860c1d83abbcf57012b309ead02b56b60e85150c6c3bfb37cbb16ebf"}, + {file = "hiredis-3.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f9ea0678806c53d96758e74c6a898f9d506a2e3367a344757f768bef9e069366"}, + {file = "hiredis-3.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cf6844035abf47d52a1c3f4257255af3bf3b0f14d559b08eaa45885418c6c55d"}, + {file = "hiredis-3.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7acf35cfa7ec9e1e7559c04e7095628f7d06049b5f24dcb58c1a55ef6dc689f8"}, + {file = "hiredis-3.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b885695dce7a39b1fd9a609ed9c4cf312e53df2ec028d5a78af7a891b5fbea4d"}, + {file = "hiredis-3.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1c22fa74ddd063396b19fe8445a1ae8b4190eff755d5750dda48e860a45b2ee7"}, + {file = "hiredis-3.1.0-cp39-cp39-win32.whl", hash = "sha256:0614e16339f1784df3bbd2800322e20b4127d3f3a3509f00a5562efddb2521aa"}, + {file = "hiredis-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:c2bc713ee73ab9de4a0d68b0ab0f29612342b63173714742437b977584adb2d8"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:07ab990d0835f36bf358dbb84db4541ac0a8f533128ec09af8f80a576eef2e88"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c54a88eb9d8ebc4e5eefaadbe2102a4f7499f9e413654172f40aefd25350959"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8095ef159896e5999a795b0f80e4d64281301a109e442a8d29cd750ca6bd8303"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f8ca13e2476ffd6d5be4763f5868133506ddcfa5ce54b4dac231ebdc19be6c6"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d25aa25c10f966d5415795ed271da84605044dbf436c054966cea5442451b3"}, + {file = "hiredis-3.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4180dc5f646b426e5fa1212e1348c167ee2a864b3a70d56579163d64a847dd1e"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d92144e0cd6e6e841a6ad343e9d58631626eeb4ac96b0322649379b5d4527447"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fcb91ba42903de637b94a1b64477f381f94ad82c0742c264f9245be76a7a3cbc"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce71a797b5bc02c51da082428c00251ed6a7a67a03acbda5fbf9e8d028725f6"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e04c7feb9467e3170cd4d5bee381775783d81bbc45d6147c1c0ce3b50dc04f9"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a31806306a60f3565c04c964d6bee0e9d4a5120e1da589e41976b53972edf635"}, + {file = "hiredis-3.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bc51f594c2c0863ded6501642dc96701ca8bbea9ced4fa3af0a1aeda8aa634cb"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4663a319ab7d22c597b9421e5ea384fd583e044f2f1ca9a1b98d4fef8a0fea2f"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8060fa256862b0c3de64a73ab45bc1ccf381caca464f2647af9075b200828948"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e9445b7f117a9c8c8ccad97cb44daa55ddccff3cbc9079984eac56d982ba01f"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:732cf1c5cf1324f7bf3b6086976fe62a2ca98f0bf6316f31063c2c67be8797bc"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2102a94063d878c40df92f55199637a74f535e3a0b79ceba4a00538853a21be3"}, + {file = "hiredis-3.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d968dde69e3fe903bf9ef00667669dcf04a3e096e33aaf138775106ead138bc8"}, + {file = "hiredis-3.1.0.tar.gz", hash = "sha256:51d40ac3611091020d7dea6b05ed62cb152bff595fa4f931e7b6479d777acf7c"}, ] [[package]] @@ -1557,13 +1600,13 @@ lxml = ["lxml"] [[package]] name = "httpcore" -version = "1.0.6" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -1671,13 +1714,13 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve [[package]] name = "identify" -version = "2.6.1" +version = "2.6.9" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, + {file = "identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150"}, + {file = "identify-2.6.9.tar.gz", hash = "sha256:d40dfe3142a1421d8518e3d3985ef5ac42890683e32306ad614a29490abeb6bf"}, ] [package.extras] @@ -1717,13 +1760,13 @@ tests = ["pytest-black (>=0.3.0,<0.3.10)", "pytest-cache (>=1.0)", "pytest-inven [[package]] name = "importlib-metadata" -version = "8.5.0" +version = "8.6.1" description = "Read metadata from Python packages" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, ] [package.dependencies] @@ -1735,7 +1778,7 @@ cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] @@ -1812,22 +1855,22 @@ files = [ [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." optional = true python-versions = ">=3.6" files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [package.dependencies] -parso = ">=0.8.3,<0.9.0" +parso = ">=0.8.4,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jmespath" @@ -1892,167 +1935,167 @@ mypy = ["mypy"] [[package]] name = "lxml" -version = "5.3.0" +version = "5.3.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, - {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, - {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, - {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, - {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, - {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, - {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, - {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, - {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, - {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, - {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, - {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, - {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, - {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, - {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, - {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, - {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, - {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, - {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, - {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, - {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, - {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, + {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, + {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, + {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, + {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, + {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, + {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, + {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, + {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, + {file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d"}, + {file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a"}, + {file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576"}, + {file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9"}, + {file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce"}, + {file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407"}, + {file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5"}, + {file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73"}, + {file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc"}, + {file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af"}, + {file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0"}, + {file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2"}, + {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml-html-clean"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.11)"] +source = ["Cython (>=3.0.11,<3.1.0)"] [[package]] name = "mako" -version = "1.3.5" +version = "1.3.9" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = true python-versions = ">=3.8" files = [ - {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, - {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, + {file = "Mako-1.3.9-py3-none-any.whl", hash = "sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1"}, + {file = "mako-1.3.9.tar.gz", hash = "sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac"}, ] [package.dependencies] @@ -2065,72 +2108,72 @@ testing = ["pytest"] [[package]] name = "markupsafe" -version = "3.0.1" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = true python-versions = ">=3.9" files = [ - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win32.whl", hash = "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-win32.whl", hash = "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635"}, - {file = "MarkupSafe-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-win32.whl", hash = "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa"}, - {file = "MarkupSafe-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-win32.whl", hash = "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c"}, - {file = "MarkupSafe-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-win32.whl", hash = "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b"}, - {file = "MarkupSafe-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-win32.whl", hash = "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8"}, - {file = "MarkupSafe-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b"}, - {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -2149,13 +2192,13 @@ traitlets = "*" [[package]] name = "mavehgvs" -version = "0.6.1" +version = "0.6.2" description = "Regular expression-based validation of HGVS-style variant strings for Multiplexed Assays of Variant Effect." optional = false python-versions = ">=3.6" files = [ - {file = "mavehgvs-0.6.1-py3-none-any.whl", hash = "sha256:5bf91a8c8ddf7a1f65d6c3d7fdf33c6303392cd5e7f561ba349a19d987d2637a"}, - {file = "mavehgvs-0.6.1.tar.gz", hash = "sha256:b69a88fa3c4aa1fe9c1b93b7c66b51df378bb356784e88c18a74c58179c8ab12"}, + {file = "mavehgvs-0.6.2-py3-none-any.whl", hash = "sha256:f2c330372feb5f6b9ebae3b133842f7b7d6b436cac2e8996d6618cca7f576dac"}, + {file = "mavehgvs-0.6.2.tar.gz", hash = "sha256:876c6313f986eb64e4c49ae1a94f059ffc43c2d6724f4bec5fbbe1aad97e3f70"}, ] [package.dependencies] @@ -2166,13 +2209,13 @@ dev = ["black", "flake8", "pre-commit", "pytest"] [[package]] name = "mirakuru" -version = "2.5.3" +version = "2.6.0" description = "Process executor (not only) for tests." optional = false python-versions = ">=3.9" files = [ - {file = "mirakuru-2.5.3-py3-none-any.whl", hash = "sha256:2fab68356fb98fb5358ea3ab65f5e511f34b5a0b16cfd0a0935ef15a3393f025"}, - {file = "mirakuru-2.5.3.tar.gz", hash = "sha256:39b33f8fcdf13764a6cfe936e0feeead3902a161fec438df3be7cce98f7933c6"}, + {file = "mirakuru-2.6.0-py3-none-any.whl", hash = "sha256:0ff7080997e63289dc309d0237e137ca2cfa863b3d26b3d5e8fd4e1c2b2ef659"}, + {file = "mirakuru-2.6.0.tar.gz", hash = "sha256:3256fcf81ef090a30be97a8ce50ff0c178292d7e542866c5fedc5ae6801e3a17"}, ] [package.dependencies] @@ -2311,13 +2354,13 @@ simplejson = "*" [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -2378,6 +2421,17 @@ files = [ numpy = {version = ">=1.26.0", markers = "python_version < \"3.13\""} types-pytz = ">=2022.1.1" +[[package]] +name = "parse" +version = "1.20.2" +description = "parse() is the opposite of format()" +optional = true +python-versions = "*" +files = [ + {file = "parse-1.20.2-py2.py3-none-any.whl", hash = "sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558"}, + {file = "parse-1.20.2.tar.gz", hash = "sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce"}, +] + [[package]] name = "parsley" version = "1.3" @@ -2462,13 +2516,13 @@ files = [ [[package]] name = "pre-commit" -version = "4.0.1" +version = "4.1.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, - {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, + {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, + {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, ] [package.dependencies] @@ -2480,13 +2534,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.48" +version = "3.0.50" description = "Library for building powerful interactive command lines in Python" optional = true -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, - {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, ] [package.dependencies] @@ -2494,43 +2548,36 @@ wcwidth = "*" [[package]] name = "psutil" -version = "6.1.0" -description = "Cross-platform lib for process and system monitoring in Python." +version = "7.0.0" +description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, - {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, - {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, - {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, - {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, - {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, - {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, - {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, + {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"}, + {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"}, + {file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"}, + {file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"}, + {file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"}, + {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"}, + {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"}, ] [package.extras] -dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] +dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] test = ["pytest", "pytest-xdist", "setuptools"] [[package]] name = "psycopg" -version = "3.2.3" +version = "3.2.6" description = "PostgreSQL database adapter for Python" optional = false python-versions = ">=3.8" files = [ - {file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}, - {file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"}, + {file = "psycopg-3.2.6-py3-none-any.whl", hash = "sha256:f3ff5488525890abb0566c429146add66b329e20d6d4835662b920cbbf90ac58"}, + {file = "psycopg-3.2.6.tar.gz", hash = "sha256:16fa094efa2698f260f2af74f3710f781e4a6f226efe9d1fd0c37f384639ed8a"}, ] [package.dependencies] @@ -2538,12 +2585,12 @@ typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -binary = ["psycopg-binary (==3.2.3)"] -c = ["psycopg-c (==3.2.3)"] -dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.11)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] +binary = ["psycopg-binary (==3.2.6)"] +c = ["psycopg-c (==3.2.6)"] +dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "isort-psycopg", "isort[colors] (>=6.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] pool = ["psycopg-pool"] -test = ["anyio (>=4.0)", "mypy (>=1.11)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] +test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] [[package]] name = "psycopg2" @@ -2612,54 +2659,61 @@ files = [ [[package]] name = "pydantic" -version = "1.10.18" +version = "1.10.21" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e405ffcc1254d76bb0e760db101ee8916b620893e6edfbfee563b3c6f7a67c02"}, - {file = "pydantic-1.10.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e306e280ebebc65040034bff1a0a81fd86b2f4f05daac0131f29541cafd80b80"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11d9d9b87b50338b1b7de4ebf34fd29fdb0d219dc07ade29effc74d3d2609c62"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b661ce52c7b5e5f600c0c3c5839e71918346af2ef20062705ae76b5c16914cab"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c20f682defc9ef81cd7eaa485879ab29a86a0ba58acf669a78ed868e72bb89e0"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5ae6b7c8483b1e0bf59e5f1843e4fd8fd405e11df7de217ee65b98eb5462861"}, - {file = "pydantic-1.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:74fe19dda960b193b0eb82c1f4d2c8e5e26918d9cda858cbf3f41dd28549cb70"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72fa46abace0a7743cc697dbb830a41ee84c9db8456e8d77a46d79b537efd7ec"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef0fe7ad7cbdb5f372463d42e6ed4ca9c443a52ce544472d8842a0576d830da5"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00e63104346145389b8e8f500bc6a241e729feaf0559b88b8aa513dd2065481"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae6fa2008e1443c46b7b3a5eb03800121868d5ab6bc7cda20b5df3e133cde8b3"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9f463abafdc92635da4b38807f5b9972276be7c8c5121989768549fceb8d2588"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3445426da503c7e40baccefb2b2989a0c5ce6b163679dd75f55493b460f05a8f"}, - {file = "pydantic-1.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:467a14ee2183bc9c902579bb2f04c3d3dac00eff52e252850509a562255b2a33"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:efbc8a7f9cb5fe26122acba1852d8dcd1e125e723727c59dcd244da7bdaa54f2"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24a4a159d0f7a8e26bf6463b0d3d60871d6a52eac5bb6a07a7df85c806f4c048"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74be007703547dc52e3c37344d130a7bfacca7df112a9e5ceeb840a9ce195c7"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcb20d4cb355195c75000a49bb4a31d75e4295200df620f454bbc6bdf60ca890"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46f379b8cb8a3585e3f61bf9ae7d606c70d133943f339d38b76e041ec234953f"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbfbca662ed3729204090c4d09ee4beeecc1a7ecba5a159a94b5a4eb24e3759a"}, - {file = "pydantic-1.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:c6d0a9f9eccaf7f438671a64acf654ef0d045466e63f9f68a579e2383b63f357"}, - {file = "pydantic-1.10.18-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d5492dbf953d7d849751917e3b2433fb26010d977aa7a0765c37425a4026ff1"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe734914977eed33033b70bfc097e1baaffb589517863955430bf2e0846ac30f"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15fdbe568beaca9aacfccd5ceadfb5f1a235087a127e8af5e48df9d8a45ae85c"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c3e742f62198c9eb9201781fbebe64533a3bbf6a76a91b8d438d62b813079dbc"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19a3bd00b9dafc2cd7250d94d5b578edf7a0bd7daf102617153ff9a8fa37871c"}, - {file = "pydantic-1.10.18-cp37-cp37m-win_amd64.whl", hash = "sha256:2ce3fcf75b2bae99aa31bd4968de0474ebe8c8258a0110903478bd83dfee4e3b"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:335a32d72c51a313b33fa3a9b0fe283503272ef6467910338e123f90925f0f03"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34a3613c7edb8c6fa578e58e9abe3c0f5e7430e0fc34a65a415a1683b9c32d9a"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ee4e6ca1d9616797fa2e9c0bfb8815912c7d67aca96f77428e316741082a1b"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23e8ec1ce4e57b4f441fc91e3c12adba023fedd06868445a5b5f1d48f0ab3682"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:44ae8a3e35a54d2e8fa88ed65e1b08967a9ef8c320819a969bfa09ce5528fafe"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5389eb3b48a72da28c6e061a247ab224381435256eb541e175798483368fdd3"}, - {file = "pydantic-1.10.18-cp38-cp38-win_amd64.whl", hash = "sha256:069b9c9fc645474d5ea3653788b544a9e0ccd3dca3ad8c900c4c6eac844b4620"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80b982d42515632eb51f60fa1d217dfe0729f008e81a82d1544cc392e0a50ddf"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aad8771ec8dbf9139b01b56f66386537c6fe4e76c8f7a47c10261b69ad25c2c9"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941a2eb0a1509bd7f31e355912eb33b698eb0051730b2eaf9e70e2e1589cae1d"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65f7361a09b07915a98efd17fdec23103307a54db2000bb92095457ca758d485"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6951f3f47cb5ca4da536ab161ac0163cab31417d20c54c6de5ddcab8bc813c3f"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a4c5eec138a9b52c67f664c7d51d4c7234c5ad65dd8aacd919fb47445a62c86"}, - {file = "pydantic-1.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:49e26c51ca854286bffc22b69787a8d4063a62bf7d83dc21d44d2ff426108518"}, - {file = "pydantic-1.10.18-py3-none-any.whl", hash = "sha256:06a189b81ffc52746ec9c8c007f16e5167c8b0a696e1a726369327e3db7b2a82"}, - {file = "pydantic-1.10.18.tar.gz", hash = "sha256:baebdff1907d1d96a139c25136a9bb7d17e118f133a76a2ef3b845e831e3403a"}, + {file = "pydantic-1.10.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:245e486e0fec53ec2366df9cf1cba36e0bbf066af7cd9c974bbbd9ba10e1e586"}, + {file = "pydantic-1.10.21-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c54f8d4c151c1de784c5b93dfbb872067e3414619e10e21e695f7bb84d1d1fd"}, + {file = "pydantic-1.10.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b64708009cfabd9c2211295144ff455ec7ceb4c4fb45a07a804309598f36187"}, + {file = "pydantic-1.10.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a148410fa0e971ba333358d11a6dea7b48e063de127c2b09ece9d1c1137dde4"}, + {file = "pydantic-1.10.21-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:36ceadef055af06e7756eb4b871cdc9e5a27bdc06a45c820cd94b443de019bbf"}, + {file = "pydantic-1.10.21-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0501e1d12df6ab1211b8cad52d2f7b2cd81f8e8e776d39aa5e71e2998d0379f"}, + {file = "pydantic-1.10.21-cp310-cp310-win_amd64.whl", hash = "sha256:c261127c275d7bce50b26b26c7d8427dcb5c4803e840e913f8d9df3f99dca55f"}, + {file = "pydantic-1.10.21-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8b6350b68566bb6b164fb06a3772e878887f3c857c46c0c534788081cb48adf4"}, + {file = "pydantic-1.10.21-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:935b19fdcde236f4fbf691959fa5c3e2b6951fff132964e869e57c70f2ad1ba3"}, + {file = "pydantic-1.10.21-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6a04efdcd25486b27f24c1648d5adc1633ad8b4506d0e96e5367f075ed2e0b"}, + {file = "pydantic-1.10.21-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1ba253eb5af8d89864073e6ce8e6c8dec5f49920cff61f38f5c3383e38b1c9f"}, + {file = "pydantic-1.10.21-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:57f0101e6c97b411f287a0b7cf5ebc4e5d3b18254bf926f45a11615d29475793"}, + {file = "pydantic-1.10.21-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e85834f0370d737c77a386ce505c21b06bfe7086c1c568b70e15a568d9670d"}, + {file = "pydantic-1.10.21-cp311-cp311-win_amd64.whl", hash = "sha256:6a497bc66b3374b7d105763d1d3de76d949287bf28969bff4656206ab8a53aa9"}, + {file = "pydantic-1.10.21-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ed4a5f13cf160d64aa331ab9017af81f3481cd9fd0e49f1d707b57fe1b9f3ae"}, + {file = "pydantic-1.10.21-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b7693bb6ed3fbe250e222f9415abb73111bb09b73ab90d2d4d53f6390e0ccc1"}, + {file = "pydantic-1.10.21-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185d5f1dff1fead51766da9b2de4f3dc3b8fca39e59383c273f34a6ae254e3e2"}, + {file = "pydantic-1.10.21-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38e6d35cf7cd1727822c79e324fa0677e1a08c88a34f56695101f5ad4d5e20e5"}, + {file = "pydantic-1.10.21-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1d7c332685eafacb64a1a7645b409a166eb7537f23142d26895746f628a3149b"}, + {file = "pydantic-1.10.21-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c9b782db6f993a36092480eeaab8ba0609f786041b01f39c7c52252bda6d85f"}, + {file = "pydantic-1.10.21-cp312-cp312-win_amd64.whl", hash = "sha256:7ce64d23d4e71d9698492479505674c5c5b92cda02b07c91dfc13633b2eef805"}, + {file = "pydantic-1.10.21-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0067935d35044950be781933ab91b9a708eaff124bf860fa2f70aeb1c4be7212"}, + {file = "pydantic-1.10.21-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5e8148c2ce4894ce7e5a4925d9d3fdce429fb0e821b5a8783573f3611933a251"}, + {file = "pydantic-1.10.21-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4973232c98b9b44c78b1233693e5e1938add5af18042f031737e1214455f9b8"}, + {file = "pydantic-1.10.21-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:662bf5ce3c9b1cef32a32a2f4debe00d2f4839fefbebe1d6956e681122a9c839"}, + {file = "pydantic-1.10.21-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98737c3ab5a2f8a85f2326eebcd214510f898881a290a7939a45ec294743c875"}, + {file = "pydantic-1.10.21-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0bb58bbe65a43483d49f66b6c8474424d551a3fbe8a7796c42da314bac712738"}, + {file = "pydantic-1.10.21-cp313-cp313-win_amd64.whl", hash = "sha256:e622314542fb48542c09c7bd1ac51d71c5632dd3c92dc82ede6da233f55f4848"}, + {file = "pydantic-1.10.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d356aa5b18ef5a24d8081f5c5beb67c0a2a6ff2a953ee38d65a2aa96526b274f"}, + {file = "pydantic-1.10.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08caa8c0468172d27c669abfe9e7d96a8b1655ec0833753e117061febaaadef5"}, + {file = "pydantic-1.10.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c677aa39ec737fec932feb68e4a2abe142682f2885558402602cd9746a1c92e8"}, + {file = "pydantic-1.10.21-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:79577cc045d3442c4e845df53df9f9202546e2ba54954c057d253fc17cd16cb1"}, + {file = "pydantic-1.10.21-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:b6b73ab347284719f818acb14f7cd80696c6fdf1bd34feee1955d7a72d2e64ce"}, + {file = "pydantic-1.10.21-cp37-cp37m-win_amd64.whl", hash = "sha256:46cffa24891b06269e12f7e1ec50b73f0c9ab4ce71c2caa4ccf1fb36845e1ff7"}, + {file = "pydantic-1.10.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:298d6f765e3c9825dfa78f24c1efd29af91c3ab1b763e1fd26ae4d9e1749e5c8"}, + {file = "pydantic-1.10.21-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2f4a2305f15eff68f874766d982114ac89468f1c2c0b97640e719cf1a078374"}, + {file = "pydantic-1.10.21-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35b263b60c519354afb3a60107d20470dd5250b3ce54c08753f6975c406d949b"}, + {file = "pydantic-1.10.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e23a97a6c2f2db88995496db9387cd1727acdacc85835ba8619dce826c0b11a6"}, + {file = "pydantic-1.10.21-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:3c96fed246ccc1acb2df032ff642459e4ae18b315ecbab4d95c95cfa292e8517"}, + {file = "pydantic-1.10.21-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b92893ebefc0151474f682e7debb6ab38552ce56a90e39a8834734c81f37c8a9"}, + {file = "pydantic-1.10.21-cp38-cp38-win_amd64.whl", hash = "sha256:b8460bc256bf0de821839aea6794bb38a4c0fbd48f949ea51093f6edce0be459"}, + {file = "pydantic-1.10.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d387940f0f1a0adb3c44481aa379122d06df8486cc8f652a7b3b0caf08435f7"}, + {file = "pydantic-1.10.21-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:266ecfc384861d7b0b9c214788ddff75a2ea123aa756bcca6b2a1175edeca0fe"}, + {file = "pydantic-1.10.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61da798c05a06a362a2f8c5e3ff0341743e2818d0f530eaac0d6898f1b187f1f"}, + {file = "pydantic-1.10.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a621742da75ce272d64ea57bd7651ee2a115fa67c0f11d66d9dcfc18c2f1b106"}, + {file = "pydantic-1.10.21-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9e3e4000cd54ef455694b8be9111ea20f66a686fc155feda1ecacf2322b115da"}, + {file = "pydantic-1.10.21-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f198c8206640f4c0ef5a76b779241efb1380a300d88b1bce9bfe95a6362e674d"}, + {file = "pydantic-1.10.21-cp39-cp39-win_amd64.whl", hash = "sha256:e7f0cda108b36a30c8fc882e4fc5b7eec8ef584aa43aa43694c6a7b274fb2b56"}, + {file = "pydantic-1.10.21-py3-none-any.whl", hash = "sha256:db70c920cba9d05c69ad4a9e7f8e9e83011abb2c6490e561de9ae24aee44925c"}, + {file = "pydantic-1.10.21.tar.gz", hash = "sha256:64b48e2b609a6c22178a56c408ee1215a7206077ecb8a193e2fda31858b2362a"}, ] [package.dependencies] @@ -2671,13 +2725,13 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygments" -version = "2.18.0" +version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = true python-versions = ">=3.8" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, ] [package.extras] @@ -2710,38 +2764,42 @@ dev = ["build", "flake8", "mypy", "pytest", "twine"] [[package]] name = "pysam" -version = "0.22.1" +version = "0.23.0" description = "Package for reading, manipulating, and writing genomic data" optional = true python-versions = ">=3.6" files = [ - {file = "pysam-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f18e72013ef2db9a9bb7e8ac421934d054427f6c03e66ce8abc39b09c846ba72"}, - {file = "pysam-0.22.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:79cd94eeb96541385fa99e759a8f83d21428e092c8b577d50b4eee5823e757cd"}, - {file = "pysam-0.22.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c71ea45461ee596949061f321a799a97c418164485fdd7e8db89aea2ff979092"}, - {file = "pysam-0.22.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ab3343f221994d163e1ba2691430ce0f6e7da13762473e0d7f9a2d5db3bec235"}, - {file = "pysam-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:503c833e6cf348d87aec9113b1386d5c85c031d64deb914c29f5ad1792d103e6"}, - {file = "pysam-0.22.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4447fdc2630519a00b6bf598995f1440e6f398eb0c084a7c141db026990ae07a"}, - {file = "pysam-0.22.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:1be663a73cf56ddd1d309b91d314a0c94c9bf352eaa3c6eda30cef12699843f0"}, - {file = "pysam-0.22.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:aeb31472365014fd8b37da4a88af758094b5872a8a16a25635a52cf8ceff5a9f"}, - {file = "pysam-0.22.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e72e129d245574801125029a5892c9e18d2956b13c4203ea585cbd64ccde9351"}, - {file = "pysam-0.22.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f8f00bb1fb977fc33c87cf5fe9023eefc2ba3d43d30ab4875a1765827018c949"}, - {file = "pysam-0.22.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c0e051fda433c1c7ff94532f60477bb83b97f4bb183567a0ae23f340e1c200b4"}, - {file = "pysam-0.22.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:860c7c78ddb1539b83d5476502ba14c8b4e8435810dc7a5b715196da3dfb86b6"}, - {file = "pysam-0.22.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:18d886d50d75d8f853057fbbb284f0f0e98afad1f76b1a6f55660ea167d31c17"}, - {file = "pysam-0.22.1-cp36-cp36m-manylinux_2_28_aarch64.whl", hash = "sha256:44420290a619c02da48ca0956548eb82a1665ae97b6ee69c094f9da5a6206431"}, - {file = "pysam-0.22.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:acff506c921af36f364c5a87f3a30b3c105ebeb270d0e821c2ca571eaf60ca20"}, - {file = "pysam-0.22.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:098e0bf12d8b0399613065843310c91ba31a02d014b1f6b4e9d7f2d0d1254ff8"}, - {file = "pysam-0.22.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:cd9d457063272df16136640515183ea501bf3371f140a134b2f0a42f425a37d9"}, - {file = "pysam-0.22.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:af9fb53157ba2431b7b20a550c0223f4a039304c9f180d8da98ea9d2d3ef3fbf"}, - {file = "pysam-0.22.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d3fd6fe5aca79933632f38e5b568ce8d4e67e5c4f3bd39bff55fd9646af814d2"}, - {file = "pysam-0.22.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6cf1871c99cfc9c01261ec5f628519c2c889f0ff070e7a26aa5adbf9f69af1"}, - {file = "pysam-0.22.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b1addca11c5cfceefaebdfcf3d83bc42f4b89fb1e8ae645a4bdab971cbcd2bc0"}, - {file = "pysam-0.22.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:17fac22fc89c86241a71084ca097878c61c97f6ff5fd4535d718681a849852a7"}, - {file = "pysam-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4aff9b41856d5dba6585ffd60884b8f3778c5d2688f33989662aabe7f4cd0fe0"}, - {file = "pysam-0.22.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faa5298291b54f185c7b8f84510224918bddc64bbdcb2e8426ff43e83452310f"}, - {file = "pysam-0.22.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:4dfae1de006d1c6491a59b00052a3f67c53a136165cf4edd7789b5dcb1e6806f"}, - {file = "pysam-0.22.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:78ed746a39c9cebe489b8f0f86cf23c09c942e76c901260fb2794906e4cd0e26"}, - {file = "pysam-0.22.1.tar.gz", hash = "sha256:18a0b97be95bd71e584de698441c46651cdff378db1c9a4fb3f541e560253b22"}, + {file = "pysam-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ee2ef5f3452bc84834163a881269efed56d1be5045865b5af74d010aee4b44c"}, + {file = "pysam-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a061857f8bd723f0f223ec986b0b955f28ddea3b330a767f3c39daaca5908e39"}, + {file = "pysam-0.23.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:2ed8717c12580e76b9656af231c03254bb745bf1afc6d6556d0a27626443c48d"}, + {file = "pysam-0.23.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e681d04efe21040b3888f7484f84a2636433503cfb903bbf9b91d671726ceaed"}, + {file = "pysam-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ada6096aca1f188289832d7963137d5e9ffe9454d688c57a2cca563de4601545"}, + {file = "pysam-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:caf8f1cef87663d38228b01885f8ffb13d6a9bc2ba3ff958f79d6c1af3fb84c2"}, + {file = "pysam-0.23.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:81dc7b4418d6006ff3e16e5419f5d26a25d959efc1e9807cf56190ca0f68012a"}, + {file = "pysam-0.23.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4923c614adf642ffc7620a76faf38f57f2d834b1ba4ab567596db2ac6266038f"}, + {file = "pysam-0.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5a795db60b648902d1886faf9d3575dbd3f199736fda27504b8237b684b74710"}, + {file = "pysam-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e454f282f6ace01c5c293e3f1bc4bb2ee844f6d5b8686bffe7e02d7e0089a73e"}, + {file = "pysam-0.23.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:4f1b976bff84b99acb90276f396e7853359a8ea3a2a5fbcb69f3ceed4027761d"}, + {file = "pysam-0.23.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4fd54bae72a832317aab23ad45970f9091ac2c7c233c5a6826941095fbd7f103"}, + {file = "pysam-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b13eb322ad3726b214df3fe54249af5d91bfca6e4a64abe9f293348edae397e8"}, + {file = "pysam-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41272520d47a428c4d17441eab88d7c5b1ad609ba729cc0cd96960b8a8589e93"}, + {file = "pysam-0.23.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e0426928e676e5d9f8320cd09741be905f90be5c7133f3ad386c7d1be84930ff"}, + {file = "pysam-0.23.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1631c173363475c409352d9bf3ad96e7ff851ba903e5b979f55330f0b41d9b5d"}, + {file = "pysam-0.23.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2572519dc4b668e8e45d38335233e119cc93fa671fa03099e6f651be032370a6"}, + {file = "pysam-0.23.0-cp36-cp36m-manylinux_2_28_aarch64.whl", hash = "sha256:338d7e292f76d157ba2c7bb3ccdd9a071f164b44250ea89672b4946e3518146f"}, + {file = "pysam-0.23.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:e32afcd92a6686696147bbad7e7a8d779791e495a9f1ab814daba5e211659716"}, + {file = "pysam-0.23.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e3616d3e0a86a87cfde1e89896315961a7a409170dca038c24a756309c8e0d5"}, + {file = "pysam-0.23.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:86c5ce45690348dcd11dfe7163624ba18dd945ba57d7a064593b78ddcb8e3e72"}, + {file = "pysam-0.23.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:45abd654f6f53e938238bb9472a7c0b992c384c0bef7e51f248b0502c99964b1"}, + {file = "pysam-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ab8d993dbbe5af916f1b5f0dac00705a1fa20185b64ed9f3dd66d15850338c65"}, + {file = "pysam-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a0ef49772d4546b2a75f0448b91cf9b9e6d4124bda8747e891383570d51b50e"}, + {file = "pysam-0.23.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:4e00a02e9d5e34902c90817d742c58862493b57ccb70144927869d28a91accfc"}, + {file = "pysam-0.23.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3e1e12d078f3780173ee34990ba737427768fb332d3a1910aae5fb32bb2499fa"}, + {file = "pysam-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0bb793bd7fcabb416991607877fe4dfdc7109f73256ed5d2e1e7ed4a68c39167"}, + {file = "pysam-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd936bdd2a2a7412e96a0797da052d7a50745f0254a934ee590d10485776be58"}, + {file = "pysam-0.23.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:03f50e567ccbac028aec7ce5edc1d4962489cfd5eeeee423ca276abe01dc0a24"}, + {file = "pysam-0.23.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:79201b1ed82308540e7be69de9f73719e381f45d9e0e6310a46c6e56092967b2"}, + {file = "pysam-0.23.0.tar.gz", hash = "sha256:81488b3c7e0efc614395e21acde8bdb21c7adafea31736e733173ac7afac0c3e"}, ] [[package]] @@ -2898,24 +2956,24 @@ files = [ [[package]] name = "python-multipart" -version = "0.0.12" +version = "0.0.20" description = "A streaming multipart parser for Python" optional = true python-versions = ">=3.8" files = [ - {file = "python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf"}, - {file = "python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb"}, + {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, + {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, ] [[package]] name = "pytz" -version = "2024.2" +version = "2025.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, - {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, + {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, + {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, ] [[package]] @@ -3001,18 +3059,19 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "referencing" -version = "0.35.1" +version = "0.36.2" description = "JSON Referencing + Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, + {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, + {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, ] [package.dependencies] attrs = ">=22.2.0" rpds-py = ">=0.7.0" +typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "requests" @@ -3056,114 +3115,114 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "rpds-py" -version = "0.20.0" +version = "0.23.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, - {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, - {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, - {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, - {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, - {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, - {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, - {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, - {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, - {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, - {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, - {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, - {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, - {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, - {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, + {file = "rpds_py-0.23.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed"}, + {file = "rpds_py-0.23.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d"}, + {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8"}, + {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5"}, + {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f"}, + {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a"}, + {file = "rpds_py-0.23.1-cp310-cp310-win32.whl", hash = "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12"}, + {file = "rpds_py-0.23.1-cp310-cp310-win_amd64.whl", hash = "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda"}, + {file = "rpds_py-0.23.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590"}, + {file = "rpds_py-0.23.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522"}, + {file = "rpds_py-0.23.1-cp311-cp311-win32.whl", hash = "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6"}, + {file = "rpds_py-0.23.1-cp311-cp311-win_amd64.whl", hash = "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf"}, + {file = "rpds_py-0.23.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c"}, + {file = "rpds_py-0.23.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad"}, + {file = "rpds_py-0.23.1-cp312-cp312-win32.whl", hash = "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057"}, + {file = "rpds_py-0.23.1-cp312-cp312-win_amd64.whl", hash = "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165"}, + {file = "rpds_py-0.23.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935"}, + {file = "rpds_py-0.23.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93"}, + {file = "rpds_py-0.23.1-cp313-cp313-win32.whl", hash = "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd"}, + {file = "rpds_py-0.23.1-cp313-cp313-win_amd64.whl", hash = "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70"}, + {file = "rpds_py-0.23.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731"}, + {file = "rpds_py-0.23.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5"}, + {file = "rpds_py-0.23.1-cp313-cp313t-win32.whl", hash = "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7"}, + {file = "rpds_py-0.23.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d"}, + {file = "rpds_py-0.23.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19"}, + {file = "rpds_py-0.23.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a"}, + {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce"}, + {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07"}, + {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4"}, + {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f"}, + {file = "rpds_py-0.23.1-cp39-cp39-win32.whl", hash = "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495"}, + {file = "rpds_py-0.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4"}, + {file = "rpds_py-0.23.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3"}, + {file = "rpds_py-0.23.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00"}, + {file = "rpds_py-0.23.1.tar.gz", hash = "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707"}, ] [[package]] @@ -3209,13 +3268,13 @@ files = [ [[package]] name = "s3transfer" -version = "0.10.3" +version = "0.10.4" description = "An Amazon S3 Transfer Manager" optional = true python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d"}, - {file = "s3transfer-0.10.3.tar.gz", hash = "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c"}, + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, ] [package.dependencies] @@ -3226,152 +3285,152 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "setuptools" -version = "75.2.0" +version = "76.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6"}, + {file = "setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "simplejson" -version = "3.19.3" +version = "3.20.1" description = "Simple, fast, extensible JSON encoder/decoder for Python" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" files = [ - {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f39caec26007a2d0efab6b8b1d74873ede9351962707afab622cc2285dd26ed0"}, - {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:83c87706265ae3028e8460d08b05f30254c569772e859e5ba61fe8af2c883468"}, - {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0b5ddd2c7d1d3f4d23224bc8a04bbf1430ae9a8149c05b90f8fc610f7f857a23"}, - {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ad0e0b1ce9bd3edb5cf64b5b5b76eacbfdac8c5367153aeeec8a8b1407f68342"}, - {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:93be280fc69a952c76e261036312c20b910e7fa9e234f1d89bdfe3fa34f8a023"}, - {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6d43e24b88c80f997081503f693be832fc90854f278df277dd54f8a4c847ab61"}, - {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2876027ebdd599d730d36464debe84619b0368e9a642ca6e7c601be55aed439e"}, - {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:0766ca6222b410e08e0053a0dda3606cafb3973d5d00538307f631bb59743396"}, - {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50d8b742d74c449c4dcac570d08ce0f21f6a149d2d9cf7652dbf2ba9a1bc729a"}, - {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd011fc3c1d88b779645495fdb8189fb318a26981eebcce14109460e062f209b"}, - {file = "simplejson-3.19.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:637c4d4b81825c1f4d651e56210bd35b5604034b192b02d2d8f17f7ce8c18f42"}, - {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f56eb03bc9e432bb81adc8ecff2486d39feb371abb442964ffb44f6db23b332"}, - {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef59a53be400c1fad2c914b8d74c9d42384fed5174f9321dd021b7017fd40270"}, - {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72e8abbc86fcac83629a030888b45fed3a404d54161118be52cb491cd6975d3e"}, - {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8efb03ca77bd7725dfacc9254df00d73e6f43013cf39bd37ef1a8ed0ebb5165"}, - {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:add8850db04b98507a8b62d248a326ecc8561e6d24336d1ca5c605bbfaab4cad"}, - {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fc3dc9fb413fc34c396f52f4c87de18d0bd5023804afa8ab5cc224deeb6a9900"}, - {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dfa420bb9225dd33b6efdabde7c6a671b51150b9b1d9c4e5cd74d3b420b3fe1"}, - {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7b5c472099b39b274dcde27f1113db8d818c9aa3ba8f78cbb8ad04a4c1ac2118"}, - {file = "simplejson-3.19.3-cp310-cp310-win32.whl", hash = "sha256:817abad79241ed4a507b3caf4d3f2be5079f39d35d4c550a061988986bffd2ec"}, - {file = "simplejson-3.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:dd5b9b1783e14803e362a558680d88939e830db2466f3fa22df5c9319f8eea94"}, - {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e88abff510dcff903a18d11c2a75f9964e768d99c8d147839913886144b2065e"}, - {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:934a50a614fb831614db5dbfba35127ee277624dda4d15895c957d2f5d48610c"}, - {file = "simplejson-3.19.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:212fce86a22188b0c7f53533b0f693ea9605c1a0f02c84c475a30616f55a744d"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d9e8f836688a8fabe6a6b41b334aa550a6823f7b4ac3d3712fc0ad8655be9a8"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23228037dc5d41c36666384062904d74409a62f52283d9858fa12f4c22cffad1"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0791f64fed7d4abad639491f8a6b1ba56d3c604eb94b50f8697359b92d983f36"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f614581b61a26fbbba232a1391f6cee82bc26f2abbb6a0b44a9bba25c56a1c"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1df0aaf1cb787fdf34484ed4a1f0c545efd8811f6028623290fef1a53694e597"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:951095be8d4451a7182403354c22ec2de3e513e0cc40408b689af08d02611588"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a954b30810988feeabde843e3263bf187697e0eb5037396276db3612434049b"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c40df31a75de98db2cdfead6074d4449cd009e79f54c1ebe5e5f1f153c68ad20"}, - {file = "simplejson-3.19.3-cp311-cp311-win32.whl", hash = "sha256:7e2a098c21ad8924076a12b6c178965d88a0ad75d1de67e1afa0a66878f277a5"}, - {file = "simplejson-3.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:c9bedebdc5fdad48af8783022bae307746d54006b783007d1d3c38e10872a2c6"}, - {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:66a0399e21c2112acacfebf3d832ebe2884f823b1c7e6d1363f2944f1db31a99"}, - {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6ef9383c5e05f445be60f1735c1816163c874c0b1ede8bb4390aff2ced34f333"}, - {file = "simplejson-3.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42e5acf80d4d971238d4df97811286a044d720693092b20a56d5e56b7dcc5d09"}, - {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0b0efc7279d768db7c74d3d07f0b5c81280d16ae3fb14e9081dc903e8360771"}, - {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0552eb06e7234da892e1d02365cd2b7b2b1f8233aa5aabdb2981587b7cc92ea0"}, - {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf6a3b9a7d7191471b464fe38f684df10eb491ec9ea454003edb45a011ab187"}, - {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7017329ca8d4dca94ad5e59f496e5fc77630aecfc39df381ffc1d37fb6b25832"}, - {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67a20641afebf4cfbcff50061f07daad1eace6e7b31d7622b6fa2c40d43900ba"}, - {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd6a7dabcc4c32daf601bc45e01b79175dde4b52548becea4f9545b0a4428169"}, - {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:08f9b443a94e72dd02c87098c96886d35790e79e46b24e67accafbf13b73d43b"}, - {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa97278ae6614346b5ca41a45a911f37a3261b57dbe4a00602048652c862c28b"}, - {file = "simplejson-3.19.3-cp312-cp312-win32.whl", hash = "sha256:ef28c3b328d29b5e2756903aed888960bc5df39b4c2eab157ae212f70ed5bf74"}, - {file = "simplejson-3.19.3-cp312-cp312-win_amd64.whl", hash = "sha256:1e662336db50ad665777e6548b5076329a94a0c3d4a0472971c588b3ef27de3a"}, - {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0959e6cb62e3994b5a40e31047ff97ef5c4138875fae31659bead691bed55896"}, - {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a7bfad839c624e139a4863007233a3f194e7c51551081f9789cba52e4da5167"}, - {file = "simplejson-3.19.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afab2f7f2486a866ff04d6d905e9386ca6a231379181a3838abce1f32fbdcc37"}, - {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00313681015ac498e1736b304446ee6d1c72c5b287cd196996dad84369998f7"}, - {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d936ae682d5b878af9d9eb4d8bb1fdd5e41275c8eb59ceddb0aeed857bb264a2"}, - {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c6657485393f2e9b8177c77a7634f13ebe70d5e6de150aae1677d91516ce6b"}, - {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a6a750d3c7461b1c47cfc6bba8d9e57a455e7c5f80057d2a82f738040dd1129"}, - {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ea7a4a998c87c5674a27089e022110a1a08a7753f21af3baf09efe9915c23c3c"}, - {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6300680d83a399be2b8f3b0ef7ef90b35d2a29fe6e9c21438097e0938bbc1564"}, - {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ab69f811a660c362651ae395eba8ce84f84c944cea0df5718ea0ba9d1e4e7252"}, - {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:256e09d0f94d9c3d177d9e95fd27a68c875a4baa2046633df387b86b652f5747"}, - {file = "simplejson-3.19.3-cp313-cp313-win32.whl", hash = "sha256:2c78293470313aefa9cfc5e3f75ca0635721fb016fb1121c1c5b0cb8cc74712a"}, - {file = "simplejson-3.19.3-cp313-cp313-win_amd64.whl", hash = "sha256:3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c"}, - {file = "simplejson-3.19.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:89b35433186e977fa86ff1fd179c1fadff39cfa3afa1648dab0b6ca53153acd9"}, - {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d43c2d7504eda566c50203cdc9dc043aff6f55f1b7dae0dcd79dfefef9159d1c"}, - {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6890ff9cf0bd2e1d487e2a8869ebd620a44684c0a9667fa5ee751d099d5d84c8"}, - {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1069143a8fb3905e1bc0696c62be7e3adf812e9f1976ac9ae15b05112ff57cc9"}, - {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb324bb903330cbb35d87cce367a12631cd5720afa06e5b9c906483970946da6"}, - {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:0a32859d45d7b85fb803bb68f6bee14526991a1190269116c33399fa0daf9bbf"}, - {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:23833ee7e791ec968b744dfee2a2d39df7152050051096caf4296506d75608d8"}, - {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:d73efb03c5b39249c82488a994f0998f9e4399e3d085209d2120503305ba77a8"}, - {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7923878b7a0142d39763ec2dbecff3053c1bedd3653585a8474666e420fe83f5"}, - {file = "simplejson-3.19.3-cp36-cp36m-win32.whl", hash = "sha256:7355c7203353c36d46c4e7b6055293b3d2be097bbc5e2874a2b8a7259f0325dd"}, - {file = "simplejson-3.19.3-cp36-cp36m-win_amd64.whl", hash = "sha256:d1b8b4d6379fe55f471914345fe6171d81a18649dacf3248abfc9c349b4442eb"}, - {file = "simplejson-3.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d36608557b4dcd7a62c29ad4cd7c5a1720bbf7dc942eff9dc42d2c542a5f042d"}, - {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7137e69c6781ecf23afab064be94a277236c9cba31aa48ff1a0ec3995c69171e"}, - {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76f8c28fe2d426182405b18ddf3001fce47835a557dc15c3d8bdea01c03361da"}, - {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff7bc1bbdaa3e487c9469128bf39408e91f5573901cb852e03af378d3582c52d"}, - {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0782cb9bf827f0c488b6aa0f2819f618308a3caf2973cfd792e45d631bec4db"}, - {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:6fea0716c593dabb4392c4996d4e902a83b2428e6da82938cf28a523a11eb277"}, - {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:8f41bb5370b34f63171e65fdb00e12be1d83675cecb23e627df26f4c88dfc021"}, - {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:37105d1d708365b91165e1a6e505bdecc88637091348cf4b6adcdcb4f5a5fb8b"}, - {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:b9198c1f1f8910a3b86b60f4fe2556d9d28d3fefe35bffe6be509a27402e694d"}, - {file = "simplejson-3.19.3-cp37-cp37m-win32.whl", hash = "sha256:bc164f32dd9691e7082ce5df24b4cf8c6c394bbf9bdeeb5d843127cd07ab8ad2"}, - {file = "simplejson-3.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1bd41f2cb1a2c57656ceff67b12d005cb255c728265e222027ad73193a04005a"}, - {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0733ecd95ae03ae718ec74aad818f5af5f3155d596f7b242acbc1621e765e5fb"}, - {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a0710d1a5e41c4f829caa1572793dd3130c8d65c2b194c24ff29c4c305c26e0"}, - {file = "simplejson-3.19.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a53a07320c5ff574d8b1a89c937ce33608832f166f39dff0581ac43dc979abd"}, - {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1773cabfba66a6337b547e45dafbd471b09487370bcab75bd28f626520410d29"}, - {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c0104b4b7d2c75ccedbf1d9d5a3bd2daa75e51053935a44ba012e2fd4c43752"}, - {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c49eeb94b8f09dc8a5843c156a22b8bde6aa1ddc65ca8ddc62dddcc001e6a2d"}, - {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dc5c1a85ff388e98ea877042daec3d157b6db0d85bac6ba5498034689793e7e"}, - {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:49549e3d81ab4a58424405aa545602674d8c35c20e986b42bb8668e782a94bac"}, - {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:e1a1452ad5723ff129b081e3c8aa4ba56b8734fee4223355ed7b815a7ece69bc"}, - {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:d0d5a63f1768fed7e78cf55712dee81f5a345e34d34224f3507ebf71df2b754d"}, - {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7e062767ac165df9a46963f5735aa4eee0089ec1e48b3f2ec46182754b96f55e"}, - {file = "simplejson-3.19.3-cp38-cp38-win32.whl", hash = "sha256:56134bbafe458a7b21f6fddbf889d36bec6d903718f4430768e3af822f8e27c2"}, - {file = "simplejson-3.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:bcde83a553a96dc7533736c547bddaa35414a2566ab0ecf7d3964fc4bdb84c11"}, - {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b5587feda2b65a79da985ae6d116daf6428bf7489992badc29fc96d16cd27b05"}, - {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0d2b00ecbcd1a3c5ea1abc8bb99a26508f758c1759fd01c3be482a3655a176f"}, - {file = "simplejson-3.19.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32a3ada8f3ea41db35e6d37b86dade03760f804628ec22e4fe775b703d567426"}, - {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f455672f4738b0f47183c5896e3606cd65c9ddee3805a4d18e8c96aa3f47c84"}, - {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b737a5fefedb8333fa50b8db3dcc9b1d18fd6c598f89fa7debff8b46bf4e511"}, - {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb47ee773ce67476a960e2db4a0a906680c54f662521550828c0cc57d0099426"}, - {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eed8cd98a7b24861da9d3d937f5fbfb6657350c547528a117297fe49e3960667"}, - {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:619756f1dd634b5bdf57d9a3914300526c3b348188a765e45b8b08eabef0c94e"}, - {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dd7230d061e755d60a4d5445bae854afe33444cdb182f3815cff26ac9fb29a15"}, - {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:101a3c8392028cd704a93c7cba8926594e775ca3c91e0bee82144e34190903f1"}, - {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e557712fc79f251673aeb3fad3501d7d4da3a27eff0857af2e1d1afbbcf6685"}, - {file = "simplejson-3.19.3-cp39-cp39-win32.whl", hash = "sha256:0bc5544e3128891bf613b9f71813ee2ec9c11574806f74dd8bb84e5e95bf64a2"}, - {file = "simplejson-3.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:06662392e4913dc8846d6a71a6d5de86db5fba244831abe1dd741d62a4136764"}, - {file = "simplejson-3.19.3-py3-none-any.whl", hash = "sha256:49cc4c7b940d43bd12bf87ec63f28cbc4964fc4e12c031cc8cd01650f43eb94e"}, - {file = "simplejson-3.19.3.tar.gz", hash = "sha256:8e086896c36210ab6050f2f9f095a5f1e03c83fa0e7f296d6cba425411364680"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f5272b5866b259fe6c33c4a8c5073bf8b359c3c97b70c298a2f09a69b52c7c41"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5c0de368f3052a59a1acf21f8b2dd28686a9e4eba2da7efae7ed9554cb31e7bc"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0821871404a537fd0e22eba240c74c0467c28af6cc435903eca394cfc74a0497"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c939a1e576bded47d7d03aa2afc2ae90b928b2cf1d9dc2070ceec51fd463f430"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3c4f0a61cdc05550782ca4a2cdb311ea196c2e6be6b24a09bf71360ca8c3ca9b"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6c21f5c026ca633cfffcb6bc1fac2e99f65cb2b24657d3bef21aed9916cc3bbf"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:8d23b7f8d6b72319d6d55a0261089ff621ce87e54731c2d3de6a9bf7be5c028c"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:cda5c32a98f392909088111ecec23f2b0d39346ceae1a0fea23ab2d1f84ec21d"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e580aa65d5f6c3bf41b9b4afe74be5d5ddba9576701c107c772d936ea2b5043a"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a586ce4f78cec11f22fe55c5bee0f067e803aab9bad3441afe2181693b5ebb5"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74a1608f9e6e8c27a4008d70a54270868306d80ed48c9df7872f9f4b8ac87808"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03db8cb64154189a92a7786209f24e391644f3a3fa335658be2df2af1960b8d8"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eea7e2b7d858f6fdfbf0fe3cb846d6bd8a45446865bc09960e51f3d473c2271b"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e66712b17d8425bb7ff8968d4c7c7fd5a2dd7bd63728b28356223c000dd2f91f"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2cc4f6486f9f515b62f5831ff1888886619b84fc837de68f26d919ba7bbdcbc"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3c2df555ee4016148fa192e2b9cd9e60bc1d40769366134882685e90aee2a1e"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:78520f04b7548a5e476b5396c0847e066f1e0a4c0c5e920da1ad65e95f410b11"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f4bd49ecde87b0fe9f55cc971449a32832bca9910821f7072bbfae1155eaa007"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7eaae2b88eb5da53caaffdfa50e2e12022553949b88c0df4f9a9663609373f72"}, + {file = "simplejson-3.20.1-cp310-cp310-win32.whl", hash = "sha256:e836fb88902799eac8debc2b642300748f4860a197fa3d9ea502112b6bb8e142"}, + {file = "simplejson-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a19b552b212fc3b5b96fc5ce92333d4a9ac0a800803e1f17ebb16dac4be5"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:325b8c107253d3217e89d7b50c71015b5b31e2433e6c5bf38967b2f80630a8ca"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88a7baa8211089b9e58d78fbc1b0b322103f3f3d459ff16f03a36cece0d0fcf0"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:299b1007b8101d50d95bc0db1bf5c38dc372e85b504cf77f596462083ee77e3f"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ec618ed65caab48e81e3ed29586236a8e57daef792f1f3bb59504a7e98cd10"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2cdead1d3197f0ff43373cf4730213420523ba48697743e135e26f3d179f38"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3466d2839fdc83e1af42e07b90bc8ff361c4e8796cd66722a40ba14e458faddd"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d492ed8e92f3a9f9be829205f44b1d0a89af6582f0cf43e0d129fa477b93fe0c"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f924b485537b640dc69434565463fd6fc0c68c65a8c6e01a823dd26c9983cf79"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e8eacf6a3491bf76ea91a8d46726368a6be0eb94993f60b8583550baae9439e"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d04bf90b4cea7c22d8b19091633908f14a096caa301b24c2f3d85b5068fb8"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:69dd28d4ce38390ea4aaf212902712c0fd1093dc4c1ff67e09687c3c3e15a749"}, + {file = "simplejson-3.20.1-cp311-cp311-win32.whl", hash = "sha256:dfe7a9da5fd2a3499436cd350f31539e0a6ded5da6b5b3d422df016444d65e43"}, + {file = "simplejson-3.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:896a6c04d7861d507d800da7642479c3547060bf97419d9ef73d98ced8258766"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f31c4a3a7ab18467ee73a27f3e59158255d1520f3aad74315edde7a940f1be23"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884e6183d16b725e113b83a6fc0230152ab6627d4d36cb05c89c2c5bccfa7bc6"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03d7a426e416fe0d3337115f04164cd9427eb4256e843a6b8751cacf70abc832"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000602141d0bddfcff60ea6a6e97d5e10c9db6b17fd2d6c66199fa481b6214bb"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af8377a8af78226e82e3a4349efdde59ffa421ae88be67e18cef915e4023a595"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15c7de4c88ab2fbcb8781a3b982ef883696736134e20b1210bca43fb42ff1acf"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:455a882ff3f97d810709f7b620007d4e0aca8da71d06fc5c18ba11daf1c4df49"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fc0f523ce923e7f38eb67804bc80e0a028c76d7868500aa3f59225574b5d0453"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76461ec929282dde4a08061071a47281ad939d0202dc4e63cdd135844e162fbc"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19c2da8c043607bde4d4ef3a6b633e668a7d2e3d56f40a476a74c5ea71949f"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2578bedaedf6294415197b267d4ef678fea336dd78ee2a6d2f4b028e9d07be3"}, + {file = "simplejson-3.20.1-cp312-cp312-win32.whl", hash = "sha256:339f407373325a36b7fd744b688ba5bae0666b5d340ec6d98aebc3014bf3d8ea"}, + {file = "simplejson-3.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:627d4486a1ea7edf1f66bb044ace1ce6b4c1698acd1b05353c97ba4864ea2e17"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:71e849e7ceb2178344998cbe5ade101f1b329460243c79c27fbfc51c0447a7c3"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b63fdbab29dc3868d6f009a59797cefaba315fd43cd32ddd998ee1da28e50e29"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1190f9a3ce644fd50ec277ac4a98c0517f532cfebdcc4bd975c0979a9f05e1fb"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1336ba7bcb722ad487cd265701ff0583c0bb6de638364ca947bb84ecc0015d1"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e975aac6a5acd8b510eba58d5591e10a03e3d16c1cf8a8624ca177491f7230f0"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a6dd11ee282937ad749da6f3b8d87952ad585b26e5edfa10da3ae2536c73078"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab980fcc446ab87ea0879edad41a5c28f2d86020014eb035cf5161e8de4474c6"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f5aee2a4cb6b146bd17333ac623610f069f34e8f31d2f4f0c1a2186e50c594f0"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:652d8eecbb9a3b6461b21ec7cf11fd0acbab144e45e600c817ecf18e4580b99e"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8c09948f1a486a89251ee3a67c9f8c969b379f6ffff1a6064b41fea3bce0a112"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cbbd7b215ad4fc6f058b5dd4c26ee5c59f72e031dfda3ac183d7968a99e4ca3a"}, + {file = "simplejson-3.20.1-cp313-cp313-win32.whl", hash = "sha256:ae81e482476eaa088ef9d0120ae5345de924f23962c0c1e20abbdff597631f87"}, + {file = "simplejson-3.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:1b9fd15853b90aec3b1739f4471efbf1ac05066a2c7041bf8db821bb73cd2ddc"}, + {file = "simplejson-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c7edf279c1376f28bf41e916c015a2a08896597869d57d621f55b6a30c7e1e6d"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9202b9de38f12e99a40addd1a8d508a13c77f46d87ab1f9095f154667f4fe81"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:391345b4157cc4e120027e013bd35c45e2c191e2bf48b8913af488cdc3b9243c"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6fdcc9debb711ddd2ad6d69f9386a3d9e8e253234bbb30513e0a7caa9510c51"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9daf8cdc7ee8a9e9f7a3b313ba0a003391857e90d0e82fbcd4d614aa05cb7c3b"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:c02f4868a3a46ffe284a51a88d134dc96feff6079a7115164885331a1ba8ed9f"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:3d7310172d5340febd258cb147f46aae30ad57c445f4d7e1ae8461c10aaf43b0"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:4762e05577955312a4c6802f58dd02e040cc79ae59cda510aa1564d84449c102"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:8bb98fdf318c05aefd08a92583bd6ee148e93c6756fb1befb7b2d5f27824be78"}, + {file = "simplejson-3.20.1-cp36-cp36m-win32.whl", hash = "sha256:9a74e70818818981294b8e6956ce3496c5e1bd4726ac864fae473197671f7b85"}, + {file = "simplejson-3.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e041add470e8f8535cc05509485eb7205729a84441f03b25cde80ad48823792e"}, + {file = "simplejson-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e9d73f46119240e4f4f07868241749d67d09873f40cb968d639aa9ccc488b86"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae6e637dc24f8fee332ed23dd070e81394138e42cd4fd9d0923e5045ba122e27"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:efd3bc6c6b17e3d4620eb6be5196f0d1c08b6ce7c3101fa8e292b79e0908944b"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87fc623d457173a0213bc9ca4e346b83c9d443f63ed5cca847fb0cacea3cfc95"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec6a1e0a7aff76f0e008bebfa950188b9c50b58c1885d898145f48fc8e189a56"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:9c079606f461a6e950099167e21e13985147c8a24be8eea66c9ad68f73fad744"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:9faceb68fba27ef17eda306e4cd97a7b4b14fdadca5fbb15790ba8b26ebeec0c"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:7ceed598e4bacbf5133fe7a418f7991bb2df0683f3ac11fbf9e36a2bc7aa4b85"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ede69c765e9901861ad7c6139023b7b7d5807c48a2539d817b4ab40018002d5f"}, + {file = "simplejson-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:d8853c269a4c5146ddca4aa7c70e631795e9d11239d5fedb1c6bbc91ffdebcac"}, + {file = "simplejson-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ed6a17fd397f0e2b3ad668fc9e19253ed2e3875ad9086bd7f795c29a3223f4a1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7551682b60bba3a9e2780742e101cf0a64250e76de7d09b1c4b0c8a7c7cc6834"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd9577ec1c8c3a43040e3787711e4c257c70035b7551a21854b5dec88dad09e1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8e197e4cf6d42c2c57e7c52cd7c1e7b3e37c5911df1314fb393320131e2101"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bd09c8c75666e7f62a33d2f1fb57f81da1fcbb19a9fe7d7910b5756e1dd6048"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bd6bfe5678d73fbd5328eea6a35216503796428fc47f1237432522febaf3a0c"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b75d448fd0ceb2e7c90e72bb82c41f8462550d48529980bc0bab1d2495bfbb"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7e15b716d09f318c8cda3e20f82fae81684ce3d3acd1d7770fa3007df1769de"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3e7963197d958fcf9e98b212b80977d56c022384621ff463d98afc3b6b1ce7e8"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:2e671dd62051129185d3a9a92c60101f56cbc174854a1a3dfb69114ebd9e1699"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e25b2a0c396f3b84fb89573d07b0e1846ed563eb364f2ea8230ca92b8a8cb786"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:489c3a43116082bad56795215786313832ba3991cca1f55838e52a553f451ab6"}, + {file = "simplejson-3.20.1-cp38-cp38-win32.whl", hash = "sha256:4a92e948bad8df7fa900ba2ba0667a98303f3db206cbaac574935c332838208e"}, + {file = "simplejson-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:49d059b8363327eee3c94799dd96782314b2dbd7bcc293b4ad48db69d6f4d362"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a8011f1dd1d676befcd4d675ebdbfdbbefd3bf350052b956ba8c699fca7d8cef"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e91703a4c5fec53e36875ae426ad785f4120bd1d93b65bed4752eeccd1789e0c"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e39eaa57c7757daa25bcd21f976c46be443b73dd6c3da47fe5ce7b7048ccefe2"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceab2ce2acdc7fbaa433a93006758db6ba9a659e80c4faa13b80b9d2318e9b17"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d4f320c33277a5b715db5bf5b10dae10c19076bd6d66c2843e04bd12d1f1ea5"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b6436c48e64378fa844d8c9e58a5ed0352bbcfd4028369a9b46679b7ab79d2d"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e18345c8dda5d699be8166b61f9d80aaee4545b709f1363f60813dc032dac53"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:90b573693d1526bed576f6817e2a492eaaef68f088b57d7a9e83d122bbb49e51"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:272cc767826e924a6bd369ea3dbf18e166ded29059c7a4d64d21a9a22424b5b5"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:51b41f284d603c4380732d7d619f8b34bd04bc4aa0ed0ed5f4ffd0539b14da44"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e6697a3067d281f01de0fe96fc7cba4ea870d96d7deb7bfcf85186d74456503"}, + {file = "simplejson-3.20.1-cp39-cp39-win32.whl", hash = "sha256:6dd3a1d5aca87bf947f3339b0f8e8e329f1badf548bdbff37fac63c17936da8e"}, + {file = "simplejson-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:463f1fca8fbf23d088e5850fdd0dd4d5faea8900a9f9680270bd98fd649814ca"}, + {file = "simplejson-3.20.1-py3-none-any.whl", hash = "sha256:8a6c1bbac39fa4a79f83cbf1df6ccd8ff7069582a9fd8db1e52cea073bc2c697"}, + {file = "simplejson-3.20.1.tar.gz", hash = "sha256:e64139b4ec4f1f24c142ff7dcafe55a22b811a74d86d66560c8815687143037d"}, ] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -3424,72 +3483,72 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.36" +version = "2.0.39" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"}, - {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, - {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:66a40003bc244e4ad86b72abb9965d304726d05a939e8c09ce844d27af9e6d37"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:533e0f66c32093a987a30df3ad6ed21170db9d581d0b38e71396c49718fbb1ca"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:788b6ff6728072b313802be13e88113c33696a9a1f2f6d634a97c20f7ef5ccce"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-win32.whl", hash = "sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c"}, + {file = "SQLAlchemy-2.0.39-cp37-cp37m-win_amd64.whl", hash = "sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b761a6847f96fdc2d002e29e9e9ac2439c13b919adfd64e8ef49e75f6355c548"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d7e3866eb52d914aea50c9be74184a0feb86f9af8aaaa4daefe52b69378db0b"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344cd1ec2b3c6bdd5dfde7ba7e3b879e0f8dd44181f16b895940be9b842fd2b6"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3395e7ed89c6d264d38bea3bfb22ffe868f906a7985d03546ec7dc30221ea980"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-win32.whl", hash = "sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e"}, + {file = "SQLAlchemy-2.0.39-cp38-cp38-win_amd64.whl", hash = "sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-win32.whl", hash = "sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c"}, + {file = "sqlalchemy-2.0.39-cp310-cp310-win_amd64.whl", hash = "sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-win32.whl", hash = "sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e"}, + {file = "sqlalchemy-2.0.39-cp311-cp311-win_amd64.whl", hash = "sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2cf5b5ddb69142511d5559c427ff00ec8c0919a1e6c09486e9c32636ea2b9dd"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06205eb98cb3dd52133ca6818bf5542397f1dd1b69f7ea28aa84413897380b06"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-win32.whl", hash = "sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109"}, + {file = "sqlalchemy-2.0.39-cp312-cp312-win_amd64.whl", hash = "sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-win32.whl", hash = "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7"}, + {file = "sqlalchemy-2.0.39-cp313-cp313-win_amd64.whl", hash = "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2600a50d590c22d99c424c394236899ba72f849a02b10e65b4c70149606408b5"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4eff9c270afd23e2746e921e80182872058a7a592017b2713f33f96cc5f82e32"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125a7763b263218a80759ad9ae2f3610aaf2c2fbbd78fff088d584edf81f3782"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:805cb481474e111ee3687c9047c5f3286e62496f09c0e82e8853338aaaa348f8"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-win32.whl", hash = "sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70"}, + {file = "sqlalchemy-2.0.39-cp39-cp39-win_amd64.whl", hash = "sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a"}, + {file = "sqlalchemy-2.0.39-py3-none-any.whl", hash = "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f"}, + {file = "sqlalchemy-2.0.39.tar.gz", hash = "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} mypy = {version = ">=0.910", optional = true, markers = "extra == \"mypy\""} typing-extensions = ">=4.6.0" @@ -3520,13 +3579,13 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlparse" -version = "0.5.1" +version = "0.5.3" description = "A non-validating SQL parser." optional = true python-versions = ">=3.8" files = [ - {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, - {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, + {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, + {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, ] [package.extras] @@ -3600,31 +3659,62 @@ widechars = ["wcwidth"] [[package]] name = "tomli" -version = "2.0.2" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = true python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] @@ -3646,24 +3736,24 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "types-awscrt" -version = "0.22.0" +version = "0.24.1" description = "Type annotations and code completion for awscrt" optional = false python-versions = ">=3.8" files = [ - {file = "types_awscrt-0.22.0-py3-none-any.whl", hash = "sha256:b2c196bbd3226bab42d80fae13c34548de9ddc195f5a366d79c15d18e5897aa9"}, - {file = "types_awscrt-0.22.0.tar.gz", hash = "sha256:67a660c90bad360c339f6a79310cc17094d12472042c7ca5a41450aaf5fc9a54"}, + {file = "types_awscrt-0.24.1-py3-none-any.whl", hash = "sha256:f3f2578ff74a254a79882b95961fb493ba217cebc350b3eb239d1cd948d4d7fa"}, + {file = "types_awscrt-0.24.1.tar.gz", hash = "sha256:fc6eae56f8dc5a3f8cc93cc2c7c332fa82909f8284fbe25e014c575757af397d"}, ] [[package]] name = "types-pyasn1" -version = "0.6.0.20240913" +version = "0.6.0.20250208" description = "Typing stubs for pyasn1" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "types-pyasn1-0.6.0.20240913.tar.gz", hash = "sha256:a1da054db13d3d4ccfa69c515678154014336ad3d9f9ade01845f9edb1a2bc71"}, - {file = "types_pyasn1-0.6.0.20240913-py3-none-any.whl", hash = "sha256:95f3cb1fbd63ff91cd0410945f8aeae6b0be359533c00f39d8e17124884157af"}, + {file = "types_pyasn1-0.6.0.20250208-py3-none-any.whl", hash = "sha256:4a4fef8801efa983a88a1db52f6d7ac70cb1ad48abf25fad59134237603d5334"}, + {file = "types_pyasn1-0.6.0.20250208.tar.gz", hash = "sha256:14c6a0463555fb74ec81aca67ad2eb6d8409895359238511a3eceda7b5426235"}, ] [[package]] @@ -3682,24 +3772,24 @@ types-pyasn1 = "*" [[package]] name = "types-pytz" -version = "2024.2.0.20241003" +version = "2025.1.0.20250204" description = "Typing stubs for pytz" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "types-pytz-2024.2.0.20241003.tar.gz", hash = "sha256:575dc38f385a922a212bac00a7d6d2e16e141132a3c955078f4a4fd13ed6cb44"}, - {file = "types_pytz-2024.2.0.20241003-py3-none-any.whl", hash = "sha256:3e22df1336c0c6ad1d29163c8fda82736909eb977281cb823c57f8bae07118b7"}, + {file = "types_pytz-2025.1.0.20250204-py3-none-any.whl", hash = "sha256:32ca4a35430e8b94f6603b35beb7f56c32260ddddd4f4bb305fdf8f92358b87e"}, + {file = "types_pytz-2025.1.0.20250204.tar.gz", hash = "sha256:00f750132769f1c65a4f7240bc84f13985b4da774bd17dfbe5d9cd442746bd49"}, ] [[package]] name = "types-pyyaml" -version = "6.0.12.20240917" +version = "6.0.12.20241230" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.8" files = [ - {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"}, - {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"}, + {file = "types_PyYAML-6.0.12.20241230-py3-none-any.whl", hash = "sha256:fa4d32565219b68e6dee5f67534c722e53c00d1cfc09c435ef04d7353e1e96e6"}, + {file = "types_pyyaml-6.0.12.20241230.tar.gz", hash = "sha256:7f07622dbd34bb9c8b264fe860a17e0efcad00d50b5f27e93984909d9363498c"}, ] [[package]] @@ -3732,13 +3822,13 @@ urllib3 = ">=2" [[package]] name = "types-s3transfer" -version = "0.10.3" +version = "0.11.4" description = "Type annotations and code completion for s3transfer" optional = false python-versions = ">=3.8" files = [ - {file = "types_s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:d34c5a82f531af95bb550927136ff5b737a1ed3087f90a59d545591dfde5b4cc"}, - {file = "types_s3transfer-0.10.3.tar.gz", hash = "sha256:f761b2876ac4c208e6c6b75cdf5f6939009768be9950c545b11b0225e7703ee7"}, + {file = "types_s3transfer-0.11.4-py3-none-any.whl", hash = "sha256:2a76d92c07d4a3cb469e5343b2e7560e0b8078b2e03696a65407b8c44c861b61"}, + {file = "types_s3transfer-0.11.4.tar.gz", hash = "sha256:05fde593c84270f19fd053f0b1e08f5a057d7c5f036b9884e68fb8cd3041ac30"}, ] [[package]] @@ -3765,13 +3855,13 @@ files = [ [[package]] name = "tzdata" -version = "2024.2" +version = "2025.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, ] [[package]] @@ -3792,13 +3882,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -3809,20 +3899,20 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.32.0" +version = "0.34.0" description = "The lightning-fast ASGI server." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82"}, - {file = "uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e"}, + {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, + {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, ] [package.dependencies] click = ">=7.0" colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" -httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} @@ -3831,7 +3921,7 @@ watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standar websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "uvloop" @@ -3886,13 +3976,13 @@ test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", [[package]] name = "virtualenv" -version = "20.26.6" +version = "20.29.3" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, - {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, + {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, + {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, ] [package.dependencies] @@ -3906,94 +3996,82 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchfiles" -version = "0.24.0" +version = "1.0.4" description = "Simple, modern and high performance file watching and code reload in python." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "watchfiles-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0"}, - {file = "watchfiles-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188"}, - {file = "watchfiles-0.24.0-cp310-none-win32.whl", hash = "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735"}, - {file = "watchfiles-0.24.0-cp310-none-win_amd64.whl", hash = "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec"}, - {file = "watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d"}, - {file = "watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c"}, - {file = "watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968"}, - {file = "watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444"}, - {file = "watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896"}, - {file = "watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18"}, - {file = "watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07"}, - {file = "watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22"}, - {file = "watchfiles-0.24.0-cp38-none-win32.whl", hash = "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1"}, - {file = "watchfiles-0.24.0-cp38-none-win_amd64.whl", hash = "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e"}, - {file = "watchfiles-0.24.0-cp39-none-win32.whl", hash = "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da"}, - {file = "watchfiles-0.24.0-cp39-none-win_amd64.whl", hash = "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e"}, - {file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"}, + {file = "watchfiles-1.0.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ba5bb3073d9db37c64520681dd2650f8bd40902d991e7b4cfaeece3e32561d08"}, + {file = "watchfiles-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f25d0ba0fe2b6d2c921cf587b2bf4c451860086534f40c384329fb96e2044d1"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47eb32ef8c729dbc4f4273baece89398a4d4b5d21a1493efea77a17059f4df8a"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:076f293100db3b0b634514aa0d294b941daa85fc777f9c698adb1009e5aca0b1"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eacd91daeb5158c598fe22d7ce66d60878b6294a86477a4715154990394c9b3"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13c2ce7b72026cfbca120d652f02c7750f33b4c9395d79c9790b27f014c8a5a2"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90192cdc15ab7254caa7765a98132a5a41471cf739513cc9bcf7d2ffcc0ec7b2"}, + {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278aaa395f405972e9f523bd786ed59dfb61e4b827856be46a42130605fd0899"}, + {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a462490e75e466edbb9fc4cd679b62187153b3ba804868452ef0577ec958f5ff"}, + {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8d0d0630930f5cd5af929040e0778cf676a46775753e442a3f60511f2409f48f"}, + {file = "watchfiles-1.0.4-cp310-cp310-win32.whl", hash = "sha256:cc27a65069bcabac4552f34fd2dce923ce3fcde0721a16e4fb1b466d63ec831f"}, + {file = "watchfiles-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:8b1f135238e75d075359cf506b27bf3f4ca12029c47d3e769d8593a2024ce161"}, + {file = "watchfiles-1.0.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2a9f93f8439639dc244c4d2902abe35b0279102bca7bbcf119af964f51d53c19"}, + {file = "watchfiles-1.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eea33ad8c418847dd296e61eb683cae1c63329b6d854aefcd412e12d94ee235"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f1a379c9dcbb3f09cf6be1b7e83b67c0e9faabed0471556d9438a4a4e14202"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab594e75644421ae0a2484554832ca5895f8cab5ab62de30a1a57db460ce06c6"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2eb5d14a8e0d5df7b36288979176fbb39672d45184fc4b1c004d7c3ce29317"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f68d8e9d5a321163ddacebe97091000955a1b74cd43724e346056030b0bacee"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9ce064e81fe79faa925ff03b9f4c1a98b0bbb4a1b8c1b015afa93030cb21a49"}, + {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b77d5622ac5cc91d21ae9c2b284b5d5c51085a0bdb7b518dba263d0af006132c"}, + {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1941b4e39de9b38b868a69b911df5e89dc43767feeda667b40ae032522b9b5f1"}, + {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f8c4998506241dedf59613082d1c18b836e26ef2a4caecad0ec41e2a15e4226"}, + {file = "watchfiles-1.0.4-cp311-cp311-win32.whl", hash = "sha256:4ebbeca9360c830766b9f0df3640b791be569d988f4be6c06d6fae41f187f105"}, + {file = "watchfiles-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:05d341c71f3d7098920f8551d4df47f7b57ac5b8dad56558064c3431bdfc0b74"}, + {file = "watchfiles-1.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:32b026a6ab64245b584acf4931fe21842374da82372d5c039cba6bf99ef722f3"}, + {file = "watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2"}, + {file = "watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af"}, + {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a"}, + {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff"}, + {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e"}, + {file = "watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94"}, + {file = "watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c"}, + {file = "watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90"}, + {file = "watchfiles-1.0.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9"}, + {file = "watchfiles-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590"}, + {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902"}, + {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1"}, + {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303"}, + {file = "watchfiles-1.0.4-cp313-cp313-win32.whl", hash = "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80"}, + {file = "watchfiles-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc"}, + {file = "watchfiles-1.0.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d3452c1ec703aa1c61e15dfe9d482543e4145e7c45a6b8566978fbb044265a21"}, + {file = "watchfiles-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7b75fee5a16826cf5c46fe1c63116e4a156924d668c38b013e6276f2582230f0"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e997802d78cdb02623b5941830ab06f8860038faf344f0d288d325cc9c5d2ff"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0611d244ce94d83f5b9aff441ad196c6e21b55f77f3c47608dcf651efe54c4a"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9745a4210b59e218ce64c91deb599ae8775c8a9da4e95fb2ee6fe745fc87d01a"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4810ea2ae622add560f4aa50c92fef975e475f7ac4900ce5ff5547b2434642d8"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:740d103cd01458f22462dedeb5a3382b7f2c57d07ff033fbc9465919e5e1d0f3"}, + {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdbd912a61543a36aef85e34f212e5d2486e7c53ebfdb70d1e0b060cc50dd0bf"}, + {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0bc80d91ddaf95f70258cf78c471246846c1986bcc5fd33ccc4a1a67fcb40f9a"}, + {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab0311bb2ffcd9f74b6c9de2dda1612c13c84b996d032cd74799adb656af4e8b"}, + {file = "watchfiles-1.0.4-cp39-cp39-win32.whl", hash = "sha256:02a526ee5b5a09e8168314c905fc545c9bc46509896ed282aeb5a8ba9bd6ca27"}, + {file = "watchfiles-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:a5ae5706058b27c74bac987d615105da17724172d5aaacc6c362a40599b6de43"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdcc92daeae268de1acf5b7befcd6cfffd9a047098199056c72e4623f531de18"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8d3d9203705b5797f0af7e7e5baa17c8588030aaadb7f6a86107b7247303817"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdef5a1be32d0b07dcea3318a0be95d42c98ece24177820226b56276e06b63b0"}, + {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:342622287b5604ddf0ed2d085f3a589099c9ae8b7331df3ae9845571586c4f3d"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9fe37a2de80aa785d340f2980276b17ef697ab8db6019b07ee4fd28a8359d2f3"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9d1ef56b56ed7e8f312c934436dea93bfa3e7368adfcf3df4c0da6d4de959a1e"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b42cac65beae3a362629950c444077d1b44f1790ea2772beaea95451c086bb"}, + {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e0227b8ed9074c6172cf55d85b5670199c99ab11fd27d2c473aa30aec67ee42"}, + {file = "watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205"}, ] [package.dependencies] @@ -4040,97 +4118,80 @@ files = [ [[package]] name = "websockets" -version = "13.1" +version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, ] [[package]] @@ -4156,13 +4217,13 @@ pyodbc = ["pyodbc"] [[package]] name = "zipp" -version = "3.20.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -4174,9 +4235,9 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [extras] -server = ["alembic", "arq", "authlib", "biocommons", "boto3", "cdot", "cryptography", "fastapi", "hgvs", "orcid", "psycopg2", "python-jose", "python-multipart", "requests", "slack-sdk", "starlette", "starlette-context", "uvicorn", "watchtower"] +server = ["alembic", "alembic-utils", "arq", "authlib", "biocommons", "boto3", "cdot", "cryptography", "fastapi", "hgvs", "orcid", "psycopg2", "python-jose", "python-multipart", "requests", "slack-sdk", "starlette", "starlette-context", "uvicorn", "watchtower"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "ae56dc1a1a2c4b05f6374fd532267500028eb43f1c78ae9ca908f3b712868bec" +content-hash = "14d7a4b130c68372ffcf53f309375451eeda86bee1cbc0aad163819443e77e4b" diff --git a/pyproject.toml b/pyproject.toml index 7c8c6cf8..1e5b254c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ SQLAlchemy = "~2.0.0" # Optional dependencies for running this application as a server alembic = { version = "~1.7.6", optional = true } +alembic-utils = { version = "0.8.1", optional = true } arq = { version = "~0.25.0", optional = true } authlib = { version = "~1.3.1", optional = true } boto3 = { version = "~1.34.97", optional = true } @@ -85,7 +86,7 @@ SQLAlchemy = { extras = ["mypy"], version = "~2.0.0" } [tool.poetry.extras] -server = ["alembic", "arq", "authlib", "biocommons", "boto3", "cdot", "cryptography", "fastapi", "hgvs", "orcid", "psycopg2", "python-jose", "python-multipart", "requests", "starlette", "starlette-context", "slack-sdk", "uvicorn", "watchtower"] +server = ["alembic", "alembic-utils", "arq", "authlib", "biocommons", "boto3", "cdot", "cryptography", "fastapi", "hgvs", "orcid", "psycopg2", "python-jose", "python-multipart", "requests", "starlette", "starlette-context", "slack-sdk", "uvicorn", "watchtower"] [tool.mypy] From 4afc810c399610887f6512679aaa01da013fce87 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 03:06:23 -0700 Subject: [PATCH 13/20] Require refresh requests to provide an active session --- src/mavedb/db/view.py | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/mavedb/db/view.py b/src/mavedb/db/view.py index 3c64ee5c..37293a01 100644 --- a/src/mavedb/db/view.py +++ b/src/mavedb/db/view.py @@ -10,7 +10,6 @@ from sqlalchemy.orm import Session from mavedb.db.base import Base -from mavedb.db.session import SessionLocal # See: https://github.com/sqlalchemy/sqlalchemy/wiki/Views, https://github.com/jeffwidman/sqlalchemy-postgresql-materialized-views?tab=readme-ov-file @@ -32,9 +31,9 @@ class MaterializedView(Base): __abstract__ = True @classmethod - def refresh(cls, concurrently=True): + def refresh(cls, connection, concurrently=True): """Refresh this materialized view.""" - refresh_mat_view(cls.__table__.fullname, concurrently) + refresh_mat_view(connection, cls.__table__.fullname, concurrently) @compiler.compiles(CreateView) @@ -81,7 +80,12 @@ class MyView(Base): ) ``` - When registered in this manner, SQLAlchemy will create and destroy the view along with other tables. + When registered in this manner, SQLAlchemy will create and destroy the view along with other tables. You can + then query this view as if it were an ORM object. + + ``` + results = db.query(select(MyView.col1).where(MyView.col2)).all() + ``` """ t = sa.table( name, @@ -89,6 +93,7 @@ class MyView(Base): ) t.primary_key.update(c for c in t.c if c.primary_key) # type: ignore + # TODO: Figure out indices. if materialized: sa.event.listen( metadata, @@ -116,32 +121,23 @@ class MyView(Base): return t -# TODO: untested. -def refresh_mat_view(name, concurrently=True): +def refresh_mat_view(session, name, concurrently=True): """ Refreshes a single materialized view, given by `name`. """ - db = SessionLocal() - try: - # since session.execute() bypasses autoflush, must manually flush in order - # to include newly-created/modified objects in the refresh - db.flush() - _con = "CONCURRENTLY " if concurrently else "" - db.execute("REFRESH MATERIALIZED VIEW " + _con + name) - finally: - db.close() + # since session.execute() bypasses autoflush, must manually flush in order + # to include newly-created/modified objects in the refresh + session.flush() + _con = "CONCURRENTLY " if concurrently else "" + session.execute(sa.text("REFRESH MATERIALIZED VIEW " + _con + name)) # TODO: untested. -def refresh_all_mat_views(concurrently=True): +def refresh_all_mat_views(session, concurrently=True): """ Refreshes all materialized views. Views are refreshed in non-deterministic order, so view definitions can't depend on each other. """ - db = SessionLocal() - try: - mat_views = db.inspect(db.engine).get_view_names() - for v in mat_views: - refresh_mat_view(v, concurrently) - finally: - db.close() + mat_views = session.inspect(session.engine).get_view_names() + for v in mat_views: + refresh_mat_view(session, v, concurrently) From 4f53e686edd813310147b92f159f90a8a4009d6c Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 03:09:11 -0700 Subject: [PATCH 14/20] Create materialized view for variant publication dates --- ...aterialized_view_for_variant_statistics.py | 75 +++++++++++++++++++ src/mavedb/models/__init__.py | 1 + src/mavedb/models/published_variant.py | 45 +++++++++++ 3 files changed, 121 insertions(+) create mode 100644 alembic/versions/b85bc7b1bec7_materialized_view_for_variant_statistics.py create mode 100644 src/mavedb/models/published_variant.py diff --git a/alembic/versions/b85bc7b1bec7_materialized_view_for_variant_statistics.py b/alembic/versions/b85bc7b1bec7_materialized_view_for_variant_statistics.py new file mode 100644 index 00000000..7ce51c88 --- /dev/null +++ b/alembic/versions/b85bc7b1bec7_materialized_view_for_variant_statistics.py @@ -0,0 +1,75 @@ +"""materialized view for variant statistics +Revision ID: b85bc7b1bec7 +Revises: c404b6719110 +Create Date: 2025-03-14 01:53:19.898198 +""" + +from alembic import op +from alembic_utils.pg_materialized_view import PGMaterializedView +from sqlalchemy.dialects import postgresql + +from mavedb.models.published_variant import signature, definition + + +# revision identifiers, used by Alembic. +revision = "b85bc7b1bec7" +down_revision = "c404b6719110" +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_entity( + PGMaterializedView( + schema="public", + signature=signature, + definition=definition.compile(dialect=postgresql.dialect()).string, + with_data=True, + ) + ) + op.create_index( + f"idx_{signature}_variant_id", + signature, + ["variant_id"], + unique=False, + ) + op.create_index( + f"idx_{signature}_variant_urn", + signature, + ["variant_urn"], + unique=False, + ) + op.create_index( + f"idx_{signature}_score_set_id", + signature, + ["score_set_id"], + unique=False, + ) + op.create_index( + f"idx_{signature}_score_set_urn", + signature, + ["score_set_urn"], + unique=False, + ) + op.create_index( + f"idx_{signature}_mapped_variant_id", + signature, + ["mapped_variant_id"], + unique=True, + ) + + +def downgrade(): + op.drop_index(f"idx_{signature}_variant_id", signature) + op.drop_index(f"idx_{signature}_variant_urn", signature) + op.drop_index(f"idx_{signature}_mapped_variant_id", signature) + op.drop_index(f"idx_{signature}_score_set_id", signature) + op.drop_index(f"idx_{signature}_score_set_urn", signature) + op.drop_entity( + PGMaterializedView( + schema="public", + signature=signature, + definition=definition.compile(dialect=postgresql.dialect()).string, + with_data=True, + ) + ) diff --git a/src/mavedb/models/__init__.py b/src/mavedb/models/__init__.py index 0143a84f..a1a2c0af 100644 --- a/src/mavedb/models/__init__.py +++ b/src/mavedb/models/__init__.py @@ -12,6 +12,7 @@ "license", "mapped_variant", "publication_identifier", + "published_variant", "raw_read_identifier", "refseq_identifier", "refseq_offset", diff --git a/src/mavedb/models/published_variant.py b/src/mavedb/models/published_variant.py new file mode 100644 index 00000000..eff749bd --- /dev/null +++ b/src/mavedb/models/published_variant.py @@ -0,0 +1,45 @@ +from sqlalchemy import select, join + +from mavedb.db.view import MaterializedView, view + +from mavedb.models.score_set import ScoreSet +from mavedb.models.variant import Variant +from mavedb.models.mapped_variant import MappedVariant + + +signature = "published_variants_materialized_view" +definition = ( + select( + Variant.id.label("variant_id"), + Variant.urn.label("variant_urn"), + MappedVariant.id.label("mapped_variant_id"), + ScoreSet.id.label("score_set_id"), + ScoreSet.urn.label("score_set_urn"), + ScoreSet.published_date.label("published_date"), + MappedVariant.current.label("current_mapped_variant"), + ) + .select_from( + join(Variant, MappedVariant, Variant.id == MappedVariant.variant_id, isouter=True).join( + ScoreSet, ScoreSet.id == Variant.score_set_id + ) + ) + .where( + ScoreSet.published_date.is_not(None), + ) +) + + +class PublishedVariantsMV(MaterializedView): + __table__ = view( + signature, + definition, + materialized=True, + ) + + variant_id = __table__.c.variant_id + variant_urn = __table__.c.variant_urn + mapped_variant_id = __table__.c.mapped_variant_id + score_set_id = __table__.c.score_set_id + score_set_urn = __table__.c.score_set_urn + published_date = __table__.c.published_date + current_mapped_variant = __table__.c.current_mapped_variant From 44a25e5c012e3fd6b1c4976950ee649784f0e04e Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 03:11:21 -0700 Subject: [PATCH 15/20] Use published variants materialized view for statistics dashboard --- src/mavedb/routers/statistics.py | 24 ++++++++++++------------ tests/conftest.py | 4 ++-- tests/routers/conftest.py | 5 +++++ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index a1308a25..f79d07f6 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -19,8 +19,8 @@ ) from mavedb.models.experiment_controlled_keyword import ExperimentControlledKeywordAssociation from mavedb.models.experiment_publication_identifier import ExperimentPublicationIdentifierAssociation -from mavedb.models.mapped_variant import MappedVariant from mavedb.models.publication_identifier import PublicationIdentifier +from mavedb.models.published_variant import PublishedVariantsMV from mavedb.models.raw_read_identifier import RawReadIdentifier from mavedb.models.refseq_identifier import RefseqIdentifier from mavedb.models.refseq_offset import RefseqOffset @@ -37,7 +37,6 @@ from mavedb.models.uniprot_identifier import UniprotIdentifier from mavedb.models.uniprot_offset import UniprotOffset from mavedb.models.user import User -from mavedb.models.variant import Variant router = APIRouter( prefix="/api/v1/statistics", @@ -484,9 +483,12 @@ def variant_counts(group: Optional[GroupBy] = None, db: Session = Depends(get_db Returns a dictionary of counts for the number of published and distinct variants in the database. Optionally, group the counts by the day on which the score set (and by extension, the variant) was published. """ - query = _join_model_and_filter_unpublished(select(ScoreSet.published_date, func.count(Variant.id)), ScoreSet) + variants = db.execute( + select(PublishedVariantsMV.published_date, func.count(PublishedVariantsMV.variant_id)) + .group_by(PublishedVariantsMV.published_date) + .order_by(PublishedVariantsMV.published_date) + ).all() - variants = db.execute(query.group_by(ScoreSet.published_date).order_by(ScoreSet.published_date)).all() if group == GroupBy.month: grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y-%m"))} elif group == GroupBy.year: @@ -506,17 +508,15 @@ def mapped_variant_counts( Optionally, group the counts by the day on which the score set (and by extension, the variant) was published. Optionally, return the count of all mapped variants, not just the current/most up to date ones. """ - query = _join_model_and_filter_unpublished( - select(ScoreSet.published_date, func.count(MappedVariant.id)).join( - Variant, Variant.id == MappedVariant.variant_id - ), - ScoreSet, - ) + query = select(PublishedVariantsMV.published_date, func.count(PublishedVariantsMV.mapped_variant_id)) if onlyCurrent: - query = query.where(MappedVariant.current.is_(True)) + query = query.where(PublishedVariantsMV.current_mapped_variant.is_(True)) + + variants = db.execute( + query.group_by(PublishedVariantsMV.published_date).order_by(PublishedVariantsMV.published_date) + ).all() - variants = db.execute(query.group_by(ScoreSet.published_date).order_by(ScoreSet.published_date)).all() if group == GroupBy.month: grouped = {k: sum(c for _, c in g) for k, g in itertools.groupby(variants, lambda t: t[0].strftime("%Y-%m"))} elif group == GroupBy.year: diff --git a/tests/conftest.py b/tests/conftest.py index 16ac097c..e5d55a32 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ import os -import logging +import logging # noqa: F401 import sys from concurrent import futures from inspect import getsourcefile @@ -44,7 +44,7 @@ @pytest.fixture() def session(postgresql): # Un-comment this line to log all database queries: - logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) + # logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) connection = ( f"postgresql+psycopg2://{postgresql.info.user}:" diff --git a/tests/routers/conftest.py b/tests/routers/conftest.py index d5a69cd9..591c4e3e 100644 --- a/tests/routers/conftest.py +++ b/tests/routers/conftest.py @@ -8,6 +8,7 @@ from mavedb.models.controlled_keyword import ControlledKeyword from mavedb.models.contributor import Contributor from mavedb.models.enums.user_role import UserRole +from mavedb.models.published_variant import PublishedVariantsMV from mavedb.models.license import License from mavedb.models.role import Role from mavedb.models.taxonomy import Taxonomy @@ -80,6 +81,10 @@ def setup_seq_scoreset(setup_router_db, session, data_provider, client, data_fil create_mapped_variants_for_score_set(session, score_set["urn"]) publish_score_set(client, score_set["urn"]) + # Note that we have not created indexes for this view when it is generated via metadata. This differs + # from the database created via alembic, which does create indexes. + PublishedVariantsMV.refresh(session, False) + @pytest.fixture def mock_publication_fetch(request, requests_mock): From 52e5e05da24bde98859fe52dc92d416ffc5ab36e Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Tue, 18 Mar 2025 15:09:13 -0700 Subject: [PATCH 16/20] Add async materialized view refresh jobs Adds refresh jobs for existing materialized views and invokes them: - Refreshes the published variants materialized view whenever a new score set is published. (We cannot delete a published score set, nor edit it's variants, so publication time is the only moment this view becomes outdated). - Refreshes all materialized views at 0300. Adds tests for newly placed publication view refresh. Clarifies connection -> inspector flow during mat view refresh. Opens #405. --- src/mavedb/db/view.py | 19 +- src/mavedb/routers/score_sets.py | 18 +- src/mavedb/worker/jobs.py | 23 +- src/mavedb/worker/settings.py | 15 +- tests/helpers/util.py | 6 +- tests/routers/test_experiments.py | 89 ++++--- tests/routers/test_permissions.py | 5 +- tests/routers/test_score_set.py | 422 ++++++++++++++++++++++-------- 8 files changed, 425 insertions(+), 172 deletions(-) diff --git a/src/mavedb/db/view.py b/src/mavedb/db/view.py index 37293a01..64655686 100644 --- a/src/mavedb/db/view.py +++ b/src/mavedb/db/view.py @@ -50,7 +50,7 @@ def _drop_view(element: DropView, compiler, **kw): return "DROP %s %s" % ("MATERIALIZED VIEW" if element.materialized else "VIEW", element.name) -def view_exists(ddl: CreateView, target, connection: Session, materialized: bool, **kw): +def view_exists(ddl: CreateView, target, connection: sa.Connection, materialized: bool, **kw): inspector = sa.inspect(connection) if inspector is None: return False @@ -59,7 +59,7 @@ def view_exists(ddl: CreateView, target, connection: Session, materialized: bool return ddl.name in view_names -def view_doesnt_exist(ddl: CreateView, target, connection: Session, materialized: bool, **kw): +def view_doesnt_exist(ddl: CreateView, target, connection: sa.Connection, materialized: bool, **kw): return not view_exists(ddl, target, connection, materialized, **kw) @@ -121,7 +121,7 @@ class MyView(Base): return t -def refresh_mat_view(session, name, concurrently=True): +def refresh_mat_view(session: Session, name: str, concurrently=True): """ Refreshes a single materialized view, given by `name`. """ @@ -132,12 +132,15 @@ def refresh_mat_view(session, name, concurrently=True): session.execute(sa.text("REFRESH MATERIALIZED VIEW " + _con + name)) -# TODO: untested. -def refresh_all_mat_views(session, concurrently=True): +def refresh_all_mat_views(session: Session, concurrently=True): """ Refreshes all materialized views. Views are refreshed in non-deterministic order, so view definitions can't depend on each other. """ - mat_views = session.inspect(session.engine).get_view_names() - for v in mat_views: - refresh_mat_view(session, v, concurrently) + inspector = sa.inspect(session.connection()) + + if not inspector: + return + + for mv in inspector.get_materialized_view_names(): + refresh_mat_view(session, mv, concurrently) diff --git a/src/mavedb/routers/score_sets.py b/src/mavedb/routers/score_sets.py index aa22c54f..235f436f 100644 --- a/src/mavedb/routers/score_sets.py +++ b/src/mavedb/routers/score_sets.py @@ -658,7 +658,6 @@ async def upload_score_set_variant_data( except UnicodeDecodeError as e: raise HTTPException(status_code=400, detail=f"Error decoding file: {e}. Ensure the file has correct values.") - if scores_file: # Although this is also updated within the variant creation job, update it here # as well so that we can display the proper UI components (queue invocation delay @@ -1016,11 +1015,12 @@ async def delete_score_set( response_model=score_set.ScoreSet, response_model_exclude_none=True, ) -def publish_score_set( +async def publish_score_set( *, urn: str, db: Session = Depends(deps.get_db), user_data: UserData = Depends(require_current_user), + worker: ArqRedis = Depends(deps.get_worker), ) -> Any: """ Publish a score set. @@ -1097,4 +1097,18 @@ def publish_score_set( db.commit() db.refresh(item) + # await the insertion of this job into the worker queue, not the job itself. + job = await worker.enqueue_job( + "refresh_published_variants_view", + correlation_id_for_context(), + user_data.user.id, + ) + if job is not None: + save_to_logging_context({"worker_job_id": job.job_id}) + logger.info(msg="Enqueud published variant materialized view refresh job.", extra=logging_context()) + else: + logger.warning( + msg="Failed to enqueue published variant materialized view refresh job.", extra=logging_context() + ) + return item diff --git a/src/mavedb/worker/jobs.py b/src/mavedb/worker/jobs.py index fed261c8..2219a496 100644 --- a/src/mavedb/worker/jobs.py +++ b/src/mavedb/worker/jobs.py @@ -14,6 +14,7 @@ from sqlalchemy.orm import Session from mavedb.data_providers.services import vrs_mapper +from mavedb.db.view import refresh_all_mat_views from mavedb.lib.exceptions import MappingEnqueueError, NonexistentMappingReferenceError, NonexistentMappingResultsError from mavedb.lib.logging.context import format_raised_exception_info_as_dict from mavedb.lib.score_sets import ( @@ -29,6 +30,7 @@ from mavedb.models.enums.mapping_state import MappingState from mavedb.models.enums.processing_state import ProcessingState from mavedb.models.mapped_variant import MappedVariant +from mavedb.models.published_variant import PublishedVariantsMV from mavedb.models.score_set import ScoreSet from mavedb.models.user import User from mavedb.models.variant import Variant @@ -50,7 +52,9 @@ async def mapping_in_execution(redis: ArqRedis, job_id: str): await redis.set(MAPPING_CURRENT_ID_NAME, "") -def setup_job_state(ctx, invoker: int, resource: Optional[str], correlation_id: str): +def setup_job_state( + ctx, invoker: Optional[int], resource: Optional[str], correlation_id: Optional[str] +) -> dict[str, Any]: ctx["state"][ctx["job_id"]] = { "application": "mavedb-worker", "user": invoker, @@ -653,3 +657,20 @@ async def variant_mapper_manager(ctx: dict, correlation_id: str, updater_id: int db.commit() return {"success": False, "enqueued_job": new_job_id} + + +# TODO#405: Refresh materialized views within an executor. +async def refresh_materialized_views(ctx: dict): + logging_context = setup_job_state(ctx, None, None, None) + logger.debug(msg="Began refresh materialized views.", extra=logging_context) + refresh_all_mat_views(ctx["db"]) + logger.debug(msg="Done refreshing materialized views.", extra=logging_context) + return {"success": True} + + +async def refresh_published_variants_view(ctx: dict, correlation_id: str): + logging_context = setup_job_state(ctx, None, None, correlation_id) + logger.debug(msg="Began refresh of published variants materialized view.", extra=logging_context) + PublishedVariantsMV.refresh(ctx["db"]) + logger.debug(msg="Done refreshing of published variants materialized view.", extra=logging_context) + return {"success": True} diff --git a/src/mavedb/worker/settings.py b/src/mavedb/worker/settings.py index d91e48b8..5e393259 100644 --- a/src/mavedb/worker/settings.py +++ b/src/mavedb/worker/settings.py @@ -3,20 +3,29 @@ from typing import Callable from arq.connections import RedisSettings -from arq.cron import CronJob +from arq.cron import CronJob, cron from mavedb.data_providers.services import cdot_rest from mavedb.db.session import SessionLocal from mavedb.lib.logging.canonical import log_job -from mavedb.worker.jobs import create_variants_for_score_set, map_variants_for_score_set, variant_mapper_manager +from mavedb.worker.jobs import ( + create_variants_for_score_set, + map_variants_for_score_set, + variant_mapper_manager, + refresh_materialized_views, + refresh_published_variants_view, +) # ARQ requires at least one task on startup. BACKGROUND_FUNCTIONS: list[Callable] = [ create_variants_for_score_set, variant_mapper_manager, map_variants_for_score_set, + refresh_published_variants_view, +] +BACKGROUND_CRONJOBS: list[CronJob] = [ + cron(refresh_materialized_views, name="refresh_all_materialized_views", hour=3, minute=0) ] -BACKGROUND_CRONJOBS: list[CronJob] = [] REDIS_IP = os.getenv("REDIS_IP") or "localhost" REDIS_PORT = int(os.getenv("REDIS_PORT") or 6379) diff --git a/tests/helpers/util.py b/tests/helpers/util.py index 0cbfe4c9..6a005e3a 100644 --- a/tests/helpers/util.py +++ b/tests/helpers/util.py @@ -240,8 +240,10 @@ def create_acc_score_set_with_variants( def publish_score_set(client, score_set_urn): - response = client.post(f"/api/v1/score-sets/{score_set_urn}/publish") - assert response.status_code == 200, f"Could not publish score set {score_set_urn}" + with patch.object(ArqRedis, "enqueue_job", return_value=None) as worker_queue: + response = client.post(f"/api/v1/score-sets/{score_set_urn}/publish") + assert response.status_code == 200, f"Could not publish score set {score_set_urn}" + worker_queue.assert_called_once() response_data = response.json() jsonschema.validate(instance=response_data, schema=ScoreSet.schema()) diff --git a/tests/routers/test_experiments.py b/tests/routers/test_experiments.py index 041c42e4..199cd2b7 100644 --- a/tests/routers/test_experiments.py +++ b/tests/routers/test_experiments.py @@ -37,6 +37,7 @@ create_experiment, create_seq_score_set, create_seq_score_set_with_variants, + publish_score_set, ) @@ -502,7 +503,8 @@ def test_can_update_own_public_experiment_set(session, data_provider, client, se score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + + published_score_set = publish_score_set(client, score_set["urn"]) response_data = create_experiment( client, {"experimentSetUrn": published_score_set["experiment"]["experimentSetUrn"], "title": "Second Experiment"}, @@ -516,7 +518,7 @@ def test_cannot_update_other_users_public_experiment_set(session, data_provider, score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) published_experiment_set_urn = published_score_set["experiment"]["experimentSetUrn"] change_ownership(session, published_experiment_set_urn, ExperimentSetDbModel) experiment_post_payload = deepcopy(TEST_MINIMAL_EXPERIMENT) @@ -534,7 +536,7 @@ def test_anonymous_cannot_update_others_user_public_experiment_set( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) published_experiment_set_urn = published_score_set["experiment"]["experimentSetUrn"] experiment_post_payload = deepcopy(TEST_MINIMAL_EXPERIMENT) experiment_post_payload.update({"experimentSetUrn": published_experiment_set_urn, "title": "Second Experiment"}) @@ -554,7 +556,7 @@ def test_admin_can_update_other_users_public_experiment_set( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) with DependencyOverrider(admin_app_overrides): response_data = create_experiment( @@ -760,7 +762,7 @@ def test_create_experiment_with_new_primary_pubmed_url_publication(client, setup "publicationYear", ] ) - assert response_data["primaryPublicationIdentifiers"][0]["identifier"] == '37162834' + assert response_data["primaryPublicationIdentifiers"][0]["identifier"] == "37162834" @pytest.mark.parametrize( @@ -1009,7 +1011,7 @@ def test_search_meta_analysis_experiment(session, data_provider, client, setup_r client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + score_set = publish_score_set(client, score_set["urn"]) meta_score_set = create_seq_score_set_with_variants( client, session, @@ -1019,7 +1021,7 @@ def test_search_meta_analysis_experiment(session, data_provider, client, setup_r update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set["urn"]]}, ) - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + meta_score_set = publish_score_set(client, meta_score_set["urn"]) score_set_refresh = (client.get(f"/api/v1/score-sets/{score_set['urn']}")).json() search_payload = {"metaAnalysis": True} response = client.post("/api/v1/me/experiments/search", json=search_payload) @@ -1035,7 +1037,7 @@ def test_search_exclude_meta_analysis_experiment(session, data_provider, client, client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + score_set = publish_score_set(client, score_set["urn"]) meta_score_set = create_seq_score_set_with_variants( client, session, @@ -1045,7 +1047,7 @@ def test_search_exclude_meta_analysis_experiment(session, data_provider, client, update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set["urn"]]}, ) - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + meta_score_set = publish_score_set(client, meta_score_set["urn"]) score_set_refresh = (client.get(f"/api/v1/score-sets/{score_set['urn']}")).json() search_payload = {"metaAnalysis": False} response = client.post("/api/v1/me/experiments/search", json=search_payload) @@ -1062,7 +1064,7 @@ def test_search_score_sets_for_experiments(session, client, setup_router_db, dat ) # make the unpublished score set owned by some other user. This shouldn't appear in the results. score_set_unpub = create_seq_score_set(client, experiment["urn"], update={"title": "Unpublished Score Set"}) - published_score_set = client.post(f"/api/v1/score-sets/{score_set_pub['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set_pub["urn"]) change_ownership(session, score_set_unpub["urn"], ScoreSetDbModel) # On score set publication, the experiment will get a new urn @@ -1074,14 +1076,14 @@ def test_search_score_sets_for_experiments(session, client, setup_router_db, dat # Creator created a superseding score set but not published it yet. -def test_owner_searches_score_sets_with_unpublished_superseding_score_sets_for_experiments(session, client, setup_router_db, data_files, data_provider): +def test_owner_searches_score_sets_with_unpublished_superseding_score_sets_for_experiments( + session, client, setup_router_db, data_files, data_provider +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 - published_score_set = publish_score_set_response.json() + published_score_set = publish_score_set(client, unpublished_score_set["urn"]) score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] score_set_post_payload["supersededScoreSetUrn"] = published_score_set["urn"] @@ -1097,14 +1099,14 @@ def test_owner_searches_score_sets_with_unpublished_superseding_score_sets_for_e assert response.json()[0]["urn"] == superseding_score_set["urn"] -def test_non_owner_searches_score_sets_with_unpublished_superseding_score_sets_for_experiments(session, client, setup_router_db, data_files, data_provider): +def test_non_owner_searches_score_sets_with_unpublished_superseding_score_sets_for_experiments( + session, client, setup_router_db, data_files, data_provider +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 - published_score_set = publish_score_set_response.json() + published_score_set = publish_score_set(client, unpublished_score_set["urn"]) score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] score_set_post_payload["supersededScoreSetUrn"] = published_score_set["urn"] @@ -1121,14 +1123,14 @@ def test_non_owner_searches_score_sets_with_unpublished_superseding_score_sets_f assert response.json()[0]["urn"] == published_score_set["urn"] -def test_owner_searches_published_superseding_score_sets_for_experiments(session, client, setup_router_db, data_files, data_provider): +def test_owner_searches_published_superseding_score_sets_for_experiments( + session, client, setup_router_db, data_files, data_provider +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 - published_score_set = publish_score_set_response.json() + published_score_set = publish_score_set(client, unpublished_score_set["urn"]) superseding_score_set = create_seq_score_set_with_variants( client, @@ -1138,9 +1140,7 @@ def test_owner_searches_published_superseding_score_sets_for_experiments(session data_files / "scores.csv", update={"supersededScoreSetUrn": published_score_set["urn"]}, ) - published_superseding_score_set_response = client.post(f"/api/v1/score-sets/{superseding_score_set['urn']}/publish") - assert published_superseding_score_set_response.status_code == 200 - published_superseding_score_set = published_superseding_score_set_response.json() + published_superseding_score_set = publish_score_set(client, superseding_score_set["urn"]) # On score set publication, the experiment will get a new urn experiment_urn = published_score_set["experiment"]["urn"] response = client.get(f"/api/v1/experiments/{experiment_urn}/score-sets") @@ -1149,14 +1149,14 @@ def test_owner_searches_published_superseding_score_sets_for_experiments(session assert response.json()[0]["urn"] == published_superseding_score_set["urn"] -def test_non_owner_searches_published_superseding_score_sets_for_experiments(session, client, setup_router_db, data_files, data_provider): +def test_non_owner_searches_published_superseding_score_sets_for_experiments( + session, client, setup_router_db, data_files, data_provider +): experiment = create_experiment(client) unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 - published_score_set = publish_score_set_response.json() + published_score_set = publish_score_set(client, unpublished_score_set["urn"]) superseding_score_set = create_seq_score_set_with_variants( client, @@ -1166,9 +1166,7 @@ def test_non_owner_searches_published_superseding_score_sets_for_experiments(ses data_files / "scores.csv", update={"supersededScoreSetUrn": published_score_set["urn"]}, ) - published_superseding_score_set_response = client.post(f"/api/v1/score-sets/{superseding_score_set['urn']}/publish") - assert published_superseding_score_set_response.status_code == 200 - published_superseding_score_set = published_superseding_score_set_response.json() + published_superseding_score_set = publish_score_set(client, superseding_score_set["urn"]) change_ownership(session, published_score_set["urn"], ScoreSetDbModel) change_ownership(session, published_superseding_score_set["urn"], ScoreSetDbModel) # On score set publication, the experiment will get a new urn @@ -1186,7 +1184,7 @@ def test_search_score_sets_for_contributor_experiments(session, client, setup_ro ) # make the unpublished score set owned by some other user. This shouldn't appear in the results. score_set_unpub = create_seq_score_set(client, experiment["urn"], update={"title": "Unpublished Score Set"}) - published_score_set = client.post(f"/api/v1/score-sets/{score_set_pub['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set_pub["urn"]) change_ownership(session, score_set_unpub["urn"], ScoreSetDbModel) add_contributor( session, @@ -1214,7 +1212,7 @@ def test_search_score_sets_for_my_experiments(session, client, setup_router_db, ) # The unpublished score set is for the current user, so it should show up in results. score_set_unpub = create_seq_score_set(client, experiment["urn"], update={"title": "Unpublished Score Set"}) - published_score_set = client.post(f"/api/v1/score-sets/{score_set_pub['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set_pub["urn"]) # On score set publication, the experiment will get a new urn experiment_urn = published_score_set["experiment"]["urn"] @@ -1283,7 +1281,7 @@ def test_anonymous_cannot_delete_other_users_published_experiment( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + publish_score_set(client, score_set["urn"]) with DependencyOverrider(anonymous_app_overrides): del_response = client.delete(f"/api/v1/experiments/{experiment['urn']}") @@ -1305,9 +1303,8 @@ def test_cannot_delete_own_published_experiment(session, data_provider, client, score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - response_data = response.json() - experiment_urn = response_data["experiment"]["urn"] + published_score_set = publish_score_set(client, score_set["urn"]) + experiment_urn = published_score_set["experiment"]["urn"] del_response = client.delete(f"/api/v1/experiments/{experiment_urn}") assert del_response.status_code == 403 @@ -1339,14 +1336,15 @@ def test_admin_can_delete_other_users_private_experiment(session, client, setup_ assert response.status_code == 200 -def test_contributor_can_delete_other_users_published_experiment( +def test_contributor_cannot_delete_other_users_published_experiment( session, data_provider, client, setup_router_db, data_files ): experiment = create_experiment(client) score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - client.post(f"/api/v1/experiments/{score_set['urn']}/publish") + published_score_set = publish_score_set(client, score_set["urn"]) + experiment = published_score_set["experiment"] change_ownership(session, experiment["urn"], ExperimentDbModel) add_contributor( session, @@ -1358,7 +1356,7 @@ def test_contributor_can_delete_other_users_published_experiment( ) del_response = client.delete(f"/api/v1/experiments/{experiment['urn']}") - assert del_response.status_code == 200 + assert del_response.status_code == 403 def test_admin_can_delete_other_users_published_experiment( @@ -1368,7 +1366,8 @@ def test_admin_can_delete_other_users_published_experiment( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - client.post(f"/api/v1/experiments/{score_set['urn']}/publish") + published_score_set = publish_score_set(client, score_set["urn"]) + experiment = published_score_set["experiment"] with DependencyOverrider(admin_app_overrides): del_response = client.delete(f"/api/v1/experiments/{experiment['urn']}") @@ -1388,7 +1387,7 @@ def test_can_add_experiment_to_own_public_experiment_set(session, data_provider, score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) test_experiment = deepcopy(TEST_MINIMAL_EXPERIMENT) test_experiment.update({"experimentSetUrn": published_score_set["experiment"]["experimentSetUrn"]}) response = client.post("/api/v1/experiments/", json=test_experiment) @@ -1420,7 +1419,7 @@ def test_contributor_can_add_experiment_to_others_public_experiment_set( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) change_ownership(session, published_score_set["urn"], ScoreSetDbModel) change_ownership(session, published_score_set["experiment"]["urn"], ExperimentDbModel) change_ownership(session, published_score_set["experiment"]["experimentSetUrn"], ExperimentSetDbModel) @@ -1458,7 +1457,7 @@ def test_cannot_add_experiment_to_others_public_experiment_set( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + published_score_set = publish_score_set(client, score_set["urn"]) experiment_set_urn = published_score_set["experiment"]["experimentSetUrn"] change_ownership(session, published_score_set["urn"], ScoreSetDbModel) change_ownership(session, published_score_set["experiment"]["urn"], ExperimentDbModel) diff --git a/tests/routers/test_permissions.py b/tests/routers/test_permissions.py index 1473a125..ef8bebb1 100644 --- a/tests/routers/test_permissions.py +++ b/tests/routers/test_permissions.py @@ -8,6 +8,7 @@ create_experiment, create_seq_score_set, create_seq_score_set_with_variants, + publish_score_set, ) @@ -173,8 +174,8 @@ def test_get_true_permission_from_others_public_experiment_add_score_set_check( score_set_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - pub_score_set = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish").json() - pub_experiment_urn = pub_score_set["experiment"]["urn"] + published_score_set = publish_score_set(client, score_set_1["urn"]) + pub_experiment_urn = published_score_set["experiment"]["urn"] change_ownership(session, pub_experiment_urn, ExperimentDbModel) response = client.get(f"/api/v1/permissions/user-is-permitted/experiment/{pub_experiment_urn}/add_score_set") diff --git a/tests/routers/test_score_set.py b/tests/routers/test_score_set.py index ac263777..67c26b27 100644 --- a/tests/routers/test_score_set.py +++ b/tests/routers/test_score_set.py @@ -308,9 +308,13 @@ def test_can_update_score_set_supporting_data_after_publication( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 200 - published_urn = response.json()["urn"] + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publication_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publication_response.status_code == 200 + queue.assert_called_once() + published_score_set = publication_response.json() + + published_urn = published_score_set["urn"] response = client.get(f"/api/v1/score-sets/{published_urn}") assert response.status_code == 200 response_data = response.json() @@ -369,9 +373,13 @@ def test_cannot_update_score_set_target_data_after_publication( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 200 - published_urn = response.json()["urn"] + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publication_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publication_response.status_code == 200 + queue.assert_called_once() + published_score_set = publication_response.json() + + published_urn = published_score_set["urn"] response = client.get(f"/api/v1/score-sets/{published_urn}") assert response.status_code == 200 response_data = response.json() @@ -863,9 +871,12 @@ def test_publish_score_set(session, data_provider, client, setup_router_db, data client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 200 - response_data = response.json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publication_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publication_response.status_code == 200 + queue.assert_called_once() + response_data = publication_response.json() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(response_data["urn"]), re.Match) assert isinstance(MAVEDB_EXPERIMENT_URN_RE.fullmatch(response_data["experiment"]["urn"]), re.Match) @@ -908,15 +919,18 @@ def test_publish_multiple_score_sets(session, data_provider, client, setup_route client, session, data_provider, experiment["urn"], data_files / "scores.csv", update={"title": "Score Set 3"} ) - pub_score_set_1_response = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") - assert pub_score_set_1_response.status_code == 200 - pub_score_set_2_response = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") - assert pub_score_set_2_response.status_code == 200 - pub_score_set_3_response = client.post(f"/api/v1/score-sets/{score_set_3['urn']}/publish") - assert pub_score_set_3_response.status_code == 200 - pub_score_set_1_data = pub_score_set_1_response.json() - pub_score_set_2_data = pub_score_set_2_response.json() - pub_score_set_3_data = pub_score_set_3_response.json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + pub_score_set_1_response = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert pub_score_set_1_response.status_code == 200 + pub_score_set_2_response = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") + assert pub_score_set_2_response.status_code == 200 + pub_score_set_3_response = client.post(f"/api/v1/score-sets/{score_set_3['urn']}/publish") + assert pub_score_set_3_response.status_code == 200 + queue.assert_called() + pub_score_set_1_data = pub_score_set_1_response.json() + pub_score_set_2_data = pub_score_set_2_response.json() + pub_score_set_3_data = pub_score_set_3_response.json() + assert pub_score_set_1_data["urn"] == "urn:mavedb:00000001-a-1" assert pub_score_set_1_data["title"] == score_set_1["title"] assert pub_score_set_1_data["experiment"]["urn"] == "urn:mavedb:00000001-a" @@ -944,9 +958,13 @@ def test_publish_multiple_score_sets(session, data_provider, client, setup_route def test_cannot_publish_score_set_without_variants(client, setup_router_db): experiment = create_experiment(client) score_set = create_seq_score_set(client, experiment["urn"]) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 422 - response_data = response.json() + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 422 + queue.assert_not_called() + response_data = response.json() + assert "cannot publish score set without variant scores" in response_data["detail"] @@ -955,11 +973,14 @@ def test_cannot_publish_other_user_private_score_set(session, data_provider, cli score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - change_ownership(session, score_set["urn"], ScoreSetDbModel) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 404 - response_data = response.json() + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 404 + queue.assert_not_called() + response_data = response.json() + assert f"score set with URN '{score_set['urn']}' not found" in response_data["detail"] @@ -970,11 +991,16 @@ def test_anonymous_cannot_publish_user_private_score_set( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - with DependencyOverrider(anonymous_app_overrides): + + with ( + DependencyOverrider(anonymous_app_overrides), + patch.object(ArqRedis, "enqueue_job", return_value=None) as queue, + ): response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 401 + queue.assert_not_called() + response_data = response.json() - assert response.status_code == 401 - response_data = response.json() assert "Could not validate credentials" in response_data["detail"] @@ -993,9 +1019,12 @@ def test_contributor_can_publish_other_users_score_set(session, data_provider, c TEST_USER["last_name"], ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert response.status_code == 200 - response_data = response.json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() + response_data = response.json() + assert response_data["urn"] == "urn:mavedb:00000001-a-1" assert response_data["experiment"]["urn"] == "urn:mavedb:00000001-a" @@ -1054,11 +1083,12 @@ def test_admin_cannot_publish_other_user_private_score_set( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - with DependencyOverrider(admin_app_overrides): + with DependencyOverrider(admin_app_overrides), patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 404 + queue.assert_not_called() + response_data = response.json() - assert response.status_code == 404 - response_data = response.json() assert f"score set with URN '{score_set['urn']}' not found" in response_data["detail"] @@ -1073,7 +1103,12 @@ def test_create_single_score_set_meta_analysis(session, data_provider, client, s client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() + score_set = response.json() + meta_score_set = create_seq_score_set_with_variants( client, session, @@ -1095,7 +1130,12 @@ def test_publish_single_score_set_meta_analysis(session, data_provider, client, client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() + score_set = response.json() + meta_score_set = create_seq_score_set_with_variants( client, session, @@ -1105,7 +1145,12 @@ def test_publish_single_score_set_meta_analysis(session, data_provider, client, update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set["urn"]]}, ) - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) assert meta_score_set["urn"] == "urn:mavedb:00000001-0-1" @@ -1121,8 +1166,14 @@ def test_multiple_score_set_meta_analysis_single_experiment( client, session, data_provider, experiment["urn"], data_files / "scores.csv", update={"title": "Score Set 2"} ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() - score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert response_1.status_code == 200 + response_2 = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") + assert response_2.status_code == 200 + queue.assert_called() + score_set_1 = response_1.json() + score_set_2 = response_2.json() meta_score_set = create_seq_score_set_with_variants( client, @@ -1136,7 +1187,12 @@ def test_multiple_score_set_meta_analysis_single_experiment( assert meta_score_set["metaAnalyzesScoreSetUrns"] == sorted([score_set_1["urn"], score_set_2["urn"]]) assert score_set_1_refresh["metaAnalyzedByScoreSetUrns"] == [meta_score_set["urn"]] - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) assert meta_score_set["urn"] == "urn:mavedb:00000001-0-1" @@ -1153,8 +1209,14 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets( client, session, data_provider, experiment_2["urn"], data_files / "scores.csv", update={"title": "Score Set 2"} ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() - score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert response_1.status_code == 200 + response_2 = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") + assert response_2.status_code == 200 + queue.assert_called() + score_set_1 = response_1.json() + score_set_2 = response_2.json() meta_score_set = create_seq_score_set_with_variants( client, @@ -1168,7 +1230,12 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets( assert meta_score_set["metaAnalyzesScoreSetUrns"] == sorted([score_set_1["urn"], score_set_2["urn"]]) assert score_set_1_refresh["metaAnalyzedByScoreSetUrns"] == [meta_score_set["urn"]] - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) assert meta_score_set["urn"] == "urn:mavedb:00000003-0-1" @@ -1187,8 +1254,14 @@ def test_multiple_score_set_meta_analysis_multiple_experiments( client, session, data_provider, experiment_2["urn"], data_files / "scores.csv", update={"title": "Score Set 2"} ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() - score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert response_1.status_code == 200 + response_2 = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") + assert response_2.status_code == 200 + queue.assert_called() + score_set_1 = response_1.json() + score_set_2 = response_2.json() meta_score_set = create_seq_score_set_with_variants( client, @@ -1202,7 +1275,12 @@ def test_multiple_score_set_meta_analysis_multiple_experiments( assert meta_score_set["metaAnalyzesScoreSetUrns"] == sorted([score_set_1["urn"], score_set_2["urn"]]) assert score_set_1_refresh["metaAnalyzedByScoreSetUrns"] == [meta_score_set["urn"]] - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) assert meta_score_set["urn"] == "urn:mavedb:00000001-0-1" @@ -1245,10 +1323,21 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets_different_sco update={"title": "Exp 2 Score Set 2"}, ) - score_set_1_1 = (client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish")).json() - score_set_1_2 = (client.post(f"/api/v1/score-sets/{score_set_1_2['urn']}/publish")).json() - score_set_2_1 = (client.post(f"/api/v1/score-sets/{score_set_2_1['urn']}/publish")).json() - score_set_2_2 = (client.post(f"/api/v1/score-sets/{score_set_2_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response_1_1 = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert response_1_1.status_code == 200 + response_1_2 = client.post(f"/api/v1/score-sets/{score_set_1_2['urn']}/publish") + assert response_1_2.status_code == 200 + response_2_1 = client.post(f"/api/v1/score-sets/{score_set_2_1['urn']}/publish") + assert response_2_1.status_code == 200 + response_2_2 = client.post(f"/api/v1/score-sets/{score_set_2_2['urn']}/publish") + assert response_2_2.status_code == 200 + queue.assert_called() + score_set_1_1 = response_1_1.json() + score_set_1_2 = response_1_2.json() + score_set_2_1 = response_2_1.json() + score_set_2_2 = response_2_2.json() + meta_score_set_1 = create_seq_score_set_with_variants( client, session, @@ -1287,12 +1376,15 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets_different_sco }, ) - meta_score_set_1 = (client.post(f"/api/v1/score-sets/{meta_score_set_1['urn']}/publish")).json() - assert meta_score_set_1["urn"] == "urn:mavedb:00000003-0-1" - meta_score_set_2 = (client.post(f"/api/v1/score-sets/{meta_score_set_2['urn']}/publish")).json() - assert meta_score_set_2["urn"] == "urn:mavedb:00000003-0-2" - meta_score_set_3 = (client.post(f"/api/v1/score-sets/{meta_score_set_3['urn']}/publish")).json() - assert meta_score_set_3["urn"] == "urn:mavedb:00000003-0-3" + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_score_set_1 = (client.post(f"/api/v1/score-sets/{meta_score_set_1['urn']}/publish")).json() + assert meta_score_set_1["urn"] == "urn:mavedb:00000003-0-1" + meta_score_set_2 = (client.post(f"/api/v1/score-sets/{meta_score_set_2['urn']}/publish")).json() + assert meta_score_set_2["urn"] == "urn:mavedb:00000003-0-2" + meta_score_set_3 = (client.post(f"/api/v1/score-sets/{meta_score_set_3['urn']}/publish")).json() + assert meta_score_set_3["urn"] == "urn:mavedb:00000003-0-3" + queue.assert_called() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set_1["urn"]), re.Match) assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set_2["urn"]), re.Match) assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set_3["urn"]), re.Match) @@ -1304,7 +1396,12 @@ def test_cannot_add_score_set_to_meta_analysis_experiment(session, data_provider client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() + score_set_1 = response.json() + meta_score_set_1 = create_seq_score_set_with_variants( client, session, @@ -1314,7 +1411,11 @@ def test_cannot_add_score_set_to_meta_analysis_experiment(session, data_provider update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set_1["urn"]]}, ) - meta_score_set_1 = (client.post(f"/api/v1/score-sets/{meta_score_set_1['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_score_set_1 = (client.post(f"/api/v1/score-sets/{meta_score_set_1['urn']}/publish")).json() + assert meta_score_set_1["urn"] == "urn:mavedb:00000001-0-1" + queue.assert_called() + assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set_1["urn"]), re.Match) score_set_2 = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_2["experimentUrn"] = meta_score_set_1["experiment"]["urn"] @@ -1334,7 +1435,12 @@ def test_create_single_score_set_meta_analysis_to_others_score_set( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() + score_set = response.json() + change_ownership(session, score_set["urn"], ScoreSetDbModel) meta_score_set = create_seq_score_set_with_variants( client, @@ -1362,8 +1468,14 @@ def test_multiple_score_set_meta_analysis_single_experiment_with_different_creat client, session, data_provider, experiment["urn"], data_files / "scores.csv", update={"title": "Score Set 2"} ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() - score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish") + assert response_1.status_code == 200 + response_2 = client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish") + assert response_2.status_code == 200 + queue.assert_called() + score_set_1 = response_1.json() + score_set_2 = response_2.json() change_ownership(session, score_set_2["urn"], ScoreSetDbModel) meta_score_set = create_seq_score_set_with_variants( @@ -1378,7 +1490,12 @@ def test_multiple_score_set_meta_analysis_single_experiment_with_different_creat assert meta_score_set["metaAnalyzesScoreSetUrns"] == sorted([score_set_1["urn"], score_set_2["urn"]]) assert score_set_1_refresh["metaAnalyzedByScoreSetUrns"] == [meta_score_set["urn"]] - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert meta_score_set["urn"] == "urn:mavedb:00000001-0-1" assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) @@ -1395,8 +1512,10 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets_with_differen client, session, data_provider, experiment_2["urn"], data_files / "scores.csv", update={"title": "Score Set 2"} ) - score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() - score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() + score_set_2 = (client.post(f"/api/v1/score-sets/{score_set_2['urn']}/publish")).json() + queue.assert_called() change_ownership(session, score_set_2["urn"], ScoreSetDbModel) meta_score_set = create_seq_score_set_with_variants( @@ -1411,7 +1530,12 @@ def test_multiple_score_set_meta_analysis_multiple_experiment_sets_with_differen assert meta_score_set["metaAnalyzesScoreSetUrns"] == sorted([score_set_1["urn"], score_set_2["urn"]]) assert score_set_1_refresh["metaAnalyzedByScoreSetUrns"] == [meta_score_set["urn"]] - meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + meta_response = client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish") + assert meta_response.status_code == 200 + queue.assert_called_once() + meta_score_set = meta_response.json() + assert meta_score_set["urn"] == "urn:mavedb:00000003-0-1" assert isinstance(MAVEDB_SCORE_SET_URN_RE.fullmatch(meta_score_set["urn"]), re.Match) @@ -1555,8 +1679,11 @@ def test_search_public_score_sets_no_match(session, data_provider, client, setup data_files / "scores.csv", update={"title": "Test Score Set"}, ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - assert score_set_response.status_code == 200 + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() search_payload = {"text": "fnord"} response = client.post("/api/v1/score-sets/search", json=search_payload) @@ -1575,8 +1702,11 @@ def test_search_public_score_sets_match(session, data_provider, client, setup_ro update={"title": "Test Fnord Score Set"}, ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - assert score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + search_payload = {"text": "fnord"} response = client.post("/api/v1/score-sets/search", json=search_payload) assert response.status_code == 200 @@ -1589,9 +1719,12 @@ def test_search_public_score_sets_urn_with_space_match(session, data_provider, c score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - published_score_set = score_set_response.json() - assert score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + published_score_set = score_set_response.json() + assert score_set_response.status_code == 200 + queue.assert_called_once() + urn_with_space = published_score_set["urn"] + " " search_payload = {"urn": urn_with_space} response = client.post("/api/v1/score-sets/search", json=search_payload) @@ -1610,9 +1743,13 @@ def test_search_others_public_score_sets_no_match(session, data_provider, client data_files / "scores.csv", update={"title": "Test Score Set"}, ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + publish_score_set = score_set_response.json() - assert score_set_response.status_code == 200 change_ownership(session, publish_score_set["urn"], ScoreSetDbModel) search_payload = {"text": "fnord"} response = client.post("/api/v1/score-sets/search", json=search_payload) @@ -1630,9 +1767,13 @@ def test_search_others_public_score_sets_match(session, data_provider, client, s data_files / "scores.csv", update={"title": "Test Fnord Score Set"}, ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + publish_score_set = score_set_response.json() - assert score_set_response.status_code == 200 change_ownership(session, publish_score_set["urn"], ScoreSetDbModel) assert session.query(ScoreSetDbModel).filter_by(urn=publish_score_set["urn"]).one() search_payload = {"text": "fnord"} @@ -1647,9 +1788,13 @@ def test_search_others_public_score_sets_urn_match(session, data_provider, clien score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + publish_score_set = score_set_response.json() - assert score_set_response.status_code == 200 change_ownership(session, publish_score_set["urn"], ScoreSetDbModel) search_payload = {"urn": score_set_1_1["urn"]} response = client.post("/api/v1/score-sets/search", json=search_payload) @@ -1665,8 +1810,12 @@ def test_search_others_public_score_sets_urn_with_space_match( score_set_1_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - assert score_set_response.status_code == 200 + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + published_score_set = score_set_response.json() change_ownership(session, published_score_set["urn"], ScoreSetDbModel) urn_with_space = published_score_set["urn"] + " " @@ -1687,8 +1836,12 @@ def test_search_private_score_sets_not_showing_public_score_set( score_set_1_2 = create_seq_score_set_with_variants( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - assert score_set_response.status_code == 200 + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + search_payload = {"published": False} response = client.post("/api/v1/score-sets/search", json=search_payload) assert response.status_code == 200 @@ -1704,8 +1857,12 @@ def test_search_public_score_sets_not_showing_private_score_set( client, session, data_provider, experiment_1["urn"], data_files / "scores.csv" ) create_seq_score_set_with_variants(client, session, data_provider, experiment_1["urn"], data_files / "scores.csv") - score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") - assert score_set_response.status_code == 200 + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + score_set_response = client.post(f"/api/v1/score-sets/{score_set_1_1['urn']}/publish") + assert score_set_response.status_code == 200 + queue.assert_called_once() + published_score_set = score_set_response.json() search_payload = {"published": True} response = client.post("/api/v1/score-sets/search", json=search_payload) @@ -1741,7 +1898,11 @@ def test_anonymous_cannot_delete_other_users_published_scoreset( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() response_data = response.json() with DependencyOverrider(anonymous_app_overrides): @@ -1768,7 +1929,11 @@ def test_cannot_delete_own_published_scoreset(session, data_provider, client, se score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() response_data = response.json() del_response = client.delete(f"/api/v1/score-sets/{response_data['urn']}") @@ -1821,7 +1986,11 @@ def test_admin_can_delete_other_users_published_scoreset( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert response.status_code == 200 + queue.assert_called_once() response_data = response.json() with DependencyOverrider(admin_app_overrides): @@ -1860,7 +2029,11 @@ def test_can_add_score_set_to_own_public_experiment(session, data_provider, clie score_set_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - pub_score_set_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish").json() + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + pub_score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() + queue.assert_called_once() + score_set_2 = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_2["experimentUrn"] = pub_score_set_1["experiment"]["urn"] response = client.post("/api/v1/score-sets/", json=score_set_2) @@ -1872,7 +2045,11 @@ def test_can_add_score_set_to_others_public_experiment(session, data_provider, c score_set_1 = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - pub_score_set_1 = client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish").json() + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + pub_score_set_1 = (client.post(f"/api/v1/score-sets/{score_set_1['urn']}/publish")).json() + queue.assert_called_once() + change_ownership(session, pub_score_set_1["experiment"]["urn"], ExperimentDbModel) score_set_2 = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_2["experimentUrn"] = pub_score_set_1["experiment"]["urn"] @@ -1904,7 +2081,11 @@ def test_contributor_can_add_score_set_to_others_public_experiment( score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - published_score_set = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish").json() + + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + published_score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + queue.assert_called_once() + change_ownership(session, published_score_set["experiment"]["urn"], ExperimentDbModel) add_contributor( session, @@ -1960,8 +2141,11 @@ def test_create_superseding_score_set(session, data_provider, client, setup_rout score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() + published_score_set = publish_score_set_response.json() score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] @@ -1975,8 +2159,11 @@ def test_can_view_unpublished_superseding_score_set(session, data_provider, clie unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() + published_score_set = publish_score_set_response.json() score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] @@ -1998,8 +2185,11 @@ def test_cannot_view_others_unpublished_superseding_score_set( unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() + published_score_set = publish_score_set_response.json() score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] @@ -2021,8 +2211,10 @@ def test_can_view_others_published_superseding_score_set(session, data_provider, unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() published_score_set = publish_score_set_response.json() superseding_score_set = create_seq_score_set_with_variants( @@ -2033,8 +2225,12 @@ def test_can_view_others_published_superseding_score_set(session, data_provider, data_files / "scores.csv", update={"supersededScoreSetUrn": published_score_set["urn"]}, ) - published_superseding_score_set_response = client.post(f"/api/v1/score-sets/{superseding_score_set['urn']}/publish") - assert published_superseding_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + published_superseding_score_set_response = client.post( + f"/api/v1/score-sets/{superseding_score_set['urn']}/publish" + ) + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() published_superseding_score_set = published_superseding_score_set_response.json() change_ownership(session, published_superseding_score_set["urn"], ScoreSetDbModel) @@ -2055,8 +2251,10 @@ def test_show_correct_score_set_version_with_superseded_score_set_to_its_owner( unpublished_score_set = create_seq_score_set_with_variants( client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{unpublished_score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() published_score_set = publish_score_set_response.json() score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET) score_set_post_payload["experimentUrn"] = published_score_set["experiment"]["urn"] @@ -2142,6 +2340,7 @@ def test_score_set_not_found_for_non_existent_score_set_when_adding_score_calibr # Score set upload files ######################################################################################################################## + # Not sure why scores_non_utf8_encoded.csv file has a wrong encoding problem, but it's good for this test. def test_upload_a_non_utf8_file(session, client, setup_router_db, data_files): experiment = create_experiment(client) @@ -2154,8 +2353,10 @@ def test_upload_a_non_utf8_file(session, client, setup_router_db, data_files): ) assert response.status_code == 400 response_data = response.json() - assert "Error decoding file: 'utf-8' codec can't decode byte 0xdd in position 10: invalid continuation byte. " \ - "Ensure the file has correct values." in response_data["detail"] + assert ( + "Error decoding file: 'utf-8' codec can't decode byte 0xdd in position 10: invalid continuation byte. " + "Ensure the file has correct values." in response_data["detail"] + ) ######################################################################################################################## @@ -2170,10 +2371,11 @@ def test_download_scores_file(session, data_provider, client, setup_router_db, d client, session, data_provider, experiment["urn"], data_files / "scores.csv" ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() publish_score_set = publish_score_set_response.json() - print(publish_score_set) download_scores_csv_response = client.get( f"/api/v1/score-sets/{publish_score_set['urn']}/scores?drop_na_columns=true" @@ -2197,8 +2399,10 @@ def test_download_counts_file(session, data_provider, client, setup_router_db, d scores_csv_path=data_files / "scores.csv", counts_csv_path=data_files / "counts.csv", ) - publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") - assert publish_score_set_response.status_code == 200 + with patch.object(ArqRedis, "enqueue_job", return_value=None) as queue: + publish_score_set_response = client.post(f"/api/v1/score-sets/{score_set['urn']}/publish") + assert publish_score_set_response.status_code == 200 + queue.assert_called_once() publish_score_set = publish_score_set_response.json() download_counts_csv_response = client.get( From d140d50bddde85c2a27066aeb1e8e683c382b75a Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Tue, 18 Mar 2025 15:18:36 -0700 Subject: [PATCH 17/20] Bump python-jose to appease dependabot --- poetry.lock | 195 +++++++++++++++++++++++++------------------------ pyproject.toml | 2 +- 2 files changed, 99 insertions(+), 98 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3cdd937f..8f9ea2a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -42,13 +42,13 @@ nvim = ["neovim", "python-language-server"] [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, + {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, ] [package.dependencies] @@ -58,8 +58,8 @@ sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] @@ -688,13 +688,13 @@ crt = ["awscrt (==0.21.2)"] [[package]] name = "botocore-stubs" -version = "1.37.12" +version = "1.37.15" description = "Type annotations and code completion for botocore" optional = false python-versions = ">=3.8" files = [ - {file = "botocore_stubs-1.37.12-py3-none-any.whl", hash = "sha256:474ed3dd1e07e60da16b5be229d5f61fe3563eb7d815ff29e58a0e855623e195"}, - {file = "botocore_stubs-1.37.12.tar.gz", hash = "sha256:db834e6c5f0043a7dcb39f2c5f12c7434a835c477d91aa20bc2ce7fac588dadb"}, + {file = "botocore_stubs-1.37.15-py3-none-any.whl", hash = "sha256:70ef39669f3b9421c20295535aaeb81aa62d6a90969fb631caabe480fe11af0c"}, + {file = "botocore_stubs-1.37.15.tar.gz", hash = "sha256:055525b345cac085b4607335b13744756a3d43a4b7025b2e977d1c139b15c31b"}, ] [package.dependencies] @@ -1002,74 +1002,74 @@ type = ["pytest-mypy"] [[package]] name = "coverage" -version = "7.6.12" +version = "7.7.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, - {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, - {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, - {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, - {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, - {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, - {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, - {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, - {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, - {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, - {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, - {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, - {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, - {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, - {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, - {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, - {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, + {file = "coverage-7.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944"}, + {file = "coverage-7.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4"}, + {file = "coverage-7.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98"}, + {file = "coverage-7.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f"}, + {file = "coverage-7.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd"}, + {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b"}, + {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c"}, + {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054"}, + {file = "coverage-7.7.0-cp310-cp310-win32.whl", hash = "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee"}, + {file = "coverage-7.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3"}, + {file = "coverage-7.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7"}, + {file = "coverage-7.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656"}, + {file = "coverage-7.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b"}, + {file = "coverage-7.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b"}, + {file = "coverage-7.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd"}, + {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba"}, + {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608"}, + {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5"}, + {file = "coverage-7.7.0-cp311-cp311-win32.whl", hash = "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a"}, + {file = "coverage-7.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4"}, + {file = "coverage-7.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94"}, + {file = "coverage-7.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db"}, + {file = "coverage-7.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe"}, + {file = "coverage-7.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8"}, + {file = "coverage-7.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135"}, + {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705"}, + {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0"}, + {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd"}, + {file = "coverage-7.7.0-cp312-cp312-win32.whl", hash = "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d"}, + {file = "coverage-7.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92"}, + {file = "coverage-7.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072"}, + {file = "coverage-7.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82"}, + {file = "coverage-7.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa"}, + {file = "coverage-7.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f"}, + {file = "coverage-7.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265"}, + {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2"}, + {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d"}, + {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39"}, + {file = "coverage-7.7.0-cp313-cp313-win32.whl", hash = "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68"}, + {file = "coverage-7.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573"}, + {file = "coverage-7.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322"}, + {file = "coverage-7.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce"}, + {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816"}, + {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf"}, + {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57"}, + {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4"}, + {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c"}, + {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463"}, + {file = "coverage-7.7.0-cp313-cp313t-win32.whl", hash = "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90"}, + {file = "coverage-7.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07"}, + {file = "coverage-7.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5"}, + {file = "coverage-7.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261"}, + {file = "coverage-7.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253"}, + {file = "coverage-7.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf"}, + {file = "coverage-7.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e"}, + {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b"}, + {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e"}, + {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d"}, + {file = "coverage-7.7.0-cp39-cp39-win32.whl", hash = "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c"}, + {file = "coverage-7.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59"}, + {file = "coverage-7.7.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c"}, + {file = "coverage-7.7.0-py3-none-any.whl", hash = "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a"}, + {file = "coverage-7.7.0.tar.gz", hash = "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166"}, ] [package.dependencies] @@ -2516,13 +2516,13 @@ files = [ [[package]] name = "pre-commit" -version = "4.1.0" +version = "4.2.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, - {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, + {file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"}, + {file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"}, ] [package.dependencies] @@ -2637,13 +2637,13 @@ tests = ["pytest"] [[package]] name = "pyasn1" -version = "0.6.1" -description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +version = "0.4.8" +description = "ASN.1 types and codecs" optional = true -python-versions = ">=3.8" +python-versions = "*" files = [ - {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, - {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, ] [[package]] @@ -2923,25 +2923,26 @@ cli = ["click (>=5.0)"] [[package]] name = "python-jose" -version = "3.3.0" +version = "3.4.0" description = "JOSE implementation in Python" optional = true python-versions = "*" files = [ - {file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"}, - {file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"}, + {file = "python-jose-3.4.0.tar.gz", hash = "sha256:9a9a40f418ced8ecaf7e3b28d69887ceaa76adad3bcaa6dae0d9e596fec1d680"}, + {file = "python_jose-3.4.0-py2.py3-none-any.whl", hash = "sha256:9c9f616819652d109bd889ecd1e15e9a162b9b94d682534c9c2146092945b78f"}, ] [package.dependencies] cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryptography\""} ecdsa = "!=0.15" -pyasn1 = "*" -rsa = "*" +pyasn1 = ">=0.4.1,<0.5.0" +rsa = ">=4.0,<4.1.1 || >4.1.1,<4.4 || >4.4,<5.0" [package.extras] cryptography = ["cryptography (>=3.4.0)"] -pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"] -pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"] +pycrypto = ["pycrypto (>=2.6.0,<2.7.0)"] +pycryptodome = ["pycryptodome (>=3.3.1,<4.0.0)"] +test = ["pytest", "pytest-cov"] [[package]] name = "python-json-logger" @@ -3285,13 +3286,13 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "setuptools" -version = "76.0.0" +version = "76.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6"}, - {file = "setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4"}, + {file = "setuptools-76.1.0-py3-none-any.whl", hash = "sha256:34750dcb17d046929f545dec9b8349fe42bf4ba13ddffee78428aec422dbfb73"}, + {file = "setuptools-76.1.0.tar.gz", hash = "sha256:4959b9ad482ada2ba2320c8f1a8d8481d4d8d668908a7a1b84d987375cd7f5bd"}, ] [package.extras] @@ -3736,13 +3737,13 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "types-awscrt" -version = "0.24.1" +version = "0.24.2" description = "Type annotations and code completion for awscrt" optional = false python-versions = ">=3.8" files = [ - {file = "types_awscrt-0.24.1-py3-none-any.whl", hash = "sha256:f3f2578ff74a254a79882b95961fb493ba217cebc350b3eb239d1cd948d4d7fa"}, - {file = "types_awscrt-0.24.1.tar.gz", hash = "sha256:fc6eae56f8dc5a3f8cc93cc2c7c332fa82909f8284fbe25e014c575757af397d"}, + {file = "types_awscrt-0.24.2-py3-none-any.whl", hash = "sha256:345ab84a4f75b26bfb816b249657855824a4f2d1ce5b58268c549f81fce6eccc"}, + {file = "types_awscrt-0.24.2.tar.gz", hash = "sha256:5826baf69ad5d29c76be49fc7df00222281fa31b14f99e9fb4492d71ec98fea5"}, ] [[package]] @@ -3772,13 +3773,13 @@ types-pyasn1 = "*" [[package]] name = "types-pytz" -version = "2025.1.0.20250204" +version = "2025.1.0.20250318" description = "Typing stubs for pytz" optional = false python-versions = ">=3.9" files = [ - {file = "types_pytz-2025.1.0.20250204-py3-none-any.whl", hash = "sha256:32ca4a35430e8b94f6603b35beb7f56c32260ddddd4f4bb305fdf8f92358b87e"}, - {file = "types_pytz-2025.1.0.20250204.tar.gz", hash = "sha256:00f750132769f1c65a4f7240bc84f13985b4da774bd17dfbe5d9cd442746bd49"}, + {file = "types_pytz-2025.1.0.20250318-py3-none-any.whl", hash = "sha256:04dba4907c5415777083f9548693c6d9f80ec53adcaff55a38526a3f8ddcae04"}, + {file = "types_pytz-2025.1.0.20250318.tar.gz", hash = "sha256:97e0e35184c6fe14e3a5014512057f2c57bb0c6582d63c1cfcc4809f82180449"}, ] [[package]] @@ -4240,4 +4241,4 @@ server = ["alembic", "alembic-utils", "arq", "authlib", "biocommons", "boto3", " [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "14d7a4b130c68372ffcf53f309375451eeda86bee1cbc0aad163819443e77e4b" +content-hash = "85d3bb6397635a718f38d11a0a02d0594ade1c30dcfe02e74a9507952ec6e5f1" diff --git a/pyproject.toml b/pyproject.toml index 1e5b254c..ef819081 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ fastapi = { version = "~0.95.0", optional = true } hgvs = { version = "~1.5.4", optional = true } orcid = { version = "~1.0.3", optional = true } psycopg2 = { version = "~2.9.3", optional = true } -python-jose = { extras = ["cryptography"], version = "~3.3.0", optional = true } +python-jose = { extras = ["cryptography"], version = "~3.4.0", optional = true } python-multipart = { version = "~0.0.5", optional = true } requests = { version = "~2.32.0", optional = true } starlette = { version = "~0.27.0", optional = true } From 4deebf0fe4274a8f1bac1f33c1fdb05f4d23cf9e Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Fri, 14 Mar 2025 03:11:21 -0700 Subject: [PATCH 18/20] Add Additional Statistics Routes Adds an additional two statistics routes for aggregate mapped variant data based on score sets. These routes make use of the new materialized view for published variants. --- src/mavedb/routers/score_sets.py | 31 +++++++++++++++++++++++++++++++ src/mavedb/routers/statistics.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/mavedb/routers/score_sets.py b/src/mavedb/routers/score_sets.py index 235f436f..65e83c0f 100644 --- a/src/mavedb/routers/score_sets.py +++ b/src/mavedb/routers/score_sets.py @@ -138,6 +138,37 @@ def search_score_sets( return fetch_superseding_score_set_in_search_result(score_sets, user_data, search) +@router.get("/score-sets/mapped-genes", status_code=200, response_model=dict[str, list[str]]) +def score_set_mapped_gene_mapping( + db: Session = Depends(deps.get_db), user_data: UserData = Depends(get_current_user) +) -> Any: + """ + Get a mapping of score set URNs to mapped gene symbols. + """ + save_to_logging_context({"requested_resource": "mapped-genes"}) + + score_sets_with_mapping_metadata = db.execute( + select(ScoreSet, TargetGene.post_mapped_metadata) + .join(ScoreSet) + .where(TargetGene.post_mapped_metadata.is_not(None)) + ).all() + + mapped_genes: dict[str, list[str]] = {} + for score_set_item, post_mapped_metadata in score_sets_with_mapping_metadata: + if not has_permission(user_data, score_set_item, Action.READ).permitted: + continue + + sequence_genes = [ + *post_mapped_metadata.get("genomic", {}).get("sequence_genes", []), + *post_mapped_metadata.get("protein", {}).get("sequence_genes", []), + ] + + if sequence_genes: + mapped_genes.setdefault(score_set_item.urn, []).extend(sequence_genes) + + return mapped_genes + + @router.post( "/me/score-sets/search", status_code=200, diff --git a/src/mavedb/routers/statistics.py b/src/mavedb/routers/statistics.py index f79d07f6..876eac14 100644 --- a/src/mavedb/routers/statistics.py +++ b/src/mavedb/routers/statistics.py @@ -277,6 +277,38 @@ def record_counts(model: RecordNames, group: Optional[GroupBy] = None, db: Sessi return OrderedDict(sorted(grouped.items())) +@router.get("/record/score-set/variant/count", status_code=200, response_model=dict[str, int]) +def record_variant_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the number of published and distinct variants in the database contained + within a given record. + """ + variants = db.execute( + select(PublishedVariantsMV.score_set_urn, func.count(PublishedVariantsMV.variant_id)) + .group_by(PublishedVariantsMV.score_set_urn) + .order_by(PublishedVariantsMV.score_set_urn) + ).all() + + grouped = {urn: sum(c for _, c in g) for urn, g in itertools.groupby(variants, lambda t: t[0])} + return OrderedDict(sorted(filter(lambda item: item[1] > 0, grouped.items()))) + + +@router.get("/record/score-set/mapped-variant/count", status_code=200, response_model=dict[str, int]) +def record_mapped_variant_counts(db: Session = Depends(get_db)) -> dict[str, int]: + """ + Returns a dictionary of counts for the number of published and distinct mapped variants in the database contained + within a given record. + """ + variants = db.execute( + select(PublishedVariantsMV.score_set_urn, func.count(PublishedVariantsMV.mapped_variant_id)) + .group_by(PublishedVariantsMV.score_set_urn) + .order_by(PublishedVariantsMV.score_set_urn) + ).all() + + grouped = {urn: sum(c for _, c in g) for urn, g in itertools.groupby(variants, lambda t: t[0])} + return OrderedDict(sorted(filter(lambda item: item[1] > 0, grouped.items()))) + + ######################################################################################## # Target statistics ######################################################################################## From 418762f680bd6338d80f295f3e36136503b47962 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Tue, 18 Mar 2025 20:46:23 -0700 Subject: [PATCH 19/20] Cron timer in USA AM via UTC --- src/mavedb/worker/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mavedb/worker/settings.py b/src/mavedb/worker/settings.py index 5e393259..9a60dcdc 100644 --- a/src/mavedb/worker/settings.py +++ b/src/mavedb/worker/settings.py @@ -23,8 +23,10 @@ map_variants_for_score_set, refresh_published_variants_view, ] +# In UTC time. Depending on daylight savings time, this will bounce around by an hour but should always be very early in the morning +# for all of the USA. BACKGROUND_CRONJOBS: list[CronJob] = [ - cron(refresh_materialized_views, name="refresh_all_materialized_views", hour=3, minute=0) + cron(refresh_materialized_views, name="refresh_all_materialized_views", hour=20, minute=0) ] REDIS_IP = os.getenv("REDIS_IP") or "localhost" From 7c809fba5310266083d5d5b8c91d53260a7a4f14 Mon Sep 17 00:00:00 2001 From: Ben Capodanno Date: Tue, 18 Mar 2025 21:44:55 -0700 Subject: [PATCH 20/20] Bump version number --- pyproject.toml | 2 +- src/mavedb/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ef819081..79467b15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "mavedb" -version = "2025.1.0" +version = "2025.1.1" description = "API for MaveDB, the database of Multiplexed Assays of Variant Effect." license = "AGPL-3.0-only" readme = "README.md" diff --git a/src/mavedb/__init__.py b/src/mavedb/__init__.py index 09616348..4e185732 100644 --- a/src/mavedb/__init__.py +++ b/src/mavedb/__init__.py @@ -6,6 +6,6 @@ logger = module_logging.getLogger(__name__) __project__ = "mavedb-api" -__version__ = "2025.1.0" +__version__ = "2025.1.1" logger.info(f"MaveDB {__version__}")