Repository: CS-SI/eodag
Pull request #1437 (2024-12-10 08:25:11)

feat(plugins): order and poll without downloading
Order and poll an `EOProduct` without downloading it, using `HTTPDownload.order()`.

Remaining to do in another PR:
- expose the method as `EOProduct.order()`

github-actions[bot]: ## Test Results
    4 files  ±0      4 suites  ±0   6m 8s ⏱️ ±0s
  582 tests ±0    579 ✅ ±0   3 💤 ±0  0 ❌ ±0 
2 328 runs  ±0  2 230 ✅ ±0  98 💤 ±0  0 ❌ ±0 

Results for commit 3f2236e3. ± Comparison against base commit d709297e.

[test-results]:data:application/gzip;base64,H4sIAOP7V2cC/02MzQ7CIBAGX6Xh7IGyBcGXMRTYhNgWw8/J+O6CttjjzLc7L4J+cYnchukykFR87mBL1NmHrSIIWUWdchu5ZAfdUzGmqav6q4d/tp8uUPulCtqFizHE3cSytSYDJnc6mowB7erXVP3m1PzyOWnCuvpcgQDWiHBgxcyBTkyNRiB1GkYr5YzCaY0cBJL3B3dyKw0IAQAA

github-actions[bot]: ![badge](https://raw.githubusercontent.com/CS-SI/eodag/_xml_coverage_reports/data/order-method/./badge.svg)


## Code Coverage (Ubuntu)

<details>


```
Filename                                     Stmts    Miss  Cover    Missing
-----------------------------------------  -------  ------  -------  ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
__init__.py                                      8       0  100.00%
cli.py                                         323      64  80.19%   62-63, 87, 674-735, 837-888, 892
config.py                                      428      27  93.69%   83-85, 94, 102, 106-108, 179, 190, 690-692, 805-808, 851-852, 861-862, 967, 1030-1035, 1037
crunch.py                                        5       5  0.00%    20-24
api/__init__.py                                  0       0  100.00%
api/core.py                                    779      72  90.76%   363, 653, 697-700, 738, 782, 816, 861-866, 892, 983, 1051, 1189, 1274-1286, 1322, 1324, 1352, 1356-1367, 1380-1386, 1469-1472, 1505-1525, 1577, 1594-1598, 1610-1613, 1949, 1973-1979, 2230, 2234-2238, 2247-2249, 2293-2294, 2323-2324
api/search_result.py                            58       4  93.10%   92, 101, 108, 122
api/product/__init__.py                          6       0  100.00%
api/product/_assets.py                          48       5  89.58%   75, 147, 155, 158-162
api/product/_product.py                        187      20  89.30%   70-72, 237-238, 313, 342, 399, 413-416, 429, 453-456, 499-505
api/product/metadata_mapping.py                700      76  89.14%   131-133, 230, 262-263, 309-310, 320-332, 334, 345, 351-363, 410-411, 448, 469-472, 495, 503-504, 590-591, 615-616, 622-625, 640-641, 790, 836, 989, 998-1002, 1019-1024, 1151, 1165-1185, 1205, 1210, 1339, 1353, 1424, 1476, 1499-1500, 1516-1520, 1536, 1544, 1563
api/product/drivers/__init__.py                  6       0  100.00%
api/product/drivers/base.py                      6       1  83.33%   38
plugins/__init__.py                              0       0  100.00%
plugins/base.py                                 21       2  90.48%   48, 55
plugins/manager.py                             172      15  91.28%   116-121, 171, 209, 231, 235, 259, 281, 399-402, 414-415
plugins/apis/__init__.py                         0       0  100.00%
plugins/apis/base.py                             4       0  100.00%
plugins/apis/ecmwf.py                           97      10  89.69%   170-172, 219-220, 246-248, 301-302
plugins/apis/usgs.py                           180      31  82.78%   155, 257, 291, 326-328, 333, 359-360, 365, 395-402, 413-418, 440-446, 448-454, 477
plugins/authentication/__init__.py               6       1  83.33%   31
plugins/authentication/aws_auth.py              19       0  100.00%
plugins/authentication/base.py                  17       2  88.24%   43, 56
plugins/authentication/generic.py               14       2  85.71%   51, 61
plugins/authentication/header.py                19       0  100.00%
plugins/authentication/keycloak.py              46       7  84.78%   151-154, 175-180
plugins/authentication/oauth.py                 13       7  46.15%   42-44, 48-51
plugins/authentication/openid_connect.py       206      27  86.89%   80-81, 93-111, 149, 155-183, 191, 323-326, 352
plugins/authentication/qsauth.py                34       1  97.06%   91
plugins/authentication/sas_auth.py              47       1  97.87%   76
plugins/authentication/token.py                 92      16  82.61%   114, 143, 145, 176-189, 245-249
plugins/authentication/token_exchange.py        36      14  61.11%   75, 92-120
plugins/crunch/__init__.py                       0       0  100.00%
plugins/crunch/base.py                          10       1  90.00%   43
plugins/crunch/filter_date.py                   59      14  76.27%   52-57, 69, 78, 87, 90, 102-104, 113-115, 122
plugins/crunch/filter_latest_intersect.py       47       8  82.98%   52-53, 69, 78-81, 83, 90-93
plugins/crunch/filter_latest_tpl_name.py        31       1  96.77%   83
plugins/crunch/filter_overlap.py                66      18  72.73%   28-30, 66-69, 76-79, 85, 93, 104-120
plugins/crunch/filter_property.py               30       7  76.67%   55-60, 63-64, 80-84
plugins/download/__init__.py                     0       0  100.00%
plugins/download/aws.py                        491     163  66.80%   282, 295, 362-365, 379-383, 425-427, 431, 463-464, 470-474, 503, 535, 539, 546, 576-584, 588, 620-628, 639-641, 672-746, 764-824, 835-840, 852-865, 890, 905-907, 910, 920-928, 936-949, 959-990, 997-1009, 1047, 1073, 1118-1120, 1340
plugins/download/base.py                       258      49  81.01%   136, 164, 300-301, 355-359, 365-366, 408, 411-425, 437, 441, 505-509, 539-540, 548-565, 572-580, 582-586, 629, 651, 673, 681
plugins/download/creodias_s3.py                 17       9  47.06%   53-67
plugins/download/http.py                       545     106  80.55%   237, 333-336, 339, 346-351, 369-384, 401, 413, 461, 468-474, 492, 506, 520, 528-530, 546-551, 562, 580, 623-626, 648, 688, 733, 747-753, 782-846, 864, 894-903, 939, 964-965, 984-989, 995, 998, 1015, 1032-1033, 1063-1064, 1071, 1133, 1148, 1207-1208, 1214, 1224, 1260, 1296, 1316, 1351-1353
plugins/download/s3rest.py                     116      24  79.31%   118, 152, 159, 194, 221-228, 231-233, 237, 248-254, 262-263, 266-270, 293, 314-317
plugins/search/__init__.py                      22       0  100.00%
plugins/search/base.py                         146      11  92.47%   100, 104, 128-134, 274, 294, 433
plugins/search/build_search_result.py          341      49  85.63%   249, 277-278, 314, 317, 386-389, 478-495, 523, 558, 560, 585-592, 622-624, 628, 650, 685, 736, 765-766, 781-796, 839, 864, 867, 870, 878, 997-998, 1004, 1015, 1073, 1124
plugins/search/cop_marine.py                   240      47  80.42%   56, 64-66, 76-77, 82, 87-88, 104, 106, 109, 175-176, 218, 224, 228, 232, 245, 256-257, 265, 293, 297, 312, 316, 320, 324, 328-332, 338-341, 344-358, 375, 424-428, 433, 445
plugins/search/creodias_s3.py                   55       3  94.55%   59, 77, 111
plugins/search/csw.py                          105      81  22.86%   98-99, 103-104, 112-160, 166-179, 187-219, 237-278
plugins/search/data_request_search.py          202      69  65.84%   188-191, 207, 218, 222-223, 234, 239, 244, 251, 264-267, 321-322, 326, 336-342, 347, 373-376, 384-395, 412, 414, 421-424, 426-427, 445-449, 482, 492, 503, 516, 522-537, 542
plugins/search/qssearch.py                     732      89  87.84%   450, 508, 522, 526-532, 560-564, 677-689, 734-737, 808-809, 857, 876, 883, 895, 952, 973, 976-977, 986-987, 996-997, 1006-1007, 1034, 1105-1110, 1114-1123, 1157, 1179, 1256, 1346, 1431-1432, 1442, 1519-1523, 1585, 1588, 1594-1595, 1616, 1644-1656, 1663, 1695-1697, 1707-1713, 1743, 1766, 1771-1772, 1787, 1803, 1888-1891, 1896-1899, 1908, 1938-1942, 1948
plugins/search/static_stac_search.py            75      13  82.67%   98-124, 140, 153
rest/__init__.py                                 4       2  50.00%   21-22
rest/cache.py                                   33       7  78.79%   35-37, 53-55, 59, 68
rest/config.py                                  25       0  100.00%
rest/constants.py                                6       0  100.00%
rest/core.py                                   257      63  75.49%   258, 266, 284-301, 316-352, 446, 483-522, 705, 712-760
rest/errors.py                                  69       5  92.75%   106, 116, 127, 143-144
rest/server.py                                 192      24  87.50%   94, 117-119, 293-298, 326, 522-524, 541-546, 575, 577, 581-582, 586-587
rest/stac.py                                   319      63  80.25%   306, 328, 380-383, 410-437, 468-470, 493, 525-526, 608-648, 670-686, 778-782, 789, 843-844, 905, 995-997
rest/types/__init__.py                           0       0  100.00%
rest/types/collections_search.py                13      13  0.00%    18-44
rest/types/eodag_search.py                     180       6  96.67%   225-229, 282, 285, 353, 385
rest/types/queryables.py                        57       5  91.23%   93-98, 162
rest/types/stac_search.py                      125       7  94.40%   138, 184, 199-201, 209, 213
rest/utils/__init__.py                          94      12  87.23%   111-112, 131-133, 185, 195-209
rest/utils/cql_evaluate.py                      48       5  89.58%   69, 76, 90, 97, 105
rest/utils/rfc3339.py                           23       3  86.96%   48, 60, 62
types/__init__.py                              128      42  67.19%   66, 79-83, 94-106, 134-136, 143-148, 189, 208, 230, 240-256, 261, 263, 285, 290, 298, 308
types/bbox.py                                   43      19  55.81%   46-61, 72-74, 85-87, 99-101, 113-115, 123
types/download_args.py                           9       0  100.00%
types/queryables.py                            108       1  99.07%   63
types/search_args.py                            70      18  74.29%   60-64, 71-88, 103
types/whoosh.py                                 15       0  100.00%
utils/__init__.py                              520      47  90.96%   85, 194-195, 204-231, 234, 249, 329-333, 406-410, 429-431, 444-458, 537, 552, 592-593, 957-960, 968-969, 1007-1008, 1055-1056, 1190
utils/exceptions.py                             46       0  100.00%
utils/import_system.py                          28      19  32.14%   64-78, 89-99
utils/logging.py                                28       1  96.43%   41
utils/notebook.py                               44      23  47.73%   25-29, 36-41, 58-62, 72-78, 83-87
utils/repr.py                                   38       8  78.95%   51, 53, 57, 98, 122-129
utils/requests.py                               55      29  47.27%   51-52, 64, 85-96, 107-124, 128
utils/rest.py                                   36       1  97.22%   55
utils/stac_reader.py                           111      45  59.46%   56-57, 63-85, 95-97, 101, 137, 153-156, 203-212, 222-252
TOTAL                                         9889    1640  83.42%
```

</details>


### Diff against develop

```
Filename                    Stmts    Miss  Cover
------------------------  -------  ------  --------
plugins/download/http.py       +4      +1  -0.04%
TOTAL                          +4      +1  +100.00%
```


Results for commit: 3f2236e3d6b5304291c6f0ea31d88bf6eaaf536f


_Minimum allowed coverage is `70%`_


:recycle: This comment has been updated with latest results


<!-- Sticky Pull Request Commentartifacts/unit-test-results-python3.13-ubuntu-latest/coverage.xml -->
github-actions[bot]: ![badge](https://raw.githubusercontent.com/CS-SI/eodag/_xml_coverage_reports_win/data/order-method/./badge.svg)


## Code Coverage (Windows)

<details>


```
Filename                                     Stmts    Miss  Cover    Missing
-----------------------------------------  -------  ------  -------  --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
__init__.py                                      8       0  100.00%
cli.py                                         323      64  80.19%   62-63, 87, 674-735, 837-888, 892
config.py                                      428      28  93.46%   83-85, 94, 102, 106-108, 179, 190, 690-692, 805-808, 851-852, 861-862, 967, 998, 1030-1035, 1037
crunch.py                                        5       5  0.00%    20-24
api/__init__.py                                  0       0  100.00%
api/core.py                                    779      72  90.76%   363, 653, 697-700, 738, 782, 816, 861-866, 892, 983, 1051, 1189, 1274-1286, 1322, 1324, 1352, 1356-1367, 1380-1386, 1469-1472, 1505-1525, 1577, 1594-1598, 1610-1613, 1949, 1973-1979, 2230, 2234-2238, 2247-2249, 2293-2294, 2323-2324
api/search_result.py                            58       4  93.10%   92, 101, 108, 122
api/product/__init__.py                          6       0  100.00%
api/product/_assets.py                          48       5  89.58%   75, 147, 155, 158-162
api/product/_product.py                        187      20  89.30%   70-72, 237-238, 313, 342, 399, 413-416, 429, 453-456, 499-505
api/product/metadata_mapping.py                700      77  89.00%   131-133, 230, 262-263, 309-310, 320-332, 334, 345, 351-363, 410-411, 448, 469-472, 495, 503-504, 590-591, 615-616, 622-625, 640-641, 790, 836, 989, 998-1002, 1019-1024, 1151, 1165-1185, 1205, 1210, 1339, 1353, 1424, 1476, 1499-1500, 1503, 1516-1520, 1536, 1544, 1563
api/product/drivers/__init__.py                  6       0  100.00%
api/product/drivers/base.py                      6       1  83.33%   38
plugins/__init__.py                              0       0  100.00%
plugins/base.py                                 21       3  85.71%   48, 55, 68
plugins/manager.py                             172      15  91.28%   116-121, 171, 209, 231, 235, 259, 281, 399-402, 414-415
plugins/apis/__init__.py                         0       0  100.00%
plugins/apis/base.py                             4       0  100.00%
plugins/apis/ecmwf.py                           97      10  89.69%   170-172, 219-220, 246-248, 301-302
plugins/apis/usgs.py                           180      31  82.78%   155, 257, 291, 326-328, 333, 359-360, 365, 395-402, 413-418, 440-446, 448-454, 477
plugins/authentication/__init__.py               6       1  83.33%   31
plugins/authentication/aws_auth.py              19       0  100.00%
plugins/authentication/base.py                  17       2  88.24%   43, 56
plugins/authentication/generic.py               14       2  85.71%   51, 61
plugins/authentication/header.py                19       0  100.00%
plugins/authentication/keycloak.py              46       7  84.78%   151-154, 175-180
plugins/authentication/oauth.py                 13       7  46.15%   42-44, 48-51
plugins/authentication/openid_connect.py       206      27  86.89%   80-81, 93-111, 149, 155-183, 191, 323-326, 352
plugins/authentication/qsauth.py                34       1  97.06%   91
plugins/authentication/sas_auth.py              47       1  97.87%   76
plugins/authentication/token.py                 92      16  82.61%   114, 143, 145, 176-189, 245-249
plugins/authentication/token_exchange.py        36      14  61.11%   75, 92-120
plugins/crunch/__init__.py                       0       0  100.00%
plugins/crunch/base.py                          10       1  90.00%   43
plugins/crunch/filter_date.py                   59      14  76.27%   52-57, 69, 78, 87, 90, 102-104, 113-115, 122
plugins/crunch/filter_latest_intersect.py       47      33  29.79%   49-54, 67-112
plugins/crunch/filter_latest_tpl_name.py        31       1  96.77%   83
plugins/crunch/filter_overlap.py                66      18  72.73%   28-30, 66-69, 76-79, 85, 93, 104-120
plugins/crunch/filter_property.py               30       7  76.67%   55-60, 63-64, 80-84
plugins/download/__init__.py                     0       0  100.00%
plugins/download/aws.py                        491     163  66.80%   282, 295, 362-365, 379-383, 425-427, 431, 463-464, 470-474, 503, 535, 539, 546, 576-584, 588, 620-628, 639-641, 672-746, 764-824, 835-840, 852-865, 890, 905-907, 910, 920-928, 936-949, 959-990, 997-1009, 1047, 1073, 1118-1120, 1340
plugins/download/base.py                       258      51  80.23%   136, 164, 231-233, 300-301, 355-359, 365-366, 408, 411-425, 437, 441, 505-509, 539-540, 548-565, 572-580, 582-586, 629, 651, 673, 681
plugins/download/creodias_s3.py                 17       9  47.06%   53-67
plugins/download/http.py                       545     107  80.37%   237, 333-336, 339, 346-351, 369-384, 401, 413, 461, 468-474, 492, 506, 520, 528-530, 546-551, 562, 580, 623-626, 648, 688, 733, 747-753, 782-846, 864, 894-903, 939, 964-965, 984-989, 995, 998, 1015, 1032-1033, 1046, 1063-1064, 1071, 1133, 1148, 1207-1208, 1214, 1224, 1260, 1296, 1316, 1351-1353
plugins/download/s3rest.py                     116      24  79.31%   118, 152, 159, 194, 221-228, 231-233, 237, 248-254, 262-263, 266-270, 293, 314-317
plugins/search/__init__.py                      22       0  100.00%
plugins/search/base.py                         146      11  92.47%   100, 104, 128-134, 274, 294, 433
plugins/search/build_search_result.py          341      50  85.34%   249, 277-278, 314, 317, 386-389, 478-495, 523, 558, 560, 585-592, 622-624, 628, 650, 685, 736, 750, 765-766, 781-796, 839, 864, 867, 870, 878, 997-998, 1004, 1015, 1073, 1124
plugins/search/cop_marine.py                   240      47  80.42%   56, 64-66, 76-77, 82, 87-88, 104, 106, 109, 175-176, 218, 224, 228, 232, 245, 256-257, 265, 293, 297, 312, 316, 320, 324, 328-332, 338-341, 344-358, 375, 424-428, 433, 445
plugins/search/creodias_s3.py                   55       3  94.55%   59, 77, 111
plugins/search/csw.py                          105      81  22.86%   98-99, 103-104, 112-160, 166-179, 187-219, 237-278
plugins/search/data_request_search.py          202      69  65.84%   188-191, 207, 218, 222-223, 234, 239, 244, 251, 264-267, 321-322, 326, 336-342, 347, 373-376, 384-395, 412, 414, 421-424, 426-427, 445-449, 482, 492, 503, 516, 522-537, 542
plugins/search/qssearch.py                     732     125  82.92%   450, 508, 522, 526-532, 560-564, 677-689, 734-737, 808-809, 857, 876, 883, 895, 952, 973, 976-977, 986-987, 996-997, 1006-1007, 1034, 1105-1110, 1114-1123, 1157, 1179, 1256, 1346, 1431-1432, 1442, 1519-1523, 1585, 1588, 1594-1595, 1616, 1644-1656, 1663, 1695-1697, 1707-1713, 1743, 1766, 1771-1772, 1787, 1803, 1871-1981
plugins/search/static_stac_search.py            75      13  82.67%   98-124, 140, 153
rest/__init__.py                                 4       2  50.00%   21-22
rest/cache.py                                   33      22  33.33%   35-37, 44-70
rest/config.py                                  25       1  96.00%   35
rest/constants.py                                6       0  100.00%
rest/core.py                                   257     150  41.63%   157, 159, 161, 164-165, 179-189, 198-199, 205, 208, 249-303, 316-352, 383-420, 435-451, 467-476, 483-522, 539, 581-666, 705, 712-760
rest/errors.py                                  69      49  28.99%   60, 65-100, 105-108, 115-118, 126-147, 155-160, 175-181
rest/server.py                                 192     192  0.00%    18-600
rest/stac.py                                   319      68  78.68%   240, 306, 328, 380-383, 410-437, 468-470, 493, 525-526, 608-648, 670-686, 713, 778-782, 789, 843-844, 850, 905, 943, 976, 995-997
rest/types/__init__.py                           0       0  100.00%
rest/types/collections_search.py                13      13  0.00%    18-44
rest/types/eodag_search.py                     180      20  88.89%   225-229, 262-264, 282, 285, 291, 295, 353, 371-386
rest/types/queryables.py                        57      13  77.19%   50-51, 58-59, 66-67, 93-98, 107-108, 162
rest/types/stac_search.py                      125      11  91.20%   136-138, 184, 199-201, 209, 213, 261, 264
rest/utils/__init__.py                          94      30  68.09%   82-88, 108, 111-112, 131-133, 146, 153, 178-186, 193-214
rest/utils/cql_evaluate.py                      48       5  89.58%   69, 76, 90, 97, 105
rest/utils/rfc3339.py                           23       5  78.26%   43-44, 48, 60, 62
types/__init__.py                              128      44  65.62%   66, 70, 79-83, 94-106, 134-136, 143-148, 189, 203, 208, 230, 240-256, 261, 263, 285, 290, 298, 308
types/bbox.py                                   43      19  55.81%   46-61, 72-74, 85-87, 99-101, 113-115, 123
types/download_args.py                           9       0  100.00%
types/queryables.py                            108       1  99.07%   63
types/search_args.py                            70      18  74.29%   60-64, 71-88, 103
types/whoosh.py                                 15       0  100.00%
utils/__init__.py                              520      47  90.96%   85, 194-195, 204-231, 234, 249, 329-333, 406-410, 429-431, 444-458, 537, 552, 592-593, 957-960, 968-969, 1007-1008, 1055-1056, 1190
utils/exceptions.py                             46       0  100.00%
utils/import_system.py                          28      19  32.14%   64-78, 89-99
utils/logging.py                                28       1  96.43%   41
utils/notebook.py                               44      23  47.73%   25-29, 36-41, 58-62, 72-78, 83-87
utils/repr.py                                   38       8  78.95%   51, 53, 57, 98, 122-129
utils/requests.py                               55      29  47.27%   51-52, 64, 85-96, 107-124, 128
utils/rest.py                                   36       1  97.22%   55
utils/stac_reader.py                           111      45  59.46%   56-57, 63-85, 95-97, 101, 137, 153-156, 203-212, 222-252
TOTAL                                         9889    2076  79.01%
```

</details>


### Diff against develop

```
Filename                    Stmts    Miss  Cover
------------------------  -------  ------  --------
plugins/download/http.py       +4      +1  -0.04%
TOTAL                          +4      +1  +100.00%
```


Results for commit: 3f2236e3d6b5304291c6f0ea31d88bf6eaaf536f


_Minimum allowed coverage is `70%`_


:recycle: This comment has been updated with latest results


<!-- Sticky Pull Request Commentartifacts/unit-test-results-python3.13-windows-latest/coverage.xml -->

Patch:
diff --git a/eodag/plugins/apis/usgs.py b/eodag/plugins/apis/usgs.py
index 79bf49bd..f1663e3f 100644
--- a/eodag/plugins/apis/usgs.py
+++ b/eodag/plugins/apis/usgs.py
@@ -375,7 +375,7 @@ class UsgsApi(Api):
         logger.debug(f"Downloading {req_url}")
         ssl_verify = getattr(self.config, "ssl_verify", True)
 
-        @self._download_retry(product, wait, timeout)
+        @self._order_download_retry(product, wait, timeout)
         def download_request(
             product: EOProduct,
             fs_path: str,
diff --git a/eodag/plugins/download/base.py b/eodag/plugins/download/base.py
index b52e0d7a..12b28355 100644
--- a/eodag/plugins/download/base.py
+++ b/eodag/plugins/download/base.py
@@ -589,14 +589,14 @@ class Download(PluginTopic):
 
         return paths
 
-    def _download_retry(
+    def _order_download_retry(
         self, product: EOProduct, wait: int, timeout: int
     ) -> Callable[[Callable[..., T]], Callable[..., T]]:
         """
-        Download retry decorator.
+        Order download retry decorator.
 
-        Retries the wrapped  download method after `wait` minutes if a NotAvailableError
-        exception is thrown until `timeout` minutes.
+        Retries the wrapped order_download method after ``wait`` minutes if a
+        ``NotAvailableError`` exception is thrown until ``timeout`` minutes.
 
         :param product: The EO product to download
         :param wait: If download fails, wait time in minutes between two download tries
@@ -605,7 +605,7 @@ class Download(PluginTopic):
         :returns: decorator
         """
 
-        def decorator(download: Callable[..., T]) -> Callable[..., T]:
+        def decorator(order_download: Callable[..., T]) -> Callable[..., T]:
             def download_and_retry(*args: Any, **kwargs: Unpack[DownloadConf]) -> T:
                 # initiate retry loop
                 start_time = datetime.now()
@@ -622,7 +622,7 @@ class Download(PluginTopic):
                     if datetime_now >= product.next_try:
                         product.next_try += timedelta(minutes=wait)
                         try:
-                            return download(*args, **kwargs)
+                            return order_download(*args, **kwargs)
 
                         except NotAvailableError as e:
                             if not getattr(self.config, "order_enabled", False):
@@ -638,7 +638,7 @@ class Download(PluginTopic):
                         ).seconds
                         retry_count += 1
                         retry_info = (
-                            f"[Retry #{retry_count}] Waited {wait_seconds}s, trying again to download ordered product"
+                            f"[Retry #{retry_count}] Waited {wait_seconds}s, checking order status again"
                             f" (retry every {wait}' for {timeout}')"
                         )
                         logger.info(not_available_info)
@@ -660,8 +660,8 @@ class Download(PluginTopic):
                         ).microseconds / 1e6
                         retry_count += 1
                         retry_info = (
-                            f"[Retry #{retry_count}] Waiting {wait_seconds}s until next download try"
-                            f" for ordered product (retry every {wait}' for {timeout}')"
+                            f"[Retry #{retry_count}] Waiting {wait_seconds}s until next order status check"
+                            f" (retry every {wait}' for {timeout}')"
                         )
                         logger.info(not_available_info)
                         # Retry-After info from Response header
@@ -682,12 +682,12 @@ class Download(PluginTopic):
                         logger.info(not_available_info)
                         raise NotAvailableError(
                             f"{product.properties['title']} is not available ({product.properties['storageStatus']})"
-                            f" and could not be downloaded, timeout reached"
+                            f" and order was not successfull, timeout reached"
                         )
                     elif datetime_now >= stop_time:
                         raise NotAvailableError(not_available_info)
 
-                return download(*args, **kwargs)
+                return order_download(*args, **kwargs)
 
             return download_and_retry
 
diff --git a/eodag/plugins/download/http.py b/eodag/plugins/download/http.py
index 88427cc2..7d3af094 100644
--- a/eodag/plugins/download/http.py
+++ b/eodag/plugins/download/http.py
@@ -149,7 +149,7 @@ class HTTPDownload(Download):
     def __init__(self, provider: str, config: PluginConfig) -> None:
         super(HTTPDownload, self).__init__(provider, config)
 
-    def order_download(
+    def _order(
         self,
         product: EOProduct,
         auth: Optional[AuthBase] = None,
@@ -273,7 +273,7 @@ class HTTPDownload(Download):
 
         return json_response
 
-    def order_download_status(
+    def _order_status(
         self,
         product: EOProduct,
         auth: Optional[AuthBase] = None,
@@ -627,7 +627,7 @@ class HTTPDownload(Download):
 
         url = product.remote_location
 
-        @self._download_retry(product, wait, timeout)
+        @self._order_download_retry(product, wait, timeout)
         def download_request(
             product: EOProduct,
             auth: AuthBase,
@@ -902,6 +902,44 @@ class HTTPDownload(Download):
             else:
                 logger.error("Error while getting resource :\n%s", tb.format_exc())
 
+    def _order_request(
+        self,
+        product: EOProduct,
+        auth: Optional[AuthBase],
+    ) -> None:
+        if (
+            "orderLink" in product.properties
+            and product.properties.get("storageStatus") == OFFLINE_STATUS
+            and not product.properties.get("orderStatus")
+        ):
+            self._order(product=product, auth=auth)
+
+        if (
+            product.properties.get("orderStatusLink", None)
+            and product.properties.get("storageStatus") != ONLINE_STATUS
+        ):
+            self._order_status(product=product, auth=auth)
+
+    def order(
+        self,
+        product: EOProduct,
+        auth: Optional[Union[AuthBase, Dict[str, str]]] = None,
+        wait: int = DEFAULT_DOWNLOAD_WAIT,
+        timeout: int = DEFAULT_DOWNLOAD_TIMEOUT,
+    ) -> None:
+        """
+        Order product and poll to check its status
+
+        :param product: The EO product to download
+        :param auth: (optional) authenticated object
+        :param wait: (optional) Wait time in minutes between two order status check
+        :param timeout: (optional) Maximum time in minutes before stop checking
+                        order status
+        """
+        self._order_download_retry(product, wait, timeout)(self._order_request)(
+            product, auth
+        )
+
     def _stream_download(
         self,
         product: EOProduct,
@@ -910,8 +948,9 @@ class HTTPDownload(Download):
         **kwargs: Unpack[DownloadConf],
     ) -> Iterator[Any]:
         """
-        fetches a zip file containing the assets of a given product as a stream
+        Fetches a zip file containing the assets of a given product as a stream
         and returns a generator yielding the chunks of the file
+
         :param product: product for which the assets should be downloaded
         :param auth: The configuration of a plugin of type Authentication
         :param progress_callback: A method or a callable object
@@ -928,18 +967,8 @@ class HTTPDownload(Download):
         ssl_verify = getattr(self.config, "ssl_verify", True)
 
         ordered_message = ""
-        if (
-            "orderLink" in product.properties
-            and product.properties.get("storageStatus") == OFFLINE_STATUS
-            and not product.properties.get("orderStatus")
-        ):
-            self.order_download(product=product, auth=auth)
-
-        if (
-            product.properties.get("orderStatusLink", None)
-            and product.properties.get("storageStatus") != ONLINE_STATUS
-        ):
-            self.order_download_status(product=product, auth=auth)
+        # retry handled at download level
+        self._order_request(product, auth)
 
         params = kwargs.pop("dl_url_params", None) or getattr(
             self.config, "dl_url_params", {}
diff --git a/eodag/plugins/download/s3rest.py b/eodag/plugins/download/s3rest.py
index 1158a70e..162e9a91 100644
--- a/eodag/plugins/download/s3rest.py
+++ b/eodag/plugins/download/s3rest.py
@@ -130,9 +130,9 @@ class S3RestDownload(Download):
             and "storageStatus" in product.properties
             and product.properties["storageStatus"] != ONLINE_STATUS
         ):
-            self.http_download_plugin.order_download(product=product, auth=auth)
+            self.http_download_plugin._order(product=product, auth=auth)
 
-        @self._download_retry(product, wait, timeout)
+        @self._order_download_retry(product, wait, timeout)
         def download_request(
             product: EOProduct,
             auth: AuthBase,
@@ -142,9 +142,7 @@ class S3RestDownload(Download):
         ):
             # check order status
             if product.properties.get("orderStatusLink", None):
-                self.http_download_plugin.order_download_status(
-                    product=product, auth=auth
-                )
+                self.http_download_plugin._order_status(product=product, auth=auth)
 
             # get bucket urls
             bucket_name, prefix = get_bucket_name_and_prefix(
diff --git a/eodag/rest/core.py b/eodag/rest/core.py
index 82b38181..c8f065f3 100644
--- a/eodag/rest/core.py
+++ b/eodag/rest/core.py
@@ -327,13 +327,11 @@ def _order_and_update(
     if (
         product.properties.get("storageStatus") != ONLINE_STATUS
         and NOT_AVAILABLE in product.properties.get("orderStatusLink", "")
-        and hasattr(product.downloader, "order_download")
+        and hasattr(product.downloader, "_order")
     ):
         # first order
         logger.debug("Order product")
-        order_status_dict = product.downloader.order_download(
-            product=product, auth=auth
-        )
+        order_status_dict = product.downloader._order(product=product, auth=auth)
         query_args.update(order_status_dict or {})
 
     if (
@@ -344,11 +342,11 @@ def _order_and_update(
         product.properties["storageStatus"] = STAGING_STATUS
 
     if product.properties.get("storageStatus") == STAGING_STATUS and hasattr(
-        product.downloader, "order_download_status"
+        product.downloader, "_order_status"
     ):
         # check order status if needed
         logger.debug("Checking product order status")
-        product.downloader.order_download_status(product=product, auth=auth)
+        product.downloader._order_status(product=product, auth=auth)
 
     if product.properties.get("storageStatus") != ONLINE_STATUS:
         raise NotAvailableError("Product is not available yet")


Test patch:
diff --git a/tests/units/test_download_plugins.py b/tests/units/test_download_plugins.py
index 603b5e42..4bf19d25 100644
--- a/tests/units/test_download_plugins.py
+++ b/tests/units/test_download_plugins.py
@@ -1188,7 +1188,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
     @mock.patch("eodag.plugins.download.http.requests.request", autospec=True)
     def test_plugins_download_http_order_get(self, mock_request):
-        """HTTPDownload.order_download() must request using orderLink and GET protocol"""
+        """HTTPDownload._order() must request using orderLink and GET protocol"""
         plugin = self.get_download_plugin(self.product)
         self.product.properties["downloadLink"] = "https://peps.cnes.fr/dummy"
         self.product.properties["orderLink"] = "http://somewhere/order"
@@ -1202,7 +1202,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
             auth_plugin.config.credentials = {"username": "foo", "password": "bar"}
             auth = auth_plugin.authenticate()
 
-            plugin.order_download(self.product, auth=auth)
+            plugin._order(self.product, auth=auth)
 
             mock_request.assert_called_once_with(
                 method="GET",
@@ -1220,7 +1220,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
     @mock.patch("eodag.plugins.download.http.requests.request", autospec=True)
     def test_plugins_download_http_order_get_raises_if_request_500(self, mock_request):
-        """HTTPDownload.order_download() must raise an error if request to backend
+        """HTTPDownload._order() must raise an error if request to backend
         provider failed"""
 
         # Configure mock to raise an error
@@ -1236,7 +1236,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
         # Verify that a DownloadError is raised
         with self.assertRaises(DownloadError) as context:
-            plugin.order_download(self.product, auth=auth)
+            plugin._order(self.product, auth=auth)
         self.assertIn("could not be ordered", str(context.exception))
 
         mock_request.assert_called_once_with(
@@ -1267,7 +1267,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
         # Test the function, expecting ValidationError to be raised
         with self.assertRaises(ValidationError) as context:
-            plugin.order_download(self.product, auth=auth)
+            plugin._order(self.product, auth=auth)
         self.assertIn("could not be ordered", str(context.exception))
 
         mock_request.assert_called_once_with(
@@ -1281,7 +1281,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
     @mock.patch("eodag.plugins.download.http.requests.request", autospec=True)
     def test_plugins_download_http_order_post(self, mock_request):
-        """HTTPDownload.order_download() must request using orderLink and POST protocol"""
+        """HTTPDownload._order() must request using orderLink and POST protocol"""
         plugin = self.get_download_plugin(self.product)
         self.product.properties["downloadLink"] = "https://peps.cnes.fr/dummy"
         self.product.properties["storageStatus"] = OFFLINE_STATUS
@@ -1293,7 +1293,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
         # orderLink without query query args
         self.product.properties["orderLink"] = "http://somewhere/order"
-        plugin.order_download(self.product, auth=auth)
+        plugin._order(self.product, auth=auth)
         mock_request.assert_called_once_with(
             method="POST",
             url=self.product.properties["orderLink"],
@@ -1305,7 +1305,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
         # orderLink with query query args
         mock_request.reset_mock()
         self.product.properties["orderLink"] = "http://somewhere/order?foo=bar"
-        plugin.order_download(self.product, auth=auth)
+        plugin._order(self.product, auth=auth)
         mock_request.assert_called_once_with(
             method="POST",
             url="http://somewhere/order",
@@ -1321,7 +1321,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
         self.product.properties[
             "orderLink"
         ] = 'http://somewhere/order?{"location": "dataset_id=lorem&data_version=202211", "cacheable": "true"}'
-        plugin.order_download(self.product, auth=auth)
+        plugin._order(self.product, auth=auth)
         mock_request.assert_called_once_with(
             method="POST",
             url="http://somewhere/order",
@@ -1336,7 +1336,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
         )
 
     def test_plugins_download_http_order_status(self):
-        """HTTPDownload.order_download_status() must request status using orderStatusLink"""
+        """HTTPDownload._order_status() must request status using orderStatusLink"""
         plugin = self.get_download_plugin(self.product)
         plugin.config.order_status = {
             "metadata_mapping": {
@@ -1363,7 +1363,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
             )
 
             with self.assertRaises(DownloadError):
-                plugin.order_download_status(self.product, auth=auth)
+                plugin._order_status(self.product, auth=auth)
 
             self.assertIn(
                 list(USER_AGENT.items())[0], responses.calls[0].request.headers.items()
@@ -1376,7 +1376,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
     def test_plugins_download_http_order_status_get_raises_if_request_500(
         self, mock_request
     ):
-        """HTTPDownload.order_download() must raise an error if request to backend
+        """HTTPDownload._order() must raise an error if request to backend
         provider failed"""
 
         # Configure mock to raise an error
@@ -1393,7 +1393,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
         # Verify that a DownloadError is raised
         with self.assertRaises(DownloadError) as context:
-            plugin.order_download_status(self.product, auth=auth)
+            plugin._order_status(self.product, auth=auth)
         self.assertIn("order status could not be checked", str(context.exception))
 
         mock_request.assert_called_once_with(
@@ -1428,7 +1428,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
         # Test the function, expecting ValidationError to be raised
         with self.assertRaises(ValidationError) as context:
-            plugin.order_download_status(self.product, auth=auth)
+            plugin._order_status(self.product, auth=auth)
         self.assertIn("order status could not be checked", str(context.exception))
 
         mock_request.assert_called_once_with(
@@ -1442,7 +1442,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
         )
 
     def test_plugins_download_http_order_status_search_again(self):
-        """HTTPDownload.order_download_status() must search again after success if needed"""
+        """HTTPDownload._order_status() must search again after success if needed"""
         plugin = self.get_download_plugin(self.product)
         plugin.config.order_status = {
             "metadata_mapping": {"status": "$.json.status"},
@@ -1484,7 +1484,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
                 ),
             )
 
-            plugin.order_download_status(self.product, auth=auth)
+            plugin._order_status(self.product, auth=auth)
 
             self.assertEqual(
                 self.product.properties["downloadLink"], "http://new-download-link"
@@ -2020,12 +2020,8 @@ class TestDownloadPluginS3Rest(BaseDownloadPluginTest):
             productType="S2_MSI_L1C",
         )
 
-    @mock.patch(
-        "eodag.plugins.download.http.HTTPDownload.order_download_status", autospec=True
-    )
-    @mock.patch(
-        "eodag.plugins.download.http.HTTPDownload.order_download", autospec=True
-    )
+    @mock.patch("eodag.plugins.download.http.HTTPDownload._order_status", autospec=True)
+    @mock.patch("eodag.plugins.download.http.HTTPDownload._order", autospec=True)
     def test_plugins_download_s3rest_online(self, mock_order, mock_order_status):
         """S3RestDownload.download() must create outputfiles"""
 
@@ -2092,12 +2088,8 @@ class TestDownloadPluginS3Rest(BaseDownloadPluginTest):
         mock_order.assert_not_called()
         mock_order_status.assert_not_called()
 
-    @mock.patch(
-        "eodag.plugins.download.http.HTTPDownload.order_download_status", autospec=True
-    )
-    @mock.patch(
-        "eodag.plugins.download.http.HTTPDownload.order_download", autospec=True
-    )
+    @mock.patch("eodag.plugins.download.http.HTTPDownload._order_status", autospec=True)
+    @mock.patch("eodag.plugins.download.http.HTTPDownload._order", autospec=True)
     def test_plugins_download_s3rest_offline(self, mock_order, mock_order_status):
         """S3RestDownload.download() must order offline products"""