From 6dc6aa6a171a8ccf41f345b3756107812caebc3f Mon Sep 17 00:00:00 2001 From: dcarron <daniel.carron@idiap.ch> Date: Tue, 7 May 2024 16:13:52 +0200 Subject: [PATCH] [tests] Update tests --- .gitmodules | 0 pyproject.toml | 2 +- ...histograms_alexnet_montgomery_default.json | 0 ...grams_densenet-121_montgomery_default.json | 0 .../histograms_pasa_montgomery_default.json | 0 .../raw_data/histograms_hivtb_fold_0.json | 0 .../raw_data/histograms_indian_default.json | 0 .../histograms_montgomery_default.json | 0 ...grams_montgomery_preprocessed_default.json | 0 .../histograms_nih_cxr14_default.json | 0 .../raw_data/histograms_padchest_idiap.json | 0 .../raw_data/histograms_shenzhen_default.json | 0 .../raw_data/histograms_tbpoc_fold_0.json | 0 .../raw_data/histograms_tbx11k_v1_fold_0.json | 0 .../raw_data/histograms_tbx11k_v2_fold_0.json | 0 .../tests/data/lfs/.gitattributes | 6 + .../classification/tests/data/lfs/.gitignore | 1 + .../classification/tests/data/lfs/README.md | 14 ++ .../tests/data/lfs/models/logreg.ckpt | Bin 0 -> 3211 bytes .../tests/data/lfs/models/signstotb.ckpt | Bin 0 -> 6363 bytes .../classification/tests}/data/mednet.toml | 0 .../tests/data/test_predictions.csv | 10 + .../tests/data/test_vis_metrics.csv | 6 + .../tests/test_cli_classification.py | 20 -- .../classification/tests}/test_evaluator.py | 0 .../libs/classification/tests}/test_hivtb.py | 0 .../libs/classification/tests}/test_indian.py | 0 .../classification/tests}/test_montgomery.py | 0 .../tests}/test_montgomery_shenzhen.py | 0 .../tests}/test_montgomery_shenzhen_indian.py | 0 ...est_montgomery_shenzhen_indian_padchest.py | 0 .../test_montgomery_shenzhen_indian_tbx11k.py | 0 .../classification/tests}/test_nih_cxr14.py | 0 .../tests}/test_nih_cxr14_padchest.py | 0 .../classification/tests}/test_padchest.py | 0 .../test_saliencymap_interpretability.py | 0 .../classification/tests}/test_shenzhen.py | 0 .../classification/tests}/test_summary.py | 0 .../libs/classification/tests}/test_tbpoc.py | 0 .../libs/classification/tests}/test_tbx11k.py | 0 .../classification/tests}/test_visceral.py | 4 +- src/mednet/libs/common/scripts/upload.py | 211 ++++++++++++++++++ .../mednet/libs/common/tests}/conftest.py | 0 .../mednet/libs/common/tests}/data/16bits.png | Bin .../libs/common/tests/data/iris-test.csv | 75 +++++++ .../libs/common/tests/data/iris-train.csv | 75 +++++++ .../mednet/libs/common/tests}/data/iris.json | 0 .../tests}/data/raw_with_black_border.png | Bin .../data/raw_with_elastic_deformation.png | Bin .../tests}/data/raw_without_black_border.png | Bin .../data/raw_without_elastic_deformation.png | Bin .../libs/common/tests}/test_database_split.py | 0 .../libs/common/tests}/test_image_utils.py | 0 .../common/tests}/test_resource_monitor.py | 0 .../libs/common/tests}/test_transforms.py | 0 src/mednet/libs/common/utils/gitlab.py | 92 ++++++++ src/mednet/tests/test_cli.py | 65 ++++++ 57 files changed, 558 insertions(+), 23 deletions(-) create mode 100644 .gitmodules rename {tests => src/mednet/libs/classification/tests}/data/histograms/models/histograms_alexnet_montgomery_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/models/histograms_densenet-121_montgomery_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/models/histograms_pasa_montgomery_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_hivtb_fold_0.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_indian_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_montgomery_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_montgomery_preprocessed_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_nih_cxr14_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_padchest_idiap.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_shenzhen_default.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_tbpoc_fold_0.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_tbx11k_v1_fold_0.json (100%) rename {tests => src/mednet/libs/classification/tests}/data/histograms/raw_data/histograms_tbx11k_v2_fold_0.json (100%) create mode 100644 src/mednet/libs/classification/tests/data/lfs/.gitattributes create mode 100644 src/mednet/libs/classification/tests/data/lfs/.gitignore create mode 100644 src/mednet/libs/classification/tests/data/lfs/README.md create mode 100644 src/mednet/libs/classification/tests/data/lfs/models/logreg.ckpt create mode 100644 src/mednet/libs/classification/tests/data/lfs/models/signstotb.ckpt rename {tests => src/mednet/libs/classification/tests}/data/mednet.toml (100%) create mode 100644 src/mednet/libs/classification/tests/data/test_predictions.csv create mode 100644 src/mednet/libs/classification/tests/data/test_vis_metrics.csv rename tests/test_cli.py => src/mednet/libs/classification/tests/test_cli_classification.py (96%) rename {tests => src/mednet/libs/classification/tests}/test_evaluator.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_hivtb.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_indian.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_montgomery.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_montgomery_shenzhen.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_montgomery_shenzhen_indian.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_montgomery_shenzhen_indian_padchest.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_montgomery_shenzhen_indian_tbx11k.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_nih_cxr14.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_nih_cxr14_padchest.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_padchest.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_saliencymap_interpretability.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_shenzhen.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_summary.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_tbpoc.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_tbx11k.py (100%) rename {tests => src/mednet/libs/classification/tests}/test_visceral.py (90%) create mode 100644 src/mednet/libs/common/scripts/upload.py rename {tests => src/mednet/libs/common/tests}/conftest.py (100%) rename {tests => src/mednet/libs/common/tests}/data/16bits.png (100%) create mode 100644 src/mednet/libs/common/tests/data/iris-test.csv create mode 100644 src/mednet/libs/common/tests/data/iris-train.csv rename {tests => src/mednet/libs/common/tests}/data/iris.json (100%) rename {tests => src/mednet/libs/common/tests}/data/raw_with_black_border.png (100%) rename {tests => src/mednet/libs/common/tests}/data/raw_with_elastic_deformation.png (100%) rename {tests => src/mednet/libs/common/tests}/data/raw_without_black_border.png (100%) rename {tests => src/mednet/libs/common/tests}/data/raw_without_elastic_deformation.png (100%) rename {tests => src/mednet/libs/common/tests}/test_database_split.py (100%) rename {tests => src/mednet/libs/common/tests}/test_image_utils.py (100%) rename {tests => src/mednet/libs/common/tests}/test_resource_monitor.py (100%) rename {tests => src/mednet/libs/common/tests}/test_transforms.py (100%) create mode 100644 src/mednet/libs/common/utils/gitlab.py create mode 100644 src/mednet/tests/test_cli.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/pyproject.toml b/pyproject.toml index d4e1aef6..faf01b79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -476,7 +476,7 @@ convention = "numpy" [tool.ruff.lint.per-file-ignores] "helpers/*.py" = ["T201", "D103"] -"tests/*.py" = ["D", "E501"] +"**/tests/*.py" = ["D", "E501"] "doc/conf.py" = ["D"] "**/scripts/*.py" = ["E501"] diff --git a/tests/data/histograms/models/histograms_alexnet_montgomery_default.json b/src/mednet/libs/classification/tests/data/histograms/models/histograms_alexnet_montgomery_default.json similarity index 100% rename from tests/data/histograms/models/histograms_alexnet_montgomery_default.json rename to src/mednet/libs/classification/tests/data/histograms/models/histograms_alexnet_montgomery_default.json diff --git a/tests/data/histograms/models/histograms_densenet-121_montgomery_default.json b/src/mednet/libs/classification/tests/data/histograms/models/histograms_densenet-121_montgomery_default.json similarity index 100% rename from tests/data/histograms/models/histograms_densenet-121_montgomery_default.json rename to src/mednet/libs/classification/tests/data/histograms/models/histograms_densenet-121_montgomery_default.json diff --git a/tests/data/histograms/models/histograms_pasa_montgomery_default.json b/src/mednet/libs/classification/tests/data/histograms/models/histograms_pasa_montgomery_default.json similarity index 100% rename from tests/data/histograms/models/histograms_pasa_montgomery_default.json rename to src/mednet/libs/classification/tests/data/histograms/models/histograms_pasa_montgomery_default.json diff --git a/tests/data/histograms/raw_data/histograms_hivtb_fold_0.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_hivtb_fold_0.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_hivtb_fold_0.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_hivtb_fold_0.json diff --git a/tests/data/histograms/raw_data/histograms_indian_default.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_indian_default.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_indian_default.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_indian_default.json diff --git a/tests/data/histograms/raw_data/histograms_montgomery_default.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_montgomery_default.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_montgomery_default.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_montgomery_default.json diff --git a/tests/data/histograms/raw_data/histograms_montgomery_preprocessed_default.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_montgomery_preprocessed_default.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_montgomery_preprocessed_default.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_montgomery_preprocessed_default.json diff --git a/tests/data/histograms/raw_data/histograms_nih_cxr14_default.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_nih_cxr14_default.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_nih_cxr14_default.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_nih_cxr14_default.json diff --git a/tests/data/histograms/raw_data/histograms_padchest_idiap.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_padchest_idiap.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_padchest_idiap.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_padchest_idiap.json diff --git a/tests/data/histograms/raw_data/histograms_shenzhen_default.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_shenzhen_default.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_shenzhen_default.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_shenzhen_default.json diff --git a/tests/data/histograms/raw_data/histograms_tbpoc_fold_0.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbpoc_fold_0.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_tbpoc_fold_0.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbpoc_fold_0.json diff --git a/tests/data/histograms/raw_data/histograms_tbx11k_v1_fold_0.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbx11k_v1_fold_0.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_tbx11k_v1_fold_0.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbx11k_v1_fold_0.json diff --git a/tests/data/histograms/raw_data/histograms_tbx11k_v2_fold_0.json b/src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbx11k_v2_fold_0.json similarity index 100% rename from tests/data/histograms/raw_data/histograms_tbx11k_v2_fold_0.json rename to src/mednet/libs/classification/tests/data/histograms/raw_data/histograms_tbx11k_v2_fold_0.json diff --git a/src/mednet/libs/classification/tests/data/lfs/.gitattributes b/src/mednet/libs/classification/tests/data/lfs/.gitattributes new file mode 100644 index 00000000..ebbbf5f9 --- /dev/null +++ b/src/mednet/libs/classification/tests/data/lfs/.gitattributes @@ -0,0 +1,6 @@ +_test_densenetrs_checkpoint.pth filter=lfs diff=lfs merge=lfs -text +_test_fpasa_checkpoint.pth filter=lfs diff=lfs merge=lfs -text +_test_logreg_checkpoint.pth filter=lfs diff=lfs merge=lfs -text +_test_signstotb_checkpoint.pth filter=lfs diff=lfs merge=lfs -text +_testdb.zip filter=lfs diff=lfs merge=lfs -text +pasa.pth filter=lfs diff=lfs merge=lfs -text diff --git a/src/mednet/libs/classification/tests/data/lfs/.gitignore b/src/mednet/libs/classification/tests/data/lfs/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/src/mednet/libs/classification/tests/data/lfs/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/src/mednet/libs/classification/tests/data/lfs/README.md b/src/mednet/libs/classification/tests/data/lfs/README.md new file mode 100644 index 00000000..bc66bf5e --- /dev/null +++ b/src/mednet/libs/classification/tests/data/lfs/README.md @@ -0,0 +1,14 @@ +# Assets for Testing biosignal/software/mednet> + +This package contains test unit assets used by the test suit of +biosignal/software/mednet>. + + +## Updating + +To update the contents of this package, use [git-lfs](https://git-lfs.com), +following the workflow described at the [GitLab support +page](https://docs.gitlab.com/ee/topics/git/lfs/). + +Cloning and updating the repository, in particular, works the same as before +and should not impose any workflow changes. diff --git a/src/mednet/libs/classification/tests/data/lfs/models/logreg.ckpt b/src/mednet/libs/classification/tests/data/lfs/models/logreg.ckpt new file mode 100644 index 0000000000000000000000000000000000000000..b8609b572753ff637cac6edb39d643ec683abebb GIT binary patch literal 3211 zcmbW3Ym5_B6vwAq=<b%Kyt)gEycO;8=(fAtF6{zc%F+VEqjW`vm&0s3bOzeaoO#q; zOc4yA_*jiW`GCO~B{6DnHGWuJ$f}7-K#dShkPjM(@skN^NDPT4-g~E8I;EoNO(rv$ zx#xGzz2|@KoEU8#M^SZk)Lo;AYM^vE$!UC&%}7Z;-HM($x4b_c3D;3O3gb{s9w-+x z9+{I#U`ZsTbed0SqLfwbo0TN5@W~!Aq1mCPB@R{>GZD>Ai&>si+>h~MO3+|jLX(t) z;AVAAOsjTQ;rnzkon$pWt4a!+YqP_6my4-IhANuLrFgIzCiX~L;<R4lr5$P+3!3AB zI>w6b30a4F+M$7c3r*1$+Hnjf&<@&i3>uCLIGBkVIN~sgnQ$kfK9N&lvVhzPHo?Go zVTw>sTQrzTFh^k;Z8-`~1JS5KQyiu<PV7$+HC{pMcFU5=7S=Yy#A<_PgEh0jx(~Bv z8LZhF%!$KXW@agi&2eclSxTH|BDTYPgSenTydM)EFo+8^crXqR>3MK5^@z%5c#Xqp zgch;^i(CwPOTpqiEFs&Q;}sPx0G84gm9e2uMxwx-hgJc<)YU#hl4MQHhzEEDJbCaM z0#G$17HG>uyNjms(BWc`v{1%)8GIXGwGsz>zsz#E6!=Yx=zvbN2$ZR1#Y_c^Oa+aF zbZM|W4l5Wt0u~Ug3b4{d@j=L-bQdYB3`*Fbtk$3>4r_GUl81;(z(EP-K>QFjc5`iE zH`n3aTyL1u8f=KeM#1d06E+zpn+ql}Y_i2LiEGdshlh2YX+V+7oWf<;lp^V}3R`!> zBYD{7VruX<E5JlUM-KcHJ?ng&R8t?ylnUFUp<lnm<Ev=s=AU1G-}KbtW3Yp$n@5bD z(Uofk25)$t3lhE|IX1~BxB=KjQ)I`vjG9uoB<wy;5=vrF;nCf|qAbxCUgvb;ke8)| z0DI^~B)=K1pEcfabQ{x*gC8J8x-^YTHY;XR?3h^kh`rbCaeE*^iYb+r`nWVpQlCU| zOh)#?fXpi_anGYNQGw6HUPG3}!hsYs4NVQNUb9Wqgbh+k)YJ`<s=8W0U?!n2#hFG~ zfG7xMa@<Emw<^hHU_UbjnG}`ECZz0MF{MH}51FxD&lY!GCE^mZvaYczQZ`7mLnrTu zuGu6y!$20Sx;sYK)?L{=&~ppP8(*=1Jwu(8y}}vV>WPGHg%kAZ@Oz_A4__L6`Ot5n z**BkG>EMP!4WHf&)edg#j&^@C`kD9l(7qMT-M7!wcYkr@-B9n&x^C;U*FrdkQ@0k% z%g_q(b*~s~m16Kl!Zj!cG2!?av#$O<%Y~~IU-x1KE3w)lVSn+DF!pEoe|J$DB5Ro_ zgmYE<Z?E2e^NnHRfBmI(%d7U^QN91n&qE{If0)&EWcsd=;1>V+sqgqlVv+br?~5Ot zZ$9{8*Ix(W+?(^C4E}g}(a0~}Z$3IX<J;lwxfhn<oIP=Y-BES^eMbH}wR1u1t<k{s z3%i1oeAk1gI^Pd`J{JPl_Iww#pIs2V-2aMi-eq^!zD+{`>uYayy*+ryx9yL)0qj5b zOz?2k{{4pkGt(w4$E;0*_TyFWe`odkf4eb3{I7eX|Mma&-$(_@^j|mwBVk{41<-EC ztG{wOwH5yc@P&RK_*U%6N>7?5{J}ITcWC8|(vt#rDtAT?>fG*Tw0g=3rRRg0aIrGM zTTUpga5KS)8jT7uw3QP|Yt&3QQJK(QPAIJyGr@_P%L*}cloLudZzf!<Oz@QxN|kOV ztVLaTg&6$hgi@`V2`4HOI?D;AdTYER2K3}aZK64bg2H38&9<a4b&hpu(Fk{Bc#Pdo l67f>hOSs=e1KHueooc}i5E{5akJ00CZ;5Q|6rOL){Rdx2AL9T3 literal 0 HcmV?d00001 diff --git a/src/mednet/libs/classification/tests/data/lfs/models/signstotb.ckpt b/src/mednet/libs/classification/tests/data/lfs/models/signstotb.ckpt new file mode 100644 index 0000000000000000000000000000000000000000..59ea4595166b871e031c9664c1e0581081f3412e GIT binary patch literal 6363 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 BOdbFL literal 0 HcmV?d00001 diff --git a/tests/data/mednet.toml b/src/mednet/libs/classification/tests/data/mednet.toml similarity index 100% rename from tests/data/mednet.toml rename to src/mednet/libs/classification/tests/data/mednet.toml diff --git a/src/mednet/libs/classification/tests/data/test_predictions.csv b/src/mednet/libs/classification/tests/data/test_predictions.csv new file mode 100644 index 00000000..5de618e0 --- /dev/null +++ b/src/mednet/libs/classification/tests/data/test_predictions.csv @@ -0,0 +1,10 @@ +filename,likelihood,ground_truth +file1,"[6.1538161e-01 1.4814811e-03 6.5176686e-05 1.0000000e+00 5.1068876e-01 + 1.8108148e-04 3.6165615e-01 1.4568567e-01 4.8867718e-05 5.0666117e-05 + 5.1114771e-07 1.3583761e-01 6.0767888e-11 1.5170315e-08]",[1.] +file2,"[6.3864078e-04 3.6866156e-03 8.4878616e-08 6.3316641e-01 4.4661388e-01 + 7.6667184e-04 1.1361861e-03 4.6111313e-03 4.3461104e-04 1.1185581e-06 + 1.1631314e-06 3.7814886e-06 6.1658076e-11 3.5506051e-08]",[0.] +file3,"[1.3780616e-05 1.8464373e-05 1.4054011e-07 1.6511037e-03 7.0664110e-01 + 6.0737631e-03 7.3566751e-03 3.0668571e-04 3.1133456e-05 5.0116336e-07 + 1.5665150e-04 1.0710500e-08 4.1036647e-06 1.1140607e-07]",[1.] diff --git a/src/mednet/libs/classification/tests/data/test_vis_metrics.csv b/src/mednet/libs/classification/tests/data/test_vis_metrics.csv new file mode 100644 index 00000000..1a144f21 --- /dev/null +++ b/src/mednet/libs/classification/tests/data/test_vis_metrics.csv @@ -0,0 +1,6 @@ +Image,MoRF,LeRF,Combined Score ((LeRF-MoRF) / 2),IoU,IoDA,propEnergy,ASF +tb0004.png,1,2,3,4,5,6,7 +tb0006.png,2,3,4,5,6,7,8 +tb0009.png,1,2,3,4,5,6,7 +tb0014.png,2,3,4,5,6,7,8 +tb0015.png,1,2,3,4,5,6,7 diff --git a/tests/test_cli.py b/src/mednet/libs/classification/tests/test_cli_classification.py similarity index 96% rename from tests/test_cli.py rename to src/mednet/libs/classification/tests/test_cli_classification.py index bb3c1ced..f735ae17 100644 --- a/tests/test_cli.py +++ b/src/mednet/libs/classification/tests/test_cli_classification.py @@ -40,26 +40,6 @@ def _check_help(entry_point): assert result.output.startswith("Usage:") -def test_info_help(): - from mednet.scripts.info import info - - _check_help(info) - - -def test_info(): - from mednet.scripts.info import info - - runner = CliRunner() - result = runner.invoke(info) - _assert_exit_0(result) - assert "platform:" in result.output - assert "accelerators:" in result.output - assert "version:" in result.output - assert "configured databases:" in result.output - assert "dependencies:" in result.output - assert "python:" in result.output - - def test_config_help(): from mednet.libs.classification.scripts.config import config diff --git a/tests/test_evaluator.py b/src/mednet/libs/classification/tests/test_evaluator.py similarity index 100% rename from tests/test_evaluator.py rename to src/mednet/libs/classification/tests/test_evaluator.py diff --git a/tests/test_hivtb.py b/src/mednet/libs/classification/tests/test_hivtb.py similarity index 100% rename from tests/test_hivtb.py rename to src/mednet/libs/classification/tests/test_hivtb.py diff --git a/tests/test_indian.py b/src/mednet/libs/classification/tests/test_indian.py similarity index 100% rename from tests/test_indian.py rename to src/mednet/libs/classification/tests/test_indian.py diff --git a/tests/test_montgomery.py b/src/mednet/libs/classification/tests/test_montgomery.py similarity index 100% rename from tests/test_montgomery.py rename to src/mednet/libs/classification/tests/test_montgomery.py diff --git a/tests/test_montgomery_shenzhen.py b/src/mednet/libs/classification/tests/test_montgomery_shenzhen.py similarity index 100% rename from tests/test_montgomery_shenzhen.py rename to src/mednet/libs/classification/tests/test_montgomery_shenzhen.py diff --git a/tests/test_montgomery_shenzhen_indian.py b/src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian.py similarity index 100% rename from tests/test_montgomery_shenzhen_indian.py rename to src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian.py diff --git a/tests/test_montgomery_shenzhen_indian_padchest.py b/src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian_padchest.py similarity index 100% rename from tests/test_montgomery_shenzhen_indian_padchest.py rename to src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian_padchest.py diff --git a/tests/test_montgomery_shenzhen_indian_tbx11k.py b/src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian_tbx11k.py similarity index 100% rename from tests/test_montgomery_shenzhen_indian_tbx11k.py rename to src/mednet/libs/classification/tests/test_montgomery_shenzhen_indian_tbx11k.py diff --git a/tests/test_nih_cxr14.py b/src/mednet/libs/classification/tests/test_nih_cxr14.py similarity index 100% rename from tests/test_nih_cxr14.py rename to src/mednet/libs/classification/tests/test_nih_cxr14.py diff --git a/tests/test_nih_cxr14_padchest.py b/src/mednet/libs/classification/tests/test_nih_cxr14_padchest.py similarity index 100% rename from tests/test_nih_cxr14_padchest.py rename to src/mednet/libs/classification/tests/test_nih_cxr14_padchest.py diff --git a/tests/test_padchest.py b/src/mednet/libs/classification/tests/test_padchest.py similarity index 100% rename from tests/test_padchest.py rename to src/mednet/libs/classification/tests/test_padchest.py diff --git a/tests/test_saliencymap_interpretability.py b/src/mednet/libs/classification/tests/test_saliencymap_interpretability.py similarity index 100% rename from tests/test_saliencymap_interpretability.py rename to src/mednet/libs/classification/tests/test_saliencymap_interpretability.py diff --git a/tests/test_shenzhen.py b/src/mednet/libs/classification/tests/test_shenzhen.py similarity index 100% rename from tests/test_shenzhen.py rename to src/mednet/libs/classification/tests/test_shenzhen.py diff --git a/tests/test_summary.py b/src/mednet/libs/classification/tests/test_summary.py similarity index 100% rename from tests/test_summary.py rename to src/mednet/libs/classification/tests/test_summary.py diff --git a/tests/test_tbpoc.py b/src/mednet/libs/classification/tests/test_tbpoc.py similarity index 100% rename from tests/test_tbpoc.py rename to src/mednet/libs/classification/tests/test_tbpoc.py diff --git a/tests/test_tbx11k.py b/src/mednet/libs/classification/tests/test_tbx11k.py similarity index 100% rename from tests/test_tbx11k.py rename to src/mednet/libs/classification/tests/test_tbx11k.py diff --git a/tests/test_visceral.py b/src/mednet/libs/classification/tests/test_visceral.py similarity index 90% rename from tests/test_visceral.py rename to src/mednet/libs/classification/tests/test_visceral.py index 9743577e..77d0e94b 100644 --- a/tests/test_visceral.py +++ b/src/mednet/libs/classification/tests/test_visceral.py @@ -25,7 +25,7 @@ def test_protocol_consistency( split: str, lenghts: dict[str, int], ): - from mednet.data.split import make_split + from mednet.libs.common.data.split import make_split database_checkers.check_split( make_split("mednet.config.data.visceral", f"{split}.json"), @@ -37,7 +37,7 @@ def test_protocol_consistency( @pytest.mark.skip_if_rc_var_not_set("datadir.visceral") def test_database_check(): - from mednet.scripts.database import check + from mednet.libs.common.scripts.database import check runner = CliRunner() result = runner.invoke(check, ["visceral"]) diff --git a/src/mednet/libs/common/scripts/upload.py b/src/mednet/libs/common/scripts/upload.py new file mode 100644 index 00000000..ccca1ce8 --- /dev/null +++ b/src/mednet/libs/common/scripts/upload.py @@ -0,0 +1,211 @@ +# SPDX-FileCopyrightText: Copyright © 2023 Idiap Research Institute <contact@idiap.ch> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +import pathlib + +import click +from clapper.click import ResourceOption, verbosity_option +from clapper.logging import setup + +from .click import ConfigCommand + +logger = setup(__name__.split(".")[0], format="%(levelname)s: %(message)s") + + +@click.command( + entry_point_group="mednet.config", + cls=ConfigCommand, + epilog="""Examples: + +1. Upload an existing experiment result from a path it resides on (with a default experiment name as {model-name}_{database-name} and a default run name as {date-time}): + + .. code:: sh + + mednet upload --experiment-folder=/path/to/results + +2. Upload an existing experiment result with an experiment name: + + .. code:: sh + + mednet upload --experiment-folder=/path/to/results --experiment-name=exp-pasa_mc + +3. Upload an existing experiment result with a run name: + + .. code:: sh + + mednet upload --experiment-folder=/path/to/results --run-name=run-1 + +4. Upload an existing experiment result with defining a size limit of 20MB for each file: + + .. code:: sh + + mednet upload --experiment-folder=/path/to/results --upload-limit-mb=20 + +""", +) +@click.option( + "--project-path", + "-p", + help="Path to the project where to upload model entries", + required=True, + type=str, + default="biosignal/software/mednet", + show_default=True, + cls=ResourceOption, +) +@click.option( + "--experiment-folder", + "-f", + help="Directory in which to upload results from", + required=True, + type=click.Path( + file_okay=False, + dir_okay=True, + path_type=pathlib.Path, + ), + default="results", + show_default=True, + cls=ResourceOption, +) +@click.option( + "--experiment-name", + "-e", + help='A string indicating the experiment name (e.g. "exp-pasa-mc" or "exp-densenet-mc-ch")', + cls=ResourceOption, +) +@click.option( + "--run-name", + "-r", + help='A string indicating the run name (e.g. "run-1")', + cls=ResourceOption, +) +@click.option( + "--upload-limit-mb", + "-l", + help="Maximim upload size in MB (set to 0 for no limit).", + show_default=True, + required=True, + default=10, + type=click.IntRange(min=0), + cls=ResourceOption, +) +@verbosity_option(logger=logger, cls=ResourceOption, expose_value=False) +def upload( + project_path: str, + experiment_folder: pathlib.Path, + experiment_name: str, + run_name: str, + upload_limit_mb: int, + **_, # ignored +) -> None: # numpydoc ignore=PR01 + """Upload results from an experiment folder to GitLab's MLFlow server.""" + + import json + import os + import tempfile + + import mlflow + from mednet.libs.common.utils.checkpointer import ( + get_checkpoint_to_run_inference, + ) + from mednet.libs.common.utils.gitlab import ( + gitlab_instance_and_token, + sanitize_filename, + size_in_mb, + ) + + logger.info( + "Retrieving GitLab credentials for access to hosted MLFlow server..." + ) + gitlab, token = gitlab_instance_and_token() + project = gitlab.projects.get(project_path) + os.environ["MLFLOW_TRACKING_TOKEN"] = token + os.environ["MLFLOW_TRACKING_URI"] = ( + gitlab.api_url + f"/projects/{project.id}/ml/mlflow" + ) + + # get train files + train_folder = experiment_folder / "model" + train_meta_file = train_folder / "meta.json" + train_log_file = train_folder / "trainlog.pdf" + train_model_file = get_checkpoint_to_run_inference(train_folder) + train_files = [train_meta_file, train_model_file, train_log_file] + + # get evaluation files + evaluation_file = experiment_folder / "evaluation.json" + evaluation_meta_file = experiment_folder / "evaluation.meta.json" + evaluation_log_file = experiment_folder / "evaluation.pdf" + evaluation_files = [ + evaluation_file, + evaluation_meta_file, + evaluation_log_file, + ] + + # checks for maximum upload limit + total_size_mb = sum([size_in_mb(f) for f in train_files + evaluation_files]) + if upload_limit_mb != 0 and total_size_mb > upload_limit_mb: + raise RuntimeError( + f"Total size of upload ({total_size_mb:.2f} MB) exceeds " + f"permitted maximum ({upload_limit_mb:.2f} MB)." + ) + + # prepare experiment and run names + with train_meta_file.open("r") as meta_file: + train_data = json.load(meta_file) + + with evaluation_file.open("r") as meta_file: + evaluation_data = json.load(meta_file) + evaluation_data = evaluation_data["test"] + + experiment_name = ( + experiment_name + or f"{train_data['model-name']}-{train_data['database-name']}" + ) + run_name = run_name or train_data["datetime"] + + click.secho( + f"Uploading entry `{run_name}` to experiment `{experiment_name}` " + f"on GitLab project {project_path} (id: {project.id})...", + bold=True, + fg="green", + ) + exp_meta = mlflow.set_experiment(experiment_name=experiment_name) + with mlflow.start_run(run_name=run_name): + click.echo("Uploading package metadata...") + click.echo(f" -> `version` ({train_data['package-version']})") + mlflow.log_param("package version", train_data["package-version"]) + + click.echo("Uploading metrics...") + + for k in [ + "threshold", + "precision", + "recall", + "f1_score", + "average_precision_score", + "specificity", + "auc_score", + "accuracy", + ]: + click.secho(f" -> `{k}` ({evaluation_data[k]:.3g})") + mlflow.log_metric(k, evaluation_data[k]) + + click.echo("Uploading artifacts (files)...") + + with tempfile.TemporaryDirectory() as tmpdir_name: + tmpdir = pathlib.Path(tmpdir_name) + for f in train_files + evaluation_files: + assert f.exists(), f"File `{f}` does not exist - cannot upload!" + clean_path = str(sanitize_filename(tmpdir, f)) + click.secho(f" -> `{clean_path}` ({size_in_mb(f):.2f} MB)") + mlflow.log_artifact(clean_path) + + click.secho( + f"Uploaded {total_size_mb:.2f} MB to server.", bold=True, fg="green" + ) + click.secho( + f"Visit {gitlab.url}/{project.path_with_namespace}/-/ml/experiments/{exp_meta.experiment_id}", + bold=True, + fg="blue", + ) diff --git a/tests/conftest.py b/src/mednet/libs/common/tests/conftest.py similarity index 100% rename from tests/conftest.py rename to src/mednet/libs/common/tests/conftest.py diff --git a/tests/data/16bits.png b/src/mednet/libs/common/tests/data/16bits.png similarity index 100% rename from tests/data/16bits.png rename to src/mednet/libs/common/tests/data/16bits.png diff --git a/src/mednet/libs/common/tests/data/iris-test.csv b/src/mednet/libs/common/tests/data/iris-test.csv new file mode 100644 index 00000000..27d1b05a --- /dev/null +++ b/src/mednet/libs/common/tests/data/iris-test.csv @@ -0,0 +1,75 @@ +5,3,1.6,0.2,Iris-setosa +5,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5,3.3,1.4,0.2,Iris-setosa +6.6,3,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3,5,1.7,Iris-versicolor +6,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6,2.7,5.1,1.6,Iris-versicolor +5.4,3,4.5,1.5,Iris-versicolor +6,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3,4.1,1.3,Iris-versicolor +5.5,2.5,4,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3,4.6,1.4,Iris-versicolor +5.8,2.6,4,1.2,Iris-versicolor +5,2.3,3.3,1,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +7.2,3.2,6,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6,3,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3,5.2,2.3,Iris-virginica +6.3,2.5,5,1.9,Iris-virginica +6.5,3,5.2,2,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3,5.1,1.8,Iris-virginica diff --git a/src/mednet/libs/common/tests/data/iris-train.csv b/src/mednet/libs/common/tests/data/iris-train.csv new file mode 100644 index 00000000..82d5b134 --- /dev/null +++ b/src/mednet/libs/common/tests/data/iris-train.csv @@ -0,0 +1,75 @@ +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3,1.4,0.1,Iris-setosa +4.3,3,1.1,0.1,Iris-setosa +5.8,4,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +7,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5,2,3.5,1,Iris-versicolor +5.9,3,4.2,1.5,Iris-versicolor +6,2.2,4,1,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.3,3.3,6,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3,5.8,2.2,Iris-virginica +7.6,3,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3,5.5,2.1,Iris-virginica +5.7,2.5,5,2,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6,2.2,5,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2,Iris-virginica +7.7,2.8,6.7,2,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica diff --git a/tests/data/iris.json b/src/mednet/libs/common/tests/data/iris.json similarity index 100% rename from tests/data/iris.json rename to src/mednet/libs/common/tests/data/iris.json diff --git a/tests/data/raw_with_black_border.png b/src/mednet/libs/common/tests/data/raw_with_black_border.png similarity index 100% rename from tests/data/raw_with_black_border.png rename to src/mednet/libs/common/tests/data/raw_with_black_border.png diff --git a/tests/data/raw_with_elastic_deformation.png b/src/mednet/libs/common/tests/data/raw_with_elastic_deformation.png similarity index 100% rename from tests/data/raw_with_elastic_deformation.png rename to src/mednet/libs/common/tests/data/raw_with_elastic_deformation.png diff --git a/tests/data/raw_without_black_border.png b/src/mednet/libs/common/tests/data/raw_without_black_border.png similarity index 100% rename from tests/data/raw_without_black_border.png rename to src/mednet/libs/common/tests/data/raw_without_black_border.png diff --git a/tests/data/raw_without_elastic_deformation.png b/src/mednet/libs/common/tests/data/raw_without_elastic_deformation.png similarity index 100% rename from tests/data/raw_without_elastic_deformation.png rename to src/mednet/libs/common/tests/data/raw_without_elastic_deformation.png diff --git a/tests/test_database_split.py b/src/mednet/libs/common/tests/test_database_split.py similarity index 100% rename from tests/test_database_split.py rename to src/mednet/libs/common/tests/test_database_split.py diff --git a/tests/test_image_utils.py b/src/mednet/libs/common/tests/test_image_utils.py similarity index 100% rename from tests/test_image_utils.py rename to src/mednet/libs/common/tests/test_image_utils.py diff --git a/tests/test_resource_monitor.py b/src/mednet/libs/common/tests/test_resource_monitor.py similarity index 100% rename from tests/test_resource_monitor.py rename to src/mednet/libs/common/tests/test_resource_monitor.py diff --git a/tests/test_transforms.py b/src/mednet/libs/common/tests/test_transforms.py similarity index 100% rename from tests/test_transforms.py rename to src/mednet/libs/common/tests/test_transforms.py diff --git a/src/mednet/libs/common/utils/gitlab.py b/src/mednet/libs/common/utils/gitlab.py new file mode 100644 index 00000000..d0b111dd --- /dev/null +++ b/src/mednet/libs/common/utils/gitlab.py @@ -0,0 +1,92 @@ +# SPDX-FileCopyrightText: Copyright © 2023 Idiap Research Institute <contact@idiap.ch> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +import configparser +import logging +import pathlib +import shutil + +import gitlab + +logger = logging.getLogger(__name__) + + +def gitlab_instance_and_token() -> tuple[gitlab.Gitlab, str]: + """Return an instance of the Gitlab object for remote operations, and the + user token. + + Returns + ------- + Gitlab main object and user token + """ + + cfg = pathlib.Path("~/.python-gitlab.cfg").expanduser() + if cfg.exists(): + gl = gitlab.Gitlab.from_config("idiap", [str(cfg)]) + config = configparser.ConfigParser() + config.read(cfg) + token = config["idiap"]["private_token"] + + else: # ask the user for a token or use one from the current runner + server = "https://gitlab.idiap.ch" + token = input(f"{server} (user or project) token: ") + gl = gitlab.Gitlab(server, private_token=token, api_version="4") + + # tests authentication with given credential. + gl.auth() + + return gl, token + + +def sanitize_filename(tmpdir: pathlib.Path, path: pathlib.Path) -> pathlib.Path: + """Sanitize the name of a file to be logged. + + This function sanitizes the basename of a file to be logged on the GitLab + MLflow server. It removes unsupported characters (such as ``=``) by + creating a copy of the file to be uploaded, with a modified name, on the + provided temporary directory. It then returns the name of such a temporary + file. + + If the input file path does not need sanitization, it is returned as is. + + Parameters + ---------- + tmpdir + The temporary directory where a copy of the input path, with a + sanitized name will be created. + path + The file that needs its name sanitized. + + Returns + ------- + Path to the temporary folder, and the sanitized copy of the input file + in said temporary folder, or the input ``path``, in case its name does not + need sanitization. + """ + + sanitized_filename = path.parts[-1].replace("=", "-") + if path.parts[-1] == sanitized_filename: + return path + + absolute_sanitized_filename = tmpdir / sanitized_filename + logger.info( + f"Sanitazing filename `{path}` -> `{absolute_sanitized_filename}`" + ) + shutil.copy2(path, absolute_sanitized_filename) + return absolute_sanitized_filename + + +def size_in_mb(path: pathlib.Path) -> float: + """Return the size in megabytes of a file. + + Parameters + ---------- + path + Input path to calculate file size from. + + Returns + ------- + A floating point number for the size of the object in MB. + """ + return path.stat().st_size / (1024**2) diff --git a/src/mednet/tests/test_cli.py b/src/mednet/tests/test_cli.py new file mode 100644 index 00000000..e3a7d9a0 --- /dev/null +++ b/src/mednet/tests/test_cli.py @@ -0,0 +1,65 @@ +# SPDX-FileCopyrightText: Copyright © 2023 Idiap Research Institute <contact@idiap.ch> +# +# SPDX-License-Identifier: GPL-3.0-or-later +"""Tests for our CLI applications.""" + +import contextlib + +from click.testing import CliRunner + + +@contextlib.contextmanager +def stdout_logging(): + # copy logging messages to std out + + import io + import logging + + buf = io.StringIO() + ch = logging.StreamHandler(buf) + ch.setFormatter(logging.Formatter("%(message)s")) + ch.setLevel(logging.INFO) + logger = logging.getLogger("mednet") + logger.addHandler(ch) + yield buf + logger.removeHandler(ch) + + +def _assert_exit_0(result): + assert ( + result.exit_code == 0 + ), f"Exit code {result.exit_code} != 0 -- Output:\n{result.output}" + + +def _check_help(entry_point): + runner = CliRunner() + result = runner.invoke(entry_point, ["--help"]) + _assert_exit_0(result) + assert result.output.startswith("Usage:") + + +def test_info_help(): + from mednet.scripts.info import info + + _check_help(info) + + +def test_info(): + from mednet.scripts.info import info + + runner = CliRunner() + result = runner.invoke(info) + _assert_exit_0(result) + assert "platform:" in result.output + assert "accelerators:" in result.output + assert "version:" in result.output + assert "configured classification databases:" in result.output + assert "configured segmentation databases:" in result.output + assert "dependencies:" in result.output + assert "python:" in result.output + + +def test_upload_help(): + from mednet.libs.common.scripts.upload import upload + + _check_help(upload) -- GitLab