flwr-nightly 1.22.0.dev20250916__py3-none-any.whl → 1.22.0.dev20250918__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. flwr/cli/app.py +2 -0
  2. flwr/cli/new/new.py +4 -2
  3. flwr/cli/new/templates/app/README.flowertune.md.tpl +1 -1
  4. flwr/cli/new/templates/app/code/client.baseline.py.tpl +64 -47
  5. flwr/cli/new/templates/app/code/client.xgboost.py.tpl +110 -0
  6. flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +56 -90
  7. flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +1 -23
  8. flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +37 -58
  9. flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +39 -44
  10. flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -14
  11. flwr/cli/new/templates/app/code/server.baseline.py.tpl +27 -29
  12. flwr/cli/new/templates/app/code/server.xgboost.py.tpl +56 -0
  13. flwr/cli/new/templates/app/code/task.xgboost.py.tpl +67 -0
  14. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +3 -3
  15. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  16. flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +61 -0
  17. flwr/cli/pull.py +100 -0
  18. flwr/cli/utils.py +17 -0
  19. flwr/common/constant.py +2 -0
  20. flwr/common/exit/exit_code.py +4 -0
  21. flwr/proto/control_pb2.py +7 -3
  22. flwr/proto/control_pb2.pyi +24 -0
  23. flwr/proto/control_pb2_grpc.py +34 -0
  24. flwr/proto/control_pb2_grpc.pyi +13 -0
  25. flwr/server/app.py +13 -0
  26. flwr/serverapp/strategy/__init__.py +4 -0
  27. flwr/serverapp/strategy/fedprox.py +174 -0
  28. flwr/serverapp/strategy/fedxgb_cyclic.py +220 -0
  29. flwr/simulation/app.py +1 -1
  30. flwr/simulation/run_simulation.py +25 -30
  31. flwr/supercore/cli/flower_superexec.py +26 -1
  32. flwr/supercore/constant.py +19 -0
  33. flwr/supercore/superexec/plugin/exec_plugin.py +11 -1
  34. flwr/supercore/superexec/run_superexec.py +16 -2
  35. flwr/superlink/artifact_provider/__init__.py +22 -0
  36. flwr/superlink/artifact_provider/artifact_provider.py +37 -0
  37. flwr/superlink/servicer/control/control_grpc.py +3 -0
  38. flwr/superlink/servicer/control/control_servicer.py +59 -2
  39. {flwr_nightly-1.22.0.dev20250916.dist-info → flwr_nightly-1.22.0.dev20250918.dist-info}/METADATA +1 -1
  40. {flwr_nightly-1.22.0.dev20250916.dist-info → flwr_nightly-1.22.0.dev20250918.dist-info}/RECORD +42 -33
  41. flwr/serverapp/strategy/strategy_utils_tests.py +0 -323
  42. {flwr_nightly-1.22.0.dev20250916.dist-info → flwr_nightly-1.22.0.dev20250918.dist-info}/WHEEL +0 -0
  43. {flwr_nightly-1.22.0.dev20250916.dist-info → flwr_nightly-1.22.0.dev20250918.dist-info}/entry_points.txt +0 -0
@@ -4,7 +4,7 @@ flwr/app/error.py,sha256=0PwA-E_CAs5P_nWAA0kksVO1A44t4CNLEf7u-Su-uJ0,2342
4
4
  flwr/app/exception.py,sha256=WX45Yviu_CmYrYd8JHNjRkSsb-g4Br7XvVLKuVxwSdI,1298
5
5
  flwr/app/metadata.py,sha256=rdMBn0zhIOYmCvmGENQWSQqDwcxwsMJzCle4PQdlc_Y,7331
6
6
  flwr/cli/__init__.py,sha256=EfMGmHoobET6P2blBt_eOByXL8299MgFfB7XNdaPQ6I,720
7
- flwr/cli/app.py,sha256=AKCP45Dkbpvdil_4Ir9S93L3HP3iUOnHmcZjscoM8uU,1856
7
+ flwr/cli/app.py,sha256=qYMZtPXzDXZpigmerRz4WF3lA3D0Y1lVufzgWB8Nd9A,1899
8
8
  flwr/cli/auth_plugin/__init__.py,sha256=FyaoqPzcxlBTFfJ2sBRC5USwQLmAhFr5KuBwfMO4bmo,1052
9
9
  flwr/cli/auth_plugin/oidc_cli_plugin.py,sha256=kQteGRB9-DmC7K5F9TBmUc8ndSBR7WyT27ygWUUuX_g,5402
10
10
  flwr/cli/build.py,sha256=hE54Q_eMdWLpVKSVC2aQaUxVaiUlWnAosGNvIPSEg6Y,7284
@@ -18,19 +18,19 @@ flwr/cli/login/__init__.py,sha256=B1SXKU3HCQhWfFDMJhlC7FOl8UsvH4mxysxeBnrfyUE,80
18
18
  flwr/cli/login/login.py,sha256=RM1Jiv_VFm3oz4rTHSr3D87X90lW3WzErjBBU7WviWY,4309
19
19
  flwr/cli/ls.py,sha256=3YK7cpoImJ7PbjlP_JgYRQWz1GymX2q7Reu-mKJEpao,10957
20
20
  flwr/cli/new/__init__.py,sha256=QA1E2QtzPvFCjLTUHnFnJbufuFiGyT_0Y53Wpbvg1F0,790
21
- flwr/cli/new/new.py,sha256=KyTs9Fbm4eoJ5DohhuTkYNJJX5rDC0p-YTPtNatYXrI,10529
21
+ flwr/cli/new/new.py,sha256=nIuUrQSGDjI4kqnymlq-rOT0RU3AHwZrat3abqHhCwM,10598
22
22
  flwr/cli/new/templates/__init__.py,sha256=FpjWCfIySU2DB4kh0HOXLAjlZNNFDTVU4w3HoE2TzcI,725
23
23
  flwr/cli/new/templates/app/.gitignore.tpl,sha256=HZJcGQoxp7aUzaPg8Uqch3kNrIESwr9yjimDxJYgXVY,3104
24
24
  flwr/cli/new/templates/app/LICENSE.tpl,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
25
25
  flwr/cli/new/templates/app/README.baseline.md.tpl,sha256=oClo5eR0iLuPzBT7uS3ikhNRAnySz_lhkHFElixKyJM,9640
26
- flwr/cli/new/templates/app/README.flowertune.md.tpl,sha256=sZFKxfvWvCopsTA_z0w5mvwepP0ksVslr5R-43SRBAI,3492
26
+ flwr/cli/new/templates/app/README.flowertune.md.tpl,sha256=2-W0HAseLWOe1JJU0TsNocp63D14N7jLwWhtYjxlfxs,3494
27
27
  flwr/cli/new/templates/app/README.md.tpl,sha256=uI8vUMCEGA1-WJ8-9EUFCnNtofWFkJNOxaR1V6r_Su4,1908
28
28
  flwr/cli/new/templates/app/__init__.py,sha256=LbR0ksGiF566JcHM_H5m1Tc4-oYUEilWFlcXR-Oe6bI,729
29
29
  flwr/cli/new/templates/app/code/__init__.baseline.py.tpl,sha256=YkHAgppUeD2BnBoGfVB6dEvBfjuIPGsU1gw4CiUi3qA,40
30
30
  flwr/cli/new/templates/app/code/__init__.py,sha256=zXa2YU1swzHxOKDQbwlDMEwVPOUswVeosjkiXNMTgFo,736
31
31
  flwr/cli/new/templates/app/code/__init__.py.tpl,sha256=J0Gn74E7khpLyKJVNqOPu7ev93vkcu1PZugsbxtABMw,52
32
32
  flwr/cli/new/templates/app/code/__init__.pytorch_legacy_api.py.tpl,sha256=mKIS8MK_X8T9NlmcX1-_c9Bbexc-ueqDIBI7uN6c4dE,45
33
- flwr/cli/new/templates/app/code/client.baseline.py.tpl,sha256=IYlCZqnaxT2ucP1ReffRNohOkYwNrhtrnDoQBBcrThY,1901
33
+ flwr/cli/new/templates/app/code/client.baseline.py.tpl,sha256=w8xYWhVAb5AFDLj206Nxz5U-xbzDBv0px2FFvE5wRTM,2438
34
34
  flwr/cli/new/templates/app/code/client.huggingface.py.tpl,sha256=SIZZ3s-6u8IU8cFfsqu6ZU8zjhfI1m1SWauOSUcW8TA,3015
35
35
  flwr/cli/new/templates/app/code/client.jax.py.tpl,sha256=uFCIPwAHYiRAgh2W3nRni_Oig02ZzRF-ofUG5O19zcE,2125
36
36
  flwr/cli/new/templates/app/code/client.mlx.py.tpl,sha256=CHU2IBIzI2YENZZuvTsAlSdL94DK19wMYMIhr-JgwZ8,3422
@@ -39,15 +39,16 @@ flwr/cli/new/templates/app/code/client.pytorch.py.tpl,sha256=fYoh-dTu07LkqNYvwcx
39
39
  flwr/cli/new/templates/app/code/client.pytorch_legacy_api.py.tpl,sha256=fuxVmZpjHIueNy_aHWF81531vmi8DGu4CYjYDqmUwWo,1705
40
40
  flwr/cli/new/templates/app/code/client.sklearn.py.tpl,sha256=0qqEe-RRjkHGOH8gsD9e83ae-kyyYixhyBgzVHjYpzk,3500
41
41
  flwr/cli/new/templates/app/code/client.tensorflow.py.tpl,sha256=8o55KXpsbF_rv6o98ZNYJDCazjwMp_RPTaSzDfT7Qlw,2682
42
+ flwr/cli/new/templates/app/code/client.xgboost.py.tpl,sha256=-ipRV8gqpbEg7Mht77Yyqs1viL-3JYSVZR47I7xeG4c,3493
42
43
  flwr/cli/new/templates/app/code/dataset.baseline.py.tpl,sha256=jbd_exHAk2-Blu_kVutjPO6a_dkJQWb232zxSeXIZ1k,1453
43
44
  flwr/cli/new/templates/app/code/flwr_tune/__init__.py,sha256=Xq5fEn5yZkw6HAJi10T_3HRBoqN5_5pNqJHY4wXvD5k,748
44
- flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl,sha256=vJ-cbxwaNmDr9eDAVINy_qUJzA2FirSXKsrkUnlFWYU,3759
45
+ flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl,sha256=p6BzTbP-mXkFANiVC7iz3YlskOidWaLC341IJyrUotQ,2951
45
46
  flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl,sha256=1NA2Sf-EviNtOaYN4dnFk6v2tcZVsY3-eXY84wOXVng,3059
46
- flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl,sha256=ONJw_BgBWEofVNGRDu8KAIThb8saRQlUEK4uS2u_6To,2449
47
- flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl,sha256=xkmmBKr0oGmewP56SP3s_6FG6JOVlGlquhg3a9nYMis,3270
48
- flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl,sha256=BhiqRg9w1MGuU5h2_vrLhRc0oHItYzE69qX_JI411k8,2754
49
- flwr/cli/new/templates/app/code/model.baseline.py.tpl,sha256=zJklLwH4vPx7rruzhzbAGdInxjjJw-djHCuCx5wshVA,2575
50
- flwr/cli/new/templates/app/code/server.baseline.py.tpl,sha256=rBB-DKEuA2SG1DGLW8uSHUg-GydEgb-7NHEclsC2X2g,1539
47
+ flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl,sha256=UCLEKUpXarkz9tMFtDrxmLv6QuKe5zCimTuoopQedUM,1717
48
+ flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl,sha256=qe9Om3P2ERvvSj2NN5RSEKgNgztWatCpWtC8SkS_T_M,2420
49
+ flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl,sha256=M6CzBY-gtIqLOu2xTtABXOVgBnqKOu7d6Vn2sazmYuI,2444
50
+ flwr/cli/new/templates/app/code/model.baseline.py.tpl,sha256=P6jTuN9reJfdthiN3mOUHiA4xrtDh5TTUcAV6210-hU,2104
51
+ flwr/cli/new/templates/app/code/server.baseline.py.tpl,sha256=hliBSfHSzg4bi6PxMlj4oGFfvzvi-4DzoaI67VZbJeQ,1111
51
52
  flwr/cli/new/templates/app/code/server.huggingface.py.tpl,sha256=_2Mv-SqGSMf7sMdbMEmvROzedvNaVHvhIIO3eYAhVYU,1252
52
53
  flwr/cli/new/templates/app/code/server.jax.py.tpl,sha256=RW-rh7ogcJ3_BD66bJxTw-ZoP7c-4SK8hVHc-e0SSVY,1029
53
54
  flwr/cli/new/templates/app/code/server.mlx.py.tpl,sha256=J8rIe6RL2ndODVJD79xShRKBH70HljFSCi4s_RJ-xLQ,1200
@@ -56,6 +57,7 @@ flwr/cli/new/templates/app/code/server.pytorch.py.tpl,sha256=epARqfcQ-EQsdZwaaaU
56
57
  flwr/cli/new/templates/app/code/server.pytorch_legacy_api.py.tpl,sha256=gvBsGA_Jg9kAH8xTxjzTjMcvBtciuccOwQFbO7ey8tU,916
57
58
  flwr/cli/new/templates/app/code/server.sklearn.py.tpl,sha256=ehQ5VRgBn92WeFl6kupwJnuxSNkKvE-EvKde6A9mNQo,1377
58
59
  flwr/cli/new/templates/app/code/server.tensorflow.py.tpl,sha256=2-WTOPd-ewdLd9QmSlflIH7ix7zxAzPEOZoyiPBOy8c,1010
60
+ flwr/cli/new/templates/app/code/server.xgboost.py.tpl,sha256=fwtCRyCG2hDSH1zVMyZv7zA7wsdKNPfpugDSZjxCs5Q,1746
59
61
  flwr/cli/new/templates/app/code/strategy.baseline.py.tpl,sha256=YkHAgppUeD2BnBoGfVB6dEvBfjuIPGsU1gw4CiUi3qA,40
60
62
  flwr/cli/new/templates/app/code/task.huggingface.py.tpl,sha256=piBbY3Dg60bQnCg15uzMw0QiL5SDOYX4YhQouy-X2zI,3164
61
63
  flwr/cli/new/templates/app/code/task.jax.py.tpl,sha256=Fb0XgdTAQplM-ZCusI081XA9asO3gHptH772S-Xcyy8,1525
@@ -65,9 +67,10 @@ flwr/cli/new/templates/app/code/task.pytorch.py.tpl,sha256=RKA5lV6O6OnVKZ2r75pbz
65
67
  flwr/cli/new/templates/app/code/task.pytorch_legacy_api.py.tpl,sha256=XlJqA4Ix_PloO_zJLhjiN5vDj16w3I4CPVGdmbe8asE,3800
66
68
  flwr/cli/new/templates/app/code/task.sklearn.py.tpl,sha256=vHdhtMp0FHxbYafXyhDT9aKmmmA0Jvpx5Oum1Yu9lWY,1850
67
69
  flwr/cli/new/templates/app/code/task.tensorflow.py.tpl,sha256=impgWN7MfztmcWF4xh1llcZGsgTvrb1HD5ZE0t-8U08,1731
70
+ flwr/cli/new/templates/app/code/task.xgboost.py.tpl,sha256=0xO8jQvrHuB1llVDopQPOmt5Hn6rBw8umzoNwiZZs-o,2135
68
71
  flwr/cli/new/templates/app/code/utils.baseline.py.tpl,sha256=YkHAgppUeD2BnBoGfVB6dEvBfjuIPGsU1gw4CiUi3qA,40
69
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl,sha256=eoRhBN5n00LQu2y4o29JUw3T03CasO5S1HMxHrnyWWQ,3180
70
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl,sha256=oVq52gXoPT69jHji75FSOYZ978xwIG-AVCha-LyuG7k,2497
72
+ flwr/cli/new/templates/app/pyproject.baseline.toml.tpl,sha256=mPIMPfneVYV03l8jWRgWZ0V5Kh_pJw-AMUvkhcKkmL8,3182
73
+ flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl,sha256=wqYW4bWcf12m0U2njR995lySSesFvnHB-eSkPWz-QdM,2501
71
74
  flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl,sha256=xHGF38i7oFpvnFvqfqLdtc08CkHRYsenbLz3q1dhCXk,2020
72
75
  flwr/cli/new/templates/app/pyproject.jax.toml.tpl,sha256=fdDhwmPoMirJ095cU_vFCBf0ILQlAoa1fdnHb2LM1yk,1471
73
76
  flwr/cli/new/templates/app/pyproject.mlx.toml.tpl,sha256=PAjPT2v06sBZxacNiyMJloDwocCK5tFcGQmMXOoBqc8,1542
@@ -76,10 +79,12 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=SE4H23OFkQbqNU64nYf
76
79
  flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl,sha256=docQbs3MuRR-yT24lVz7N2sQL3Sj49EHuOCuRj_0djQ,1508
77
80
  flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=apauU_PUmLEbt2rjckKniEbzdRs1EnMri_qgtHtBJZ8,1484
78
81
  flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=LQpDKJTEnRKj5Ygn5FkT44SxlnLVprkPlbrGaFf5Q50,1508
82
+ flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl,sha256=504pHibNRGFe-DLnzqHLYhKeF_n8BPMv0Xog5EfnZ0M,1661
83
+ flwr/cli/pull.py,sha256=dHiMe6x8w8yRoFNKpjA-eiPD6eFiHz4Vah5HZrqNpuo,3364
79
84
  flwr/cli/run/__init__.py,sha256=RPyB7KbYTFl6YRiilCch6oezxrLQrl1kijV7BMGkLbA,790
80
85
  flwr/cli/run/run.py,sha256=ECa0kup9dn15O70H74QdgUsEaeErbzDqVX_U0zZO5IM,8173
81
86
  flwr/cli/stop.py,sha256=TR9F61suTxNUzGIktUdoBhXwdRtCdvzGhy3qCuvcfBg,5000
82
- flwr/cli/utils.py,sha256=tTI8PyJdA8BU1PoTS8ZItdCM5EVTeze_Z1zumffYY6A,12963
87
+ flwr/cli/utils.py,sha256=sMctnDYHv-zu9FG67aV0vy_zs3gkkXclQicBD_67WWg,13805
83
88
  flwr/client/__init__.py,sha256=boIhKaK6I977zrILmoTutNx94x5jB0e6F1gnAjaRJnI,1250
84
89
  flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
85
90
  flwr/client/client_app.py,sha256=zVhi-l3chAb06ozFsKwix3hU_RpOLjST13Ha50AVIPE,16918
@@ -116,7 +121,7 @@ flwr/common/args.py,sha256=Nq2u4yePbkSY0CWFamn0hZY6Rms8G1xYDeDGIcLIITE,5849
116
121
  flwr/common/auth_plugin/__init__.py,sha256=DktrRcGZrRarLf7Jb_UlHtOyLp9_-kEplyq6PS5-vOA,988
117
122
  flwr/common/auth_plugin/auth_plugin.py,sha256=mM7SuphO4OsVAVJR1GErYVgYT83ZjxDzS_gha12bT9E,4855
118
123
  flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
119
- flwr/common/constant.py,sha256=FXG5HqwQG-mQXgfptHn4jTaXD4Y_kyDA1ntTKcp0qfs,8850
124
+ flwr/common/constant.py,sha256=zopMTlEgz8TxMSh59ueef6VutHSdfb3XRStl1W5yBZ4,9013
120
125
  flwr/common/context.py,sha256=Be8obQR_OvEDy1OmshuUKxGRQ7Qx89mf5F4xlhkR10s,2407
121
126
  flwr/common/date.py,sha256=1ZT2cRSpC2DJqprOVTLXYCR_O2_OZR0zXO_brJ3LqWc,1554
122
127
  flwr/common/differential_privacy.py,sha256=FdlpdpPl_H_2HJa8CQM1iCUGBBQ5Dc8CzxmHERM-EoE,6148
@@ -126,7 +131,7 @@ flwr/common/event_log_plugin/__init__.py,sha256=ts3VAL3Fk6Grp1EK_1Qg_V-BfOof9F86
126
131
  flwr/common/event_log_plugin/event_log_plugin.py,sha256=4SkVa1Ic-sPlICJShBuggXmXDcQtWQ1KDby4kthFNF0,2064
127
132
  flwr/common/exit/__init__.py,sha256=8W7xaO1iw0vacgmQW7FTFbSh7csNv6XfsgIlnIbNF6U,978
128
133
  flwr/common/exit/exit.py,sha256=DcXJfbpW1g-pQJqSZmps-1MZydd7T7RaarghIf2e4tU,3636
129
- flwr/common/exit/exit_code.py,sha256=e8O71zIqVT1H84mNBeenTz7S39yPZSpZQm-xUenpzN4,5249
134
+ flwr/common/exit/exit_code.py,sha256=Xa1NFGny2cefZ62kZZOfT8eii__PolMWCHxYmxoSQ2s,5416
130
135
  flwr/common/exit/exit_handler.py,sha256=uzDdWwhKgc1w5csZS52b86kjmEApmDZKwMn_X0zDZZo,2126
131
136
  flwr/common/exit/signal_handler.py,sha256=wqxykrwgmpFzmEMhpnlM7RtO0PnqIvYiSB1qYahZ5Sk,3710
132
137
  flwr/common/grpc.py,sha256=nHnFC7E84pZVTvd6BhcSYWnGd0jf8t5UmGea04qvilM,9806
@@ -181,10 +186,10 @@ flwr/proto/clientappio_pb2.py,sha256=vJjzwWydhg7LruK8cvRAeVQeHPsJztgdIW9nyiPBZF0
181
186
  flwr/proto/clientappio_pb2.pyi,sha256=XbFvpZvvrS7QcH5AFXfpRGl4hQvhd3QdKO6x0oTlCCU,165
182
187
  flwr/proto/clientappio_pb2_grpc.py,sha256=iobNROP0qvn5zddx7k-uIi_dJWP3T_BRp_kbKq086i8,17550
183
188
  flwr/proto/clientappio_pb2_grpc.pyi,sha256=Ytf1O1ktKB0Vsuc3AWLIErGjIJYokzKYzi2uA7mdMeg,4785
184
- flwr/proto/control_pb2.py,sha256=Jd_KT0Vi2GRf1rHDERxAsNmQxjLsNEmpqNLYdZ1kFCk,5684
185
- flwr/proto/control_pb2.pyi,sha256=oEQH84BwhgaiD5zIseGH_UujuMk2SVCe5R75msEga-8,9478
186
- flwr/proto/control_pb2_grpc.py,sha256=AweEk-n77uEwV1DX1lc55mhNlSfDEqsDHHWeouyTOVc,10610
187
- flwr/proto/control_pb2_grpc.pyi,sha256=8bROIwDXNlPzbpaBcxTwIzKXGTP18dvU8xBVKrfe80s,3001
189
+ flwr/proto/control_pb2.py,sha256=Sz7PTdb7YGBs2N-FX6GiOVueY9PN0cF85XbwBkK9_BE,6183
190
+ flwr/proto/control_pb2.pyi,sha256=2OLPt6ztVcLzzISqfRqW4yrA-nawIPLwVDoTjBnSS5U,10592
191
+ flwr/proto/control_pb2_grpc.py,sha256=R4ykPqGblqEpOdVskoSfMeS-pZdyMT3CMBQUtTzHbgQ,12282
192
+ flwr/proto/control_pb2_grpc.pyi,sha256=7U9aOP4dYamnc4ZtTrEQEYYz0kFNI_fT88LRxwClA0U,3504
188
193
  flwr/proto/error_pb2.py,sha256=PQVWrfjVPo88ql_KgV9nCxyQNCcV9PVfmcw7sOzTMro,1084
189
194
  flwr/proto/error_pb2.pyi,sha256=ZNH4HhJTU_KfMXlyCeg8FwU-fcUYxTqEmoJPtWtHikc,734
190
195
  flwr/proto/error_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
@@ -239,7 +244,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
239
244
  flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
240
245
  flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
241
246
  flwr/server/__init__.py,sha256=LQQHiuL2jy7TpNaKastRdGsexlxSt5ZWAQNVqitDnrY,1598
242
- flwr/server/app.py,sha256=BYFMIpzD7ZbxW9xMhW3mJ2Ojw0E71vITS3QKf6Bse3I,29286
247
+ flwr/server/app.py,sha256=SUWdNUcl-Sy8h2MiC8Etr50GDJuGq58Ekqtr5XQ-Xrg,29951
243
248
  flwr/server/client_manager.py,sha256=5jCGavVli7XdupvWWo7ru3PdFTlRU8IGvHFSSoUVLRs,6227
244
249
  flwr/server/client_proxy.py,sha256=sv0E9AldBYOvc3pusqFh-GnyreeMfsXQ1cuTtxTq_wY,2399
245
250
  flwr/server/compat/__init__.py,sha256=0IsttWvY15qO98_1GyzVC-vR1e_ZPXOdu2qUlOkYMPE,886
@@ -332,7 +337,7 @@ flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=DkayCsnlAy
332
337
  flwr/serverapp/__init__.py,sha256=ZujKNXULwhWYQhFnxOOT5Wi9MRq2JCWFhAAj7ouiQ78,884
333
338
  flwr/serverapp/dp_fixed_clipping.py,sha256=wbP4W7CaUHXdll8ZSVUnTBSEWrnWM00CGk63rOR-Q2s,12133
334
339
  flwr/serverapp/exception.py,sha256=5cuH-2AafvihzosWDdDjuMmHdDqZ1XxHvCqZXNBVklw,1334
335
- flwr/serverapp/strategy/__init__.py,sha256=MHrU_tz_myWqzG3h4gZdIpt2DDN-JdNK-HHIcrz1-Ns,1448
340
+ flwr/serverapp/strategy/__init__.py,sha256=mt2l31EAQ9oSvBcQhk4Jj4SvTePmWzBHQxZqL1v0uhE,1552
336
341
  flwr/serverapp/strategy/dp_fixed_clipping.py,sha256=wbP4W7CaUHXdll8ZSVUnTBSEWrnWM00CGk63rOR-Q2s,12133
337
342
  flwr/serverapp/strategy/fedadagrad.py,sha256=fD65P6OEERa_pxq847e1UZpA083AcWR44XavYB0naGM,6343
338
343
  flwr/serverapp/strategy/fedadam.py,sha256=s3xPIqhopy6yPTeFxevSPnc7a6BcKnKsvo2AaO6Z_xs,7138
@@ -340,26 +345,28 @@ flwr/serverapp/strategy/fedavg.py,sha256=Bq_nlmngzJbjqX1fF1mevXGVN6-pwglHv-6yNrs
340
345
  flwr/serverapp/strategy/fedavgm.py,sha256=VlByltWzUYCoiVIWPFRqsqLKNWjlOlO2INK8SUxEjzk,8327
341
346
  flwr/serverapp/strategy/fedmedian.py,sha256=b31Dk0LQBbQxi_f-jeSbWHI7iOBugcuBSN2Az-_a75E,2596
342
347
  flwr/serverapp/strategy/fedopt.py,sha256=kqT0uV2IUE93O72XEVa1JJo61dcwbZEoT9KmYTjR2tE,8477
348
+ flwr/serverapp/strategy/fedprox.py,sha256=XkkLTk3XpXAj0QoAzHqAvcAlPjrNlX11ISAu5u2x6X8,7026
343
349
  flwr/serverapp/strategy/fedtrimmedavg.py,sha256=4-QxgAQGo_7vB_L7qDYy28d95OBt9MeDa92yaTRMHqk,7166
344
350
  flwr/serverapp/strategy/fedxgb_bagging.py,sha256=ktDjzov4y0BRecioq788umCEtcuwElou9olBizQKOnM,3282
351
+ flwr/serverapp/strategy/fedxgb_cyclic.py,sha256=8H8WoLdG4Fy1_dtLLE4AYiidC-Cvaw2GxySfzAb7Xj0,8774
345
352
  flwr/serverapp/strategy/fedyogi.py,sha256=1Ripr4Hi2cdeTOLiFOXtMKvOxR3BsUQwc7bbTrXN4LM,6653
346
353
  flwr/serverapp/strategy/result.py,sha256=E0Hl2VLnZAgQJjE2GDoKsK7JX-kPPU2KXc47Axt6hGw,4295
347
354
  flwr/serverapp/strategy/strategy.py,sha256=8uJGGm1ROLZERQ_dkRS7Z_rs-yK6XCE0UxXtIdFiEWk,10789
348
355
  flwr/serverapp/strategy/strategy_utils.py,sha256=hiwS7k-Hx6_c4NZXoKpHucS5CBKb7f8GppXRBSMt3Us,10851
349
- flwr/serverapp/strategy/strategy_utils_tests.py,sha256=_adS23Lrv1QA6V_3oZ7P_csMd8RqDObFeIhOkFnNtTg,10690
350
356
  flwr/simulation/__init__.py,sha256=Gg6OsP1Z-ixc3-xxzvl7j7rz2Fijy9rzyEPpxgAQCeM,1556
351
- flwr/simulation/app.py,sha256=LbGLMvN9Ap119yBqsUcNNmVLRnCySnr4VechqcQ1hpA,10401
357
+ flwr/simulation/app.py,sha256=b_bDyZFwBf2zpKs37Vmd5cFJSzDRE0fL-8uqA0UkAv4,10393
352
358
  flwr/simulation/legacy_app.py,sha256=nMISQqW0otJL1-2Kfd94O6BLlGS2IEmEPKTM2WGKrIs,15861
353
359
  flwr/simulation/ray_transport/__init__.py,sha256=ogd-0AMv2U-wBZ1r3sHWaDIOIrVqr88Xi6C8o4Dviy0,734
354
360
  flwr/simulation/ray_transport/ray_actor.py,sha256=JN3xTqFIr5Z750k92CcA_uavzOHhSWDwE2WCaecvpks,19147
355
361
  flwr/simulation/ray_transport/ray_client_proxy.py,sha256=2kVUDrJe2ViOJEuB0v_Xb3XUwK9yKNwDwrYQXTJDdco,7506
356
362
  flwr/simulation/ray_transport/utils.py,sha256=KrexpWYCF-dAF3UHc9yDbPQWO-ahMT-BbD8nURLgiHk,2393
357
- flwr/simulation/run_simulation.py,sha256=-sp3dNZcp7MCAH0BlmZpVcFAGvozRdYXRdDYcH_2Zxk,20838
363
+ flwr/simulation/run_simulation.py,sha256=LrM5iI0Rf_QqrnqvJ1muKxKFlrInA3I8-SF-uIIsPik,20666
358
364
  flwr/simulation/simulationio_connection.py,sha256=mzS1C6EEREwQDPceDo30anAasmTDLb9qqV2tXlBhOUA,3494
359
365
  flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
360
366
  flwr/supercore/app_utils.py,sha256=K76Zt6R670b1hUmxOsNc1WUCVYvF7lejXPcCO9K0Q0g,1753
361
367
  flwr/supercore/cli/__init__.py,sha256=EDl2aO-fuQfxSbL-T1W9RAfA2N0hpWHmqX_GSwblJbQ,845
362
- flwr/supercore/cli/flower_superexec.py,sha256=kov4uEeihf7QEUAfHEgdEvsL_8nL_fzQI9EePnRM1Ww,5012
368
+ flwr/supercore/cli/flower_superexec.py,sha256=JtqYrEWVu3BxLkjavsdohTOwvMwzuFqWP5j4Mo9dqsk,6155
369
+ flwr/supercore/constant.py,sha256=F9kRjisedaZcoyGvUITSDmIG12QDSCpo2LlM_l-q6jM,820
363
370
  flwr/supercore/corestate/__init__.py,sha256=Vau6-L_JG5QzNqtCTa9xCKGGljc09wY8avZmIjSJemg,774
364
371
  flwr/supercore/corestate/corestate.py,sha256=rDAWWeG5DcpCyQso9Z3RhwL4zr2IroPlRMcDzqoSu8s,2328
365
372
  flwr/supercore/ffs/__init__.py,sha256=U3KXwG_SplEvchat27K0LYPoPHzh-cwwT_NHsGlYMt8,908
@@ -380,18 +387,20 @@ flwr/supercore/superexec/__init__.py,sha256=XKX208hZ6a9gZ4KT9kMqfpCtp_8VGxekzKFf
380
387
  flwr/supercore/superexec/plugin/__init__.py,sha256=GNwq8uNdE8RB7ywEFRAvKjLFzgS3YXgz39-HBGsemWw,1035
381
388
  flwr/supercore/superexec/plugin/base_exec_plugin.py,sha256=fL-Ufc9Dp56OhWOzNSJUc7HumbkuSDYqZKwde2opG4g,2074
382
389
  flwr/supercore/superexec/plugin/clientapp_exec_plugin.py,sha256=9FT6ufEqV5K9g4FaAB9lVDbIv-VCH5LcxT4YKy23roE,1035
383
- flwr/supercore/superexec/plugin/exec_plugin.py,sha256=w3jmtxdv7ov_EdAgifKcm4q8nV39e2Xna4sNjqClwOM,2447
390
+ flwr/supercore/superexec/plugin/exec_plugin.py,sha256=4WtCQ4bsuFRlfCbg91ZcPAsX8htrCCo_fFh1DKo3cCQ,2764
384
391
  flwr/supercore/superexec/plugin/serverapp_exec_plugin.py,sha256=IwRzdPV-cSKwrP2krGh0De4IkAuxsmgK0WU6J-2GXqM,1035
385
392
  flwr/supercore/superexec/plugin/simulation_exec_plugin.py,sha256=upn5zE-YKkl_jTw8RzmeyQ58PU_UAlQ7CqnBXXdng8I,1060
386
- flwr/supercore/superexec/run_superexec.py,sha256=8hUlaVPVNnhePQ9OUgen4yy0fSGZAVggBGzm-33iJPw,6630
393
+ flwr/supercore/superexec/run_superexec.py,sha256=JiwKq9s_WPpk0S9MSi1lIgMZU120NOZLf4GlObHzI_k,7217
387
394
  flwr/supercore/utils.py,sha256=ebuHMbeA8eXisX0oMPqBK3hk7uVnIE_yiqWVz8YbkpQ,1324
388
395
  flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
396
+ flwr/superlink/artifact_provider/__init__.py,sha256=pgZEcVPKRE874LSu3cgy0HbwSJBIpVy_HxQOmne4PAs,810
397
+ flwr/superlink/artifact_provider/artifact_provider.py,sha256=Gnlg2M2SOqCruji2B0U3ov68NJWKin9scmnWJTiSnNA,1267
389
398
  flwr/superlink/servicer/__init__.py,sha256=ZC-kILcUGeh6IxJsfu24cTzUqIGXmQfEKsGfhsnhBpM,717
390
399
  flwr/superlink/servicer/control/__init__.py,sha256=qhUTMt_Mg4lxslCJYn5hDSrA-lXf5ya3617BT8kR-2Y,803
391
400
  flwr/superlink/servicer/control/control_event_log_interceptor.py,sha256=HauUd7Xq-b1TFZmZVl9wpBITfDttn8-1_KhlEq-HJ8M,5966
392
- flwr/superlink/servicer/control/control_grpc.py,sha256=DUGArJvH3oZasutEU55NtYm0ZukPEO92UKhzOGu3qu8,4079
401
+ flwr/superlink/servicer/control/control_grpc.py,sha256=BYm2QELbUAV_mHr0K-ZU726jjgoFXTo4M0-C6MXFzTg,4244
393
402
  flwr/superlink/servicer/control/control_license_interceptor.py,sha256=T3AzmRt-PPwyTq3hrdpmZHQd5_CpPOk7TtnFZrB-JRY,3349
394
- flwr/superlink/servicer/control/control_servicer.py,sha256=RFttpc1O0pYBaru1SXE6v3hUoNfgR3_ijN02bSVhDsM,13914
403
+ flwr/superlink/servicer/control/control_servicer.py,sha256=zY1ARksabr776eLQDy48wDmEx9t-VXTOnHq1h5Mt61U,16143
395
404
  flwr/superlink/servicer/control/control_user_auth_interceptor.py,sha256=9Aqhrt_UX80FXbIQVXUrqDHs5rD5CA7vEn0Bh-zPiYU,6232
396
405
  flwr/supernode/__init__.py,sha256=KgeCaVvXWrU3rptNR1y0oBp4YtXbAcrnCcJAiOoWkI4,707
397
406
  flwr/supernode/cli/__init__.py,sha256=JuEMr0-s9zv-PEWKuLB9tj1ocNfroSyNJ-oyv7ati9A,887
@@ -407,7 +416,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
407
416
  flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
408
417
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=nIHRu38EWK-rpNOkcgBRAAKwYQQWFeCwu0lkO7OPZGQ,10239
409
418
  flwr/supernode/start_client_internal.py,sha256=Y9S1-QlO2WP6eo4JvWzIpfaCoh2aoE7bjEYyxNNnlyg,20777
410
- flwr_nightly-1.22.0.dev20250916.dist-info/METADATA,sha256=5fd7FMKBNE9N1UWd12_xAPWowIbjr948mx-erdTIBBM,14559
411
- flwr_nightly-1.22.0.dev20250916.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
412
- flwr_nightly-1.22.0.dev20250916.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
413
- flwr_nightly-1.22.0.dev20250916.dist-info/RECORD,,
419
+ flwr_nightly-1.22.0.dev20250918.dist-info/METADATA,sha256=XdvpDYzZ_dWvMX49Pwi2gOUo0qLtrt466UABjDeyavg,14559
420
+ flwr_nightly-1.22.0.dev20250918.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
421
+ flwr_nightly-1.22.0.dev20250918.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
422
+ flwr_nightly-1.22.0.dev20250918.dist-info/RECORD,,
@@ -1,323 +0,0 @@
1
- # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- # ==============================================================================
15
- """Tests for message-based strategy utilities."""
16
-
17
-
18
- from collections import OrderedDict
19
- from unittest.mock import Mock
20
-
21
- import numpy as np
22
- import pytest
23
- from parameterized import parameterized
24
-
25
- from flwr.common import (
26
- Array,
27
- ArrayRecord,
28
- ConfigRecord,
29
- Message,
30
- MetricRecord,
31
- RecordDict,
32
- )
33
- from flwr.serverapp.exception import InconsistentMessageReplies
34
-
35
- from .strategy_utils import (
36
- aggregate_arrayrecords,
37
- aggregate_metricrecords,
38
- config_to_str,
39
- validate_message_reply_consistency,
40
- )
41
-
42
-
43
- def create_mock_reply(arrays: ArrayRecord, num_examples: float) -> Message:
44
- """Create a mock reply Message with default keys."""
45
- message = Mock(spec=Message)
46
- message.content = RecordDict(
47
- {"arrays": arrays, "metrics": MetricRecord({"num-examples": num_examples})}
48
- )
49
- message.has_error.side_effect = lambda: False
50
- message.has_content.side_effect = lambda: True
51
- return message
52
-
53
-
54
- def test_config_to_str() -> None:
55
- """Test that items of types bytes are masked out."""
56
- config = ConfigRecord({"a": 123, "b": [1, 2, 3], "c": b"bytes"})
57
- expected_str = "{'a': 123, 'b': [1, 2, 3], 'c': <bytes>}"
58
- assert config_to_str(config) == expected_str
59
-
60
-
61
- def test_arrayrecords_aggregation() -> None:
62
- """Test aggregation of ArrayRecords."""
63
- num_replies = 3
64
- num_arrays = 4
65
- weights = [0.25, 0.4, 0.35]
66
- np_arrays = [
67
- [np.random.randn(7, 3) for _ in range(num_arrays)] for _ in range(num_replies)
68
- ]
69
-
70
- avg_list = [
71
- np.average([lst[i] for lst in np_arrays], axis=0, weights=weights)
72
- for i in range(num_arrays)
73
- ]
74
-
75
- # Construct RecordDicts (mimicing replies)
76
- records = [
77
- RecordDict(
78
- {
79
- "arrays": ArrayRecord(np_arrays[i]),
80
- "metrics": MetricRecord({"weight": weights[i]}),
81
- }
82
- )
83
- for i in range(num_replies)
84
- ]
85
- # Execute aggregate
86
- aggrd = aggregate_arrayrecords(records, weighting_metric_name="weight")
87
-
88
- # Assert consistency
89
- assert all(np.allclose(a, b) for a, b in zip(aggrd.to_numpy_ndarrays(), avg_list))
90
- assert aggrd.object_id == ArrayRecord(avg_list).object_id
91
-
92
-
93
- def test_arrayrecords_aggregation_with_ndim_zero() -> None:
94
- """Test aggregation of ArrayRecords with 0-dim arrays."""
95
- num_replies = 3
96
- weights = [0.25, 0.4, 0.35]
97
- np_arrays = [np.array(np.random.randn()) for _ in range(num_replies)]
98
-
99
- # For 0-dimensional arrays, we just compute the weighted average directly
100
- avg_list = [np.average(np_arrays, axis=0, weights=weights)]
101
-
102
- # Construct RecordDicts (mimicing replies)
103
- records = [
104
- RecordDict(
105
- {
106
- "arrays": ArrayRecord([np_arrays[i]]),
107
- "metrics": MetricRecord({"weight": weights[i]}),
108
- }
109
- )
110
- for i in range(num_replies)
111
- ]
112
- # Execute aggregate
113
- aggrd = aggregate_arrayrecords(records, weighting_metric_name="weight")
114
-
115
- # Assert consistency
116
- assert np.isclose(aggrd.to_numpy_ndarrays()[0], avg_list[0])
117
- assert aggrd.object_id == ArrayRecord([np.array(avg_list[0])]).object_id
118
-
119
-
120
- def test_metricrecords_aggregation() -> None:
121
- """Test aggregation of MetricRecords."""
122
- num_replies = 3
123
- weights = [0.25, 0.4, 0.35]
124
- metric_records = [
125
- MetricRecord({"a": 1, "b": 2.0, "c": np.random.randn(3).tolist()})
126
- for _ in range(num_replies)
127
- ]
128
-
129
- # Compute expected aggregated MetricRecord.
130
- # For ease, we convert everything into numpy arrays, then aggregate
131
- as_np_entries = [
132
- {
133
- k: np.array(v) if isinstance(v, (int, float, list)) else v
134
- for k, v in record.items()
135
- }
136
- for record in metric_records
137
- ]
138
- avg_list = [
139
- np.average(
140
- [list(entries.values())[i] for entries in as_np_entries],
141
- axis=0,
142
- weights=weights,
143
- ).tolist()
144
- for i in range(len(as_np_entries[0]))
145
- ]
146
- expected_record = MetricRecord(dict(zip(as_np_entries[0].keys(), avg_list)))
147
- expected_record["a"] = float(expected_record["a"]) # type: ignore
148
- expected_record["b"] = float(expected_record["b"]) # type: ignore
149
-
150
- # Construct RecordDicts (mimicing replies)
151
- # Inject weighting factor
152
- records = [
153
- RecordDict(
154
- {
155
- "metrics": MetricRecord(
156
- record.__dict__["_data"] | {"weight": weights[i]}
157
- ),
158
- }
159
- )
160
- for i, record in enumerate(metric_records)
161
- ]
162
-
163
- # Execute aggregate
164
- aggrd = aggregate_metricrecords(records, weighting_metric_name="weight")
165
- # Assert
166
- assert expected_record.object_id == aggrd.object_id
167
-
168
-
169
- @parameterized.expand( # type: ignore
170
- [
171
- (
172
- True,
173
- RecordDict(
174
- {
175
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
176
- "metrics": MetricRecord({"weight": 0.123}),
177
- }
178
- ),
179
- ), # Compliant
180
- (
181
- False,
182
- RecordDict(
183
- {
184
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
185
- "metrics": MetricRecord({"weight": [0.123]}),
186
- }
187
- ),
188
- ), # Weighting key is not a scalar (BAD)
189
- (
190
- False,
191
- RecordDict(
192
- {
193
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
194
- "metrics": MetricRecord({"loss": 0.01}),
195
- }
196
- ),
197
- ), # No weighting key in MetricRecord (BAD)
198
- (
199
- False,
200
- RecordDict({"global-model": ArrayRecord([np.random.randn(7, 3)])}),
201
- ), # No MetricsRecord (BAD)
202
- (
203
- False,
204
- RecordDict(
205
- {
206
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
207
- "another-model": ArrayRecord([np.random.randn(7, 3)]),
208
- }
209
- ),
210
- ), # Two ArrayRecords (BAD)
211
- (
212
- False,
213
- RecordDict(
214
- {
215
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
216
- "metrics": MetricRecord({"weight": 0.123}),
217
- "more-metrics": MetricRecord({"loss": 0.321}),
218
- }
219
- ),
220
- ), # Two MetricRecords (BAD)
221
- ]
222
- )
223
- def test_consistency_of_replies_with_matching_keys(
224
- is_valid: bool, recorddict: RecordDict
225
- ) -> None:
226
- """Test consistency in replies."""
227
- # Create dummy records
228
- records = [recorddict for _ in range(3)]
229
-
230
- if not is_valid:
231
- # Should raise InconsistentMessageReplies exception
232
- with pytest.raises(InconsistentMessageReplies):
233
- validate_message_reply_consistency(
234
- records, weighted_by_key="weight", check_arrayrecord=True
235
- )
236
- else:
237
- # Should not raise an exception
238
- validate_message_reply_consistency(
239
- records, weighted_by_key="weight", check_arrayrecord=True
240
- )
241
-
242
-
243
- @parameterized.expand( # type: ignore
244
- [
245
- (
246
- [
247
- RecordDict(
248
- {
249
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
250
- "metrics": MetricRecord({"weight": 0.123}),
251
- }
252
- ),
253
- RecordDict(
254
- {
255
- "model": ArrayRecord([np.random.randn(7, 3)]),
256
- "metrics": MetricRecord({"weight": 0.123}),
257
- }
258
- ),
259
- ],
260
- ), # top-level keys don't match for ArrayRecords
261
- (
262
- [
263
- RecordDict(
264
- {
265
- "global-model": ArrayRecord(
266
- OrderedDict({"a": Array(np.random.randn(7, 3))})
267
- ),
268
- "metrics": MetricRecord({"weight": 0.123}),
269
- }
270
- ),
271
- RecordDict(
272
- {
273
- "global-model": ArrayRecord(
274
- OrderedDict({"b": Array(np.random.randn(7, 3))})
275
- ),
276
- "metrics": MetricRecord({"weight": 0.123}),
277
- }
278
- ),
279
- ],
280
- ), # top-level keys match for ArrayRecords but not those for Arrays
281
- (
282
- [
283
- RecordDict(
284
- {
285
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
286
- "metrics": MetricRecord({"weight": 0.123}),
287
- }
288
- ),
289
- RecordDict(
290
- {
291
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
292
- "my-metrics": MetricRecord({"weight": 0.123}),
293
- }
294
- ),
295
- ],
296
- ), # top-level keys don't match for MetricRecords
297
- (
298
- [
299
- RecordDict(
300
- {
301
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
302
- "metrics": MetricRecord({"weight": 0.123}),
303
- }
304
- ),
305
- RecordDict(
306
- {
307
- "global-model": ArrayRecord([np.random.randn(7, 3)]),
308
- "my-metrics": MetricRecord({"my-weights": 0.123}),
309
- }
310
- ),
311
- ],
312
- ), # top-level keys match for MetricRecords but not inner ones
313
- ]
314
- )
315
- def test_consistency_of_replies_with_different_keys(
316
- list_records: list[RecordDict],
317
- ) -> None:
318
- """Test consistency in replies when records don't have matching keys."""
319
- # All test cases expect InconsistentMessageReplies exception to be raised
320
- with pytest.raises(InconsistentMessageReplies):
321
- validate_message_reply_consistency(
322
- list_records, weighted_by_key="weight", check_arrayrecord=True
323
- )