dgenerate-ultralytics-headless 8.3.185__py3-none-any.whl → 8.3.186__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dgenerate-ultralytics-headless
3
- Version: 8.3.185
3
+ Version: 8.3.186
4
4
  Summary: Automatically built Ultralytics package with python-opencv-headless dependency instead of python-opencv
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -42,7 +42,6 @@ Requires-Dist: scipy>=1.4.1
42
42
  Requires-Dist: torch>=1.8.0
43
43
  Requires-Dist: torch!=2.4.0,>=1.8.0; sys_platform == "win32"
44
44
  Requires-Dist: torchvision>=0.9.0
45
- Requires-Dist: tqdm>=4.64.0
46
45
  Requires-Dist: psutil
47
46
  Requires-Dist: py-cpuinfo
48
47
  Requires-Dist: pandas>=1.1.4
@@ -55,7 +54,7 @@ Requires-Dist: coverage[toml]; extra == "dev"
55
54
  Requires-Dist: mkdocs>=1.6.0; extra == "dev"
56
55
  Requires-Dist: mkdocs-material>=9.5.9; extra == "dev"
57
56
  Requires-Dist: mkdocstrings[python]; extra == "dev"
58
- Requires-Dist: mkdocs-ultralytics-plugin>=0.1.26; extra == "dev"
57
+ Requires-Dist: mkdocs-ultralytics-plugin>=0.1.28; extra == "dev"
59
58
  Requires-Dist: mkdocs-macros-plugin>=1.0.5; extra == "dev"
60
59
  Provides-Extra: export
61
60
  Requires-Dist: numpy<2.0.0; extra == "export"
@@ -131,7 +130,7 @@ The workflow runs automatically every day at midnight UTC to check for new Ultra
131
130
 
132
131
  <div>
133
132
  <a href="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yml"><img src="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yml/badge.svg" alt="Ultralytics CI"></a>
134
- <a href="https://pepy.tech/projects/ultralytics"><img src="https://static.pepy.tech/badge/ultralytics" alt="Ultralytics Downloads"></a>
133
+ <a href="https://clickpy.clickhouse.com/dashboard/ultralytics"><img src="https://static.pepy.tech/badge/ultralytics" alt="Ultralytics Downloads"></a>
135
134
  <a href="https://zenodo.org/badge/latestdoi/264818686"><img src="https://zenodo.org/badge/264818686.svg" alt="Ultralytics YOLO Citation"></a>
136
135
  <a href="https://discord.com/invite/ultralytics"><img alt="Ultralytics Discord" src="https://img.shields.io/discord/1089800235347353640?logo=discord&logoColor=white&label=Discord&color=blue"></a>
137
136
  <a href="https://community.ultralytics.com/"><img alt="Ultralytics Forums" src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fcommunity.ultralytics.com&logo=discourse&label=Forums&color=blue"></a>
@@ -180,7 +179,7 @@ See below for quickstart installation and usage examples. For comprehensive guid
180
179
 
181
180
  Install the `ultralytics` package, including all [requirements](https://github.com/ultralytics/ultralytics/blob/main/pyproject.toml), in a [**Python>=3.8**](https://www.python.org/) environment with [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/).
182
181
 
183
- [![PyPI - Version](https://img.shields.io/pypi/v/ultralytics?logo=pypi&logoColor=white)](https://pypi.org/project/ultralytics/) [![Ultralytics Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ultralytics?logo=python&logoColor=gold)](https://pypi.org/project/ultralytics/)
182
+ [![PyPI - Version](https://img.shields.io/pypi/v/ultralytics?logo=pypi&logoColor=white)](https://pypi.org/project/ultralytics/) [![Ultralytics Downloads](https://static.pepy.tech/badge/ultralytics)](https://clickpy.clickhouse.com/dashboard/ultralytics) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ultralytics?logo=python&logoColor=gold)](https://pypi.org/project/ultralytics/)
184
183
 
185
184
  ```bash
186
185
  pip install ultralytics
@@ -1,4 +1,4 @@
1
- dgenerate_ultralytics_headless-8.3.185.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
1
+ dgenerate_ultralytics_headless-8.3.186.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
2
2
  tests/__init__.py,sha256=b4KP5_q-2IO8Br8YHOSLYnn7IwZS81l_vfEF2YPa2lM,894
3
3
  tests/conftest.py,sha256=LXtQJcFNWPGuzauTGkiXgsvVC3llJKfg22WcmhRzuQc,2593
4
4
  tests/test_cli.py,sha256=EMf5gTAopOnIz8VvzaM-Qb044o7D0flnUHYQ-2ffOM4,5670
@@ -8,22 +8,22 @@ tests/test_exports.py,sha256=CY-4xVZlVM16vdyIC0mSR3Ix59aiZm1qjFGIhSNmB20,11007
8
8
  tests/test_integrations.py,sha256=kl_AKmE_Qs1GB0_91iVwbzNxofm_hFTt0zzU6JF-pg4,6323
9
9
  tests/test_python.py,sha256=JbOB6pbTkoQtPCjkl_idagV0_W2QLWGbsh2IvGmru0M,28274
10
10
  tests/test_solutions.py,sha256=tuf6n_fsI8KvSdJrnc-cqP2qYdiYqCWuVrx0z9dOz3Q,13213
11
- ultralytics/__init__.py,sha256=T3t4q90IckX-FOUnSIpvWlcUre7HZpg6_jBpTBKUcl0,730
11
+ ultralytics/__init__.py,sha256=CCcYcTlUEFxDB3syD60I3oQ4B2UFVPb4gCZ-jatuAsU,730
12
12
  ultralytics/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
13
13
  ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
14
14
  ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
15
15
  ultralytics/cfg/__init__.py,sha256=Uj1br3-NVFvP6VY5CL4PK63mAQAom93XFC5cqSbM6t4,39887
16
16
  ultralytics/cfg/default.yaml,sha256=1SspGAK_K_DT7DBfEScJh4jsJUTOxahehZYj92xmj7o,8347
17
- ultralytics/cfg/datasets/Argoverse.yaml,sha256=4SGaJio9JFUkrscHJTPnH_QSbYm48Wbk8EFwl39zntc,3262
17
+ ultralytics/cfg/datasets/Argoverse.yaml,sha256=J4ItoUlE_EiYTmp1DFKYHfbqHkj8j4wUtRJQhaMIlBM,3275
18
18
  ultralytics/cfg/datasets/DOTAv1.5.yaml,sha256=VZ_KKFX0H2YvlFVJ8JHcLWYBZ2xiQ6Z-ROSTiKWpS7c,1211
19
19
  ultralytics/cfg/datasets/DOTAv1.yaml,sha256=JrDuYcQ0JU9lJlCA-dCkMNko_jaj6MAVGHjsfjeZ_u0,1181
20
20
  ultralytics/cfg/datasets/GlobalWheat2020.yaml,sha256=dnr_loeYSE6Eo_f7V1yubILsMRBMRm1ozyC5r7uT-iY,2144
21
21
  ultralytics/cfg/datasets/HomeObjects-3K.yaml,sha256=xEtSqEad-rtfGuIrERjjhdISggmPlvaX-315ZzKz50I,934
22
22
  ultralytics/cfg/datasets/ImageNet.yaml,sha256=GvDWypLVG_H3H67Ai8IC1pvK6fwcTtF5FRhzO1OXXDU,42530
23
- ultralytics/cfg/datasets/Objects365.yaml,sha256=vLzbT3xgpLR-bHhrHOiYyzYvDIniRdevgSyPetm8QHk,9354
24
- ultralytics/cfg/datasets/SKU-110K.yaml,sha256=a52le1-JQ2YH6b1WLMUxVz7RkZ36YsmXgWyw0z3q9nQ,2542
25
- ultralytics/cfg/datasets/VOC.yaml,sha256=o09FWAAsr1MH3ftBJ_n-4Tmc3zxnVJL1HqlqKRUYVTQ,3774
26
- ultralytics/cfg/datasets/VisDrone.yaml,sha256=dYAewe84CrGmxAA_z6UnZUAd7peaw5l3ARDcssojADk,3604
23
+ ultralytics/cfg/datasets/Objects365.yaml,sha256=eMQuA8B4ZGp_GsmMNKFP4CziMSVduyuAK1IANkAZaJw,9367
24
+ ultralytics/cfg/datasets/SKU-110K.yaml,sha256=25M1xoJRqw-UEHmeAiyLKCzk0kTLj0FSlwpZ9dRKwIw,2555
25
+ ultralytics/cfg/datasets/VOC.yaml,sha256=NhVLvsmLOwMIteW4DPKxetURP5bTaJvYc7w08-HYAUs,3785
26
+ ultralytics/cfg/datasets/VisDrone.yaml,sha256=RauTGwmGetLjamcPCiBL7FEWwd8mAA1Y4ARlozX6-E8,3613
27
27
  ultralytics/cfg/datasets/african-wildlife.yaml,sha256=SuloMp9WAZBigGC8az-VLACsFhTM76_O29yhTvUqdnU,915
28
28
  ultralytics/cfg/datasets/brain-tumor.yaml,sha256=qrxPO_t9wxbn2kHFwP3vGTzSWj2ELTLelUwYL3_b6nc,800
29
29
  ultralytics/cfg/datasets/carparts-seg.yaml,sha256=A4e9hM1unTY2jjZIXGiKSarF6R-Ad9R99t57OgRJ37w,1253
@@ -47,7 +47,7 @@ ultralytics/cfg/datasets/open-images-v7.yaml,sha256=wK9v3OAGdHORkFdqoBi0hS0fa1b7
47
47
  ultralytics/cfg/datasets/package-seg.yaml,sha256=V4uyTDWWzgft24y9HJWuELKuZ5AndAHXbanxMI6T8GU,849
48
48
  ultralytics/cfg/datasets/signature.yaml,sha256=gBvU3715gVxVAafI_yaYczGX3kfEfA4BttbiMkgOXNk,774
49
49
  ultralytics/cfg/datasets/tiger-pose.yaml,sha256=Y_8htA4--6hmpqHTW-Ix4t9SdaWenSSyl_FUtI2A7n8,926
50
- ultralytics/cfg/datasets/xView.yaml,sha256=NEEGaRTvTGafckJiFD1ltFyMl0b04zOyOFu_J-PN-Ik,5340
50
+ ultralytics/cfg/datasets/xView.yaml,sha256=P347BJlmb7AG7YC29JyyOtNy52QqZ87Sn7gFP8Dx86s,5353
51
51
  ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml,sha256=1Ycp9qMrwpb8rq7cqht3Q-1gMN0R87U35nm2j_isdro,524
52
52
  ultralytics/cfg/models/11/yolo11-cls.yaml,sha256=17l5GdN-Vst4LvafsK2-q6Li9VX9UlUcT5ClCtikweE,1412
53
53
  ultralytics/cfg/models/11/yolo11-obb.yaml,sha256=3M_c06B-y8da4tunHVxQQ-iFUNLKUfofqCZTpnH5FEU,2034
@@ -109,19 +109,19 @@ ultralytics/data/__init__.py,sha256=nAXaL1puCc7z_NjzQNlJnhbVhT9Fla2u7Dsqo7q1dAc,
109
109
  ultralytics/data/annotator.py,sha256=uAgd7K-yudxiwdNqHz0ubfFg5JsfNlae4cgxdvCMyuY,3030
110
110
  ultralytics/data/augment.py,sha256=Ps1s-ug_oXdyAz4Jyur6OmxzRlyzwP3VP-3hDalSxj8,132959
111
111
  ultralytics/data/base.py,sha256=mRcuehK1thNuuzQGL6D1AaZkod71oHRdYTod_zdQZQg,19688
112
- ultralytics/data/build.py,sha256=TfMLSPMbE2hGZVMLl178NTFrihC1-50jNOt1ex9elxw,11480
112
+ ultralytics/data/build.py,sha256=v2dHe52m_cqKnRSWZhEcpGynKMCB-dgw4SyVnfTNAXA,11464
113
113
  ultralytics/data/converter.py,sha256=h-0liMb7OkxoR7P0h_mOUpEu5KUsocH3fVEAz3_-p-I,32096
114
114
  ultralytics/data/dataset.py,sha256=0GyB6PPsUXMxpf88RyvhGcsREDCenS7Xvc8CrMWivco,36759
115
115
  ultralytics/data/loaders.py,sha256=u9sExTGPy1iiqVd_p29zVoEkQ3C36g2rE0FEbYPET0A,31767
116
116
  ultralytics/data/split.py,sha256=F6O73bAbESj70FQZzqkydXQeXgPXGHGiC06b5MkLHjQ,5109
117
117
  ultralytics/data/split_dota.py,sha256=rr-lLpTUVaFZMggV_fUYZdFVIJk_zbbSOpgB_Qp50_M,12893
118
- ultralytics/data/utils.py,sha256=YA0fLAwxgXdEbQnbieEv4wPFhtnmJX1L67LzVbVwVZk,36794
118
+ ultralytics/data/utils.py,sha256=Zt01BBVwpdHBLwkJC_qTUpaokhF_74hmBYQC3d9Ic8w,36675
119
119
  ultralytics/data/scripts/download_weights.sh,sha256=0y8XtZxOru7dVThXDFUXLHBuICgOIqZNUwpyL4Rh6lg,595
120
120
  ultralytics/data/scripts/get_coco.sh,sha256=UuJpJeo3qQpTHVINeOpmP0NYmg8PhEFE3A8J3jKrnPw,1768
121
121
  ultralytics/data/scripts/get_coco128.sh,sha256=qmRQl_hOKrsdHrTrnyQuFIH01oDz3lfaz138OgGfLt8,650
122
122
  ultralytics/data/scripts/get_imagenet.sh,sha256=hr42H16bM47iT27rgS7MpEo-GeOZAYUQXgr0B2cwn48,1705
123
123
  ultralytics/engine/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6DXppv1-QUM,70
124
- ultralytics/engine/exporter.py,sha256=Vr7K8Yf3wyf91ZvDpRosAohwa_W0oe4qW-JvqigCPfk,75190
124
+ ultralytics/engine/exporter.py,sha256=-AUku73LwK0l_Gt71evXQIJg3WpC2jr73S-87vw5T6g,75277
125
125
  ultralytics/engine/model.py,sha256=877u2n0ISz2COOYtEMUqQe0E-HHB4Atb2DuH1XCE98k,53530
126
126
  ultralytics/engine/predictor.py,sha256=iXnUB-tvBHtVpKbB-5EKs1wSREBIerdUxWx39MaFYuk,22485
127
127
  ultralytics/engine/results.py,sha256=QcHcbPVlLBiy_APwABr-T5K65HR8Bl1rRzxawjjP76E,71873
@@ -218,7 +218,7 @@ ultralytics/solutions/object_counter.py,sha256=zD-EYIxu_y7qCFEkv6aqV60oMCZ4q6b_k
218
218
  ultralytics/solutions/object_cropper.py,sha256=lRKtWINAe9GDxau1Xejbjydsqg2hrpGZXPtZwTgvyKQ,3603
219
219
  ultralytics/solutions/parking_management.py,sha256=IfPUn15aelxz6YZNo9WYkVEl5IOVSw8VD0OrpKtExPE,13613
220
220
  ultralytics/solutions/queue_management.py,sha256=gTkILx4dVcsKRZXSCXtelkEjCRiDS5iznb3FnddC61c,4390
221
- ultralytics/solutions/region_counter.py,sha256=Ncd6_qIXmSQXUxCwQkgYc2-nI7KifQYhxPi3pOelZak,5950
221
+ ultralytics/solutions/region_counter.py,sha256=gaBN5piMyIJSk0DBycKxm7HXHOfixA0meITcMxbwHOg,6031
222
222
  ultralytics/solutions/security_alarm.py,sha256=czEaMcy04q-iBkKqT_14d8H20CFB6zcKH_31nBGQnyw,6345
223
223
  ultralytics/solutions/similarity_search.py,sha256=c18TK0qW5AvanXU28nAX4o_WtB1SDAJStUtyLDuEBHQ,9505
224
224
  ultralytics/solutions/solutions.py,sha256=9dTkAx1W-0oaZGwKyysXTxKCYNBEV4kThRjqsQea2VQ,36059
@@ -236,18 +236,18 @@ ultralytics/trackers/utils/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6D
236
236
  ultralytics/trackers/utils/gmc.py,sha256=9IvCf5MhBYY9ppVHykN02_oBWHmE98R8EaYFKaykdV0,14032
237
237
  ultralytics/trackers/utils/kalman_filter.py,sha256=PPmM0lwBMdT_hGojvfLoUsBUFMBBMNRAxKbMcQa3wJ0,21619
238
238
  ultralytics/trackers/utils/matching.py,sha256=uSYtywqi1lE_uNN1FwuBFPyISfDQXHMu8K5KH69nrRI,7160
239
- ultralytics/utils/__init__.py,sha256=X6AtIW402k7OZ8rvgNmP8V3zrtfWfUxCp1S-gabei5s,60074
239
+ ultralytics/utils/__init__.py,sha256=jI8xbKM4OrRFvYbT7j1qAlRmvKTnVSHyHzY-On3yAjI,56982
240
240
  ultralytics/utils/autobatch.py,sha256=33m8YgggLIhltDqMXZ5OE-FGs2QiHrl2-LfgY1mI4cw,5119
241
- ultralytics/utils/autodevice.py,sha256=AvgXFt8c1Cg4icKh0Hbhhz8UmVQ2Wjyfdfkeb2C8zck,8855
241
+ ultralytics/utils/autodevice.py,sha256=1wwjkO2tmyR5IAYa6t8G9QJgGrm00niPY4bTbTRH0Uk,8861
242
242
  ultralytics/utils/benchmarks.py,sha256=btsi_B0mfLPfhE8GrsBpi79vl7SRam0YYngNFAsY8Ak,31035
243
243
  ultralytics/utils/checks.py,sha256=q64U5wKyejD-2W2fCPqJ0Oiaa4_4vq2pVxV9wp6lMz4,34707
244
244
  ultralytics/utils/dist.py,sha256=A9lDGtGefTjSVvVS38w86GOdbtLzNBDZuDGK0MT4PRI,4170
245
- ultralytics/utils/downloads.py,sha256=A7r4LpWUojGkam9-VQ3Ylu-Cn1lAUGKyJE6VzwQbp7M,22016
245
+ ultralytics/utils/downloads.py,sha256=5p9X5XN3I4RzZYGv8wP8Iehm3fDR4KXtN7KgGsJ0iAg,22621
246
246
  ultralytics/utils/errors.py,sha256=XT9Ru7ivoBgofK6PlnyigGoa7Fmf5nEhyHtnD-8TRXI,1584
247
247
  ultralytics/utils/export.py,sha256=LK-wlTlyb_zIKtSvOmfmvR70RcUU9Ct9UBDt5wn9_rY,9880
248
248
  ultralytics/utils/files.py,sha256=ZCbLGleiF0f-PqYfaxMFAWop88w7U1hpreHXl8b2ko0,8238
249
249
  ultralytics/utils/instance.py,sha256=dC83rHvQXciAED3rOiScFs3BOX9OI06Ey1mj9sjUKvs,19070
250
- ultralytics/utils/logger.py,sha256=ajrogDL8_-IFoFuQBrg97g716cl9es4bJsloIJl533c,15164
250
+ ultralytics/utils/logger.py,sha256=KDHLdpBe3su3OkMpLSUgDk3-cXMkRgH3oK0hhxsxxvM,15137
251
251
  ultralytics/utils/loss.py,sha256=fbOWc3Iu0QOJiWbi-mXWA9-1otTYlehtmUsI7os7ydM,39799
252
252
  ultralytics/utils/metrics.py,sha256=Q0cD4J1_7WRElv_En6YUM94l4SjE7XTF9LdZUMvrGys,68853
253
253
  ultralytics/utils/ops.py,sha256=8d60fbpntrexK3gPoLUS6mWAYGrtrQaQCOYyRJsCjuI,34521
@@ -255,6 +255,7 @@ ultralytics/utils/patches.py,sha256=PPWiKzwGbCvuawLzDKVR8tWOQAlZbJBi8g_-A6eTCYA,
255
255
  ultralytics/utils/plotting.py,sha256=4TG_J8rz9VVPrOXbdjRHPJZVgJrFYVmEYE0BcVDdolc,47745
256
256
  ultralytics/utils/tal.py,sha256=aXawOnhn8ni65tJWIW-PYqWr_TRvltbHBjrTo7o6lDQ,20924
257
257
  ultralytics/utils/torch_utils.py,sha256=D76Pvmw5OKh-vd4aJkOMO0dSLbM5WzGr7Hmds54hPEk,39233
258
+ ultralytics/utils/tqdm.py,sha256=cJSzlv6NP72kN7_J0PETA3h4bwGh5a_YHA2gdmZqL8U,16535
258
259
  ultralytics/utils/triton.py,sha256=M7qe4RztiADBJQEWQKaIQsp94ERFJ_8_DUHDR6TXEOM,5410
259
260
  ultralytics/utils/tuner.py,sha256=bHr09Fz-0-t0ei55gX5wJh-obyiAQoicP7HUVM2I8qA,6826
260
261
  ultralytics/utils/callbacks/__init__.py,sha256=hzL63Rce6VkZhP4Lcim9LKjadixaQG86nKqPhk7IkS0,242
@@ -269,8 +270,8 @@ ultralytics/utils/callbacks/platform.py,sha256=gdbEuedXEs1VjdU0IiedjPFwttZJUiI0d
269
270
  ultralytics/utils/callbacks/raytune.py,sha256=S6Bq16oQDQ8BQgnZzA0zJHGN_BBr8iAM_WtGoLiEcwg,1283
270
271
  ultralytics/utils/callbacks/tensorboard.py,sha256=MDPBW7aDes-66OE6YqKXXvqA_EocjzEMHWGM-8z9vUQ,5281
271
272
  ultralytics/utils/callbacks/wb.py,sha256=Tm_-aRr2CN32MJkY9tylpMBJkb007-MSRNSQ7rDJ5QU,7521
272
- dgenerate_ultralytics_headless-8.3.185.dist-info/METADATA,sha256=XEpiGcn2TlOD_lJzNDs7YuMo6pTdE1PHfG1C3Z7QR2Y,38727
273
- dgenerate_ultralytics_headless-8.3.185.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
274
- dgenerate_ultralytics_headless-8.3.185.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
275
- dgenerate_ultralytics_headless-8.3.185.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
276
- dgenerate_ultralytics_headless-8.3.185.dist-info/RECORD,,
273
+ dgenerate_ultralytics_headless-8.3.186.dist-info/METADATA,sha256=tc5kxyFm0pFjeLSyNe-BkQrg_2NM5SYxzhi2SLsMbXs,38723
274
+ dgenerate_ultralytics_headless-8.3.186.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
275
+ dgenerate_ultralytics_headless-8.3.186.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
276
+ dgenerate_ultralytics_headless-8.3.186.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
277
+ dgenerate_ultralytics_headless-8.3.186.dist-info/RECORD,,
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
- __version__ = "8.3.185"
3
+ __version__ = "8.3.186"
4
4
 
5
5
  import os
6
6
 
@@ -30,14 +30,14 @@ download: |
30
30
  import json
31
31
  from pathlib import Path
32
32
 
33
- from tqdm import tqdm
33
+ from ultralytics.utils import TQDM
34
34
  from ultralytics.utils.downloads import download
35
35
 
36
36
  def argoverse2yolo(set):
37
37
  """Convert Argoverse dataset annotations to YOLO format for object detection tasks."""
38
38
  labels = {}
39
39
  a = json.load(open(set, "rb"))
40
- for annot in tqdm(a["annotations"], desc=f"Converting {set} to YOLOv5 format..."):
40
+ for annot in TQDM(a["annotations"], desc=f"Converting {set} to YOLOv5 format..."):
41
41
  img_id = annot["image_id"]
42
42
  img_name = a["images"][img_id]["name"]
43
43
  img_label_name = f"{img_name[:-3]}txt"
@@ -387,8 +387,8 @@ download: |
387
387
  from pathlib import Path
388
388
 
389
389
  import numpy as np
390
- from tqdm import tqdm
391
390
 
391
+ from ultralytics.utils import TQDM
392
392
  from ultralytics.utils.checks import check_requirements
393
393
  from ultralytics.utils.downloads import download
394
394
  from ultralytics.utils.ops import xyxy2xywhn
@@ -419,7 +419,7 @@ download: |
419
419
  download([f"{url}images/v2/patch{i}.tar.gz" for i in range(16, patches)], dir=images, curl=True, threads=8)
420
420
 
421
421
  # Move
422
- for f in tqdm(images.rglob("*.jpg"), desc=f"Moving {split} images"):
422
+ for f in TQDM(images.rglob("*.jpg"), desc=f"Moving {split} images"):
423
423
  f.rename(images / f.name) # move to /images/{split}
424
424
 
425
425
  # Labels
@@ -428,7 +428,7 @@ download: |
428
428
  for cid, cat in enumerate(names):
429
429
  catIds = coco.getCatIds(catNms=[cat])
430
430
  imgIds = coco.getImgIds(catIds=catIds)
431
- for im in tqdm(coco.loadImgs(imgIds), desc=f"Class {cid + 1}/{len(names)} {cat}"):
431
+ for im in TQDM(coco.loadImgs(imgIds), desc=f"Class {cid + 1}/{len(names)} {cat}"):
432
432
  width, height = im["width"], im["height"]
433
433
  path = Path(im["file_name"]) # image filename
434
434
  try:
@@ -25,8 +25,8 @@ download: |
25
25
 
26
26
  import numpy as np
27
27
  import pandas as pd
28
- from tqdm import tqdm
29
28
 
29
+ from ultralytics.utils import TQDM
30
30
  from ultralytics.utils.downloads import download
31
31
  from ultralytics.utils.ops import xyxy2xywh
32
32
 
@@ -49,7 +49,7 @@ download: |
49
49
  images, unique_images = x[:, 0], np.unique(x[:, 0])
50
50
  with open((dir / d).with_suffix(".txt").__str__().replace("annotations_", ""), "w", encoding="utf-8") as f:
51
51
  f.writelines(f"./images/{s}\n" for s in unique_images)
52
- for im in tqdm(unique_images, desc=f"Converting {dir / d}"):
52
+ for im in TQDM(unique_images, desc=f"Converting {dir / d}"):
53
53
  cls = 0 # single-class dataset
54
54
  with open((dir / "labels" / im).with_suffix(".txt"), "a", encoding="utf-8") as f:
55
55
  for r in x[images == im]:
@@ -48,10 +48,8 @@ download: |
48
48
  import xml.etree.ElementTree as ET
49
49
  from pathlib import Path
50
50
 
51
- from tqdm import tqdm
52
-
53
51
  from ultralytics.utils.downloads import download
54
-
52
+ from ultralytics.utils import TQDM
55
53
 
56
54
  def convert_label(path, lb_path, year, image_id):
57
55
  """Converts XML annotations from VOC format to YOLO format by extracting bounding boxes and class IDs."""
@@ -99,7 +97,7 @@ download: |
99
97
 
100
98
  with open(path / f"VOC{year}/ImageSets/Main/{image_set}.txt") as f:
101
99
  image_ids = f.read().strip().split()
102
- for id in tqdm(image_ids, desc=f"{image_set}{year}"):
100
+ for id in TQDM(image_ids, desc=f"{image_set}{year}"):
103
101
  f = path / f"VOC{year}/JPEGImages/{id}.jpg" # old img path
104
102
  lb_path = (lbs_path / f.name).with_suffix(".txt") # new label path
105
103
  f.rename(imgs_path / f.name) # move image
@@ -34,12 +34,12 @@ download: |
34
34
  import shutil
35
35
 
36
36
  from ultralytics.utils.downloads import download
37
+ from ultralytics.utils import TQDM
37
38
 
38
39
 
39
40
  def visdrone2yolo(dir, split, source_name=None):
40
41
  """Convert VisDrone annotations to YOLO format with images/{split} and labels/{split} structure."""
41
42
  from PIL import Image
42
- from tqdm import tqdm
43
43
 
44
44
  source_dir = dir / (source_name or f"VisDrone2019-DET-{split}")
45
45
  images_dir = dir / "images" / split
@@ -52,7 +52,7 @@ download: |
52
52
  for img in source_images_dir.glob("*.jpg"):
53
53
  img.rename(images_dir / img.name)
54
54
 
55
- for f in tqdm((source_dir / "annotations").glob("*.txt"), desc=f"Converting {split}"):
55
+ for f in TQDM((source_dir / "annotations").glob("*.txt"), desc=f"Converting {split}"):
56
56
  img_size = Image.open(images_dir / f.with_suffix(".jpg").name).size
57
57
  dw, dh = 1.0 / img_size[0], 1.0 / img_size[1]
58
58
  lines = []
@@ -85,8 +85,8 @@ download: |
85
85
 
86
86
  import numpy as np
87
87
  from PIL import Image
88
- from tqdm import tqdm
89
88
 
89
+ from ultralytics.utils import TQDM
90
90
  from ultralytics.data.utils import autosplit
91
91
  from ultralytics.utils.ops import xyxy2xywhn
92
92
 
@@ -110,7 +110,7 @@ download: |
110
110
  47, 48, 49, -1, 50, 51, -1, 52, -1, -1, -1, 53, 54, -1, 55, -1, -1, 56, -1, 57, -1, 58, 59]
111
111
 
112
112
  shapes = {}
113
- for feature in tqdm(data["features"], desc=f"Converting {fname}"):
113
+ for feature in TQDM(data["features"], desc=f"Converting {fname}"):
114
114
  p = feature["properties"]
115
115
  if p["bounds_imcoords"]:
116
116
  id = p["image_id"]
ultralytics/data/build.py CHANGED
@@ -22,7 +22,7 @@ from ultralytics.data.loaders import (
22
22
  SourceTypes,
23
23
  autocast_list,
24
24
  )
25
- from ultralytics.data.utils import IMG_FORMATS, PIN_MEMORY, VID_FORMATS
25
+ from ultralytics.data.utils import IMG_FORMATS, VID_FORMATS
26
26
  from ultralytics.utils import RANK, colorstr
27
27
  from ultralytics.utils.checks import check_file
28
28
 
@@ -206,7 +206,7 @@ def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, ra
206
206
  shuffle=shuffle and sampler is None,
207
207
  num_workers=nw,
208
208
  sampler=sampler,
209
- pin_memory=PIN_MEMORY,
209
+ pin_memory=nd > 0,
210
210
  collate_fn=getattr(dataset, "collate_fn", None),
211
211
  worker_init_fn=seed_worker,
212
212
  generator=generator,
ultralytics/data/utils.py CHANGED
@@ -19,7 +19,6 @@ from ultralytics.nn.autobackend import check_class_names
19
19
  from ultralytics.utils import (
20
20
  DATASETS_DIR,
21
21
  LOGGER,
22
- MACOS,
23
22
  NUM_THREADS,
24
23
  ROOT,
25
24
  SETTINGS_FILE,
@@ -37,7 +36,6 @@ from ultralytics.utils.ops import segments2boxes
37
36
  HELP_URL = "See https://docs.ultralytics.com/datasets for dataset formatting guidance."
38
37
  IMG_FORMATS = {"bmp", "dng", "jpeg", "jpg", "mpo", "png", "tif", "tiff", "webp", "pfm", "heic"} # image suffixes
39
38
  VID_FORMATS = {"asf", "avi", "gif", "m4v", "mkv", "mov", "mp4", "mpeg", "mpg", "ts", "wmv", "webm"} # video suffixes
40
- PIN_MEMORY = str(os.getenv("PIN_MEMORY", not MACOS)).lower() == "true" # global pin_memory for dataloaders
41
39
  FORMATS_HELP_MSG = f"Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}"
42
40
 
43
41
 
@@ -1479,7 +1479,10 @@ class IOSDetectModel(torch.nn.Module):
1479
1479
  if w == h:
1480
1480
  self.normalize = 1.0 / w # scalar
1481
1481
  else:
1482
- self.normalize = torch.tensor([1.0 / w, 1.0 / h, 1.0 / w, 1.0 / h]) # broadcast (slower, smaller)
1482
+ self.normalize = torch.tensor(
1483
+ [1.0 / w, 1.0 / h, 1.0 / w, 1.0 / h], # broadcast (slower, smaller)
1484
+ device=next(model.parameters()).device,
1485
+ )
1483
1486
 
1484
1487
  def forward(self, x):
1485
1488
  """Normalize predictions of object detection model with input size-dependent factors."""
@@ -115,8 +115,9 @@ class RegionCounter(BaseSolution):
115
115
 
116
116
  # Display region counts
117
117
  for region in self.counting_regions:
118
- x1, y1, x2, y2 = map(int, region["polygon"].bounds)
119
- pts = [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
118
+ poly = region["polygon"]
119
+ pts = list(map(tuple, np.array(poly.exterior.coords, dtype=np.int32)))
120
+ (x1, y1), (x2, y2) = [(int(poly.centroid.x), int(poly.centroid.y))] * 2
120
121
  annotator.draw_region(pts, region["region_color"], self.line_width * 2)
121
122
  annotator.adaptive_label(
122
123
  [x1, y1, x2, y2],
@@ -12,7 +12,6 @@ import subprocess
12
12
  import sys
13
13
  import threading
14
14
  import time
15
- import warnings
16
15
  from pathlib import Path
17
16
  from threading import Lock
18
17
  from types import SimpleNamespace
@@ -22,10 +21,10 @@ from urllib.parse import unquote
22
21
  import cv2
23
22
  import numpy as np
24
23
  import torch
25
- import tqdm
26
24
 
27
25
  from ultralytics import __version__
28
26
  from ultralytics.utils.patches import imread, imshow, imwrite, torch_save # for patches
27
+ from ultralytics.utils.tqdm import TQDM # noqa
29
28
 
30
29
  # PyTorch Multi-GPU DDP Constants
31
30
  RANK = int(os.getenv("RANK", -1))
@@ -41,7 +40,6 @@ DEFAULT_CFG_PATH = ROOT / "cfg/default.yaml"
41
40
  NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLO multiprocessing threads
42
41
  AUTOINSTALL = str(os.getenv("YOLO_AUTOINSTALL", True)).lower() == "true" # global auto-install mode
43
42
  VERBOSE = str(os.getenv("YOLO_VERBOSE", True)).lower() == "true" # global verbose mode
44
- TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" if VERBOSE else None # tqdm bar format
45
43
  LOGGING_NAME = "ultralytics"
46
44
  MACOS, LINUX, WINDOWS = (platform.system() == x for x in ["Darwin", "Linux", "Windows"]) # environment booleans
47
45
  MACOS_VERSION = platform.mac_ver()[0] if MACOS else None
@@ -130,73 +128,6 @@ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" # suppress verbose TF compiler warning
130
128
  os.environ["TORCH_CPP_LOG_LEVEL"] = "ERROR" # suppress "NNPACK.cpp could not initialize NNPACK" warnings
131
129
  os.environ["KINETO_LOG_LEVEL"] = "5" # suppress verbose PyTorch profiler output when computing FLOPs
132
130
 
133
- if TQDM_RICH := str(os.getenv("YOLO_TQDM_RICH", False)).lower() == "true":
134
- from rich.console import Console
135
- from rich.progress import BarColumn
136
- from tqdm import rich
137
-
138
- # Patch Rich Console width=200 and BarColumn bar_width=10 to solve width=80 missing bars bug
139
- _console_init = Console.__init__
140
- _bar_init = BarColumn.__init__
141
- Console.__init__ = lambda self, *a, **k: _console_init(self, *a, **{**k, "width": 200})
142
- BarColumn.__init__ = lambda self, bar_width=None, *a, **k: _bar_init(self, 10, *a, **k)
143
-
144
-
145
- class TQDM(rich.tqdm if TQDM_RICH else tqdm.tqdm):
146
- """
147
- A custom TQDM progress bar class that extends the original tqdm functionality.
148
-
149
- This class modifies the behavior of the original tqdm progress bar based on global settings and provides
150
- additional customization options for Ultralytics projects. The progress bar is automatically disabled when
151
- VERBOSE is False or when explicitly disabled.
152
-
153
- Attributes:
154
- disable (bool): Whether to disable the progress bar. Determined by the global VERBOSE setting and
155
- any passed 'disable' argument.
156
- bar_format (str): The format string for the progress bar. Uses the global TQDM_BAR_FORMAT if not
157
- explicitly set.
158
-
159
- Methods:
160
- __init__: Initialize the TQDM object with custom settings.
161
- __iter__: Return self as iterator to satisfy Iterable interface.
162
-
163
- Examples:
164
- >>> from ultralytics.utils import TQDM
165
- >>> for i in TQDM(range(100)):
166
- ... # Your processing code here
167
- ... pass
168
- """
169
-
170
- def __init__(self, *args, **kwargs):
171
- """
172
- Initialize a custom TQDM progress bar with Ultralytics-specific settings.
173
-
174
- Args:
175
- *args (Any): Variable length argument list to be passed to the original tqdm constructor.
176
- **kwargs (Any): Arbitrary keyword arguments to be passed to the original tqdm constructor.
177
-
178
- Notes:
179
- - The progress bar is disabled if VERBOSE is False or if 'disable' is explicitly set to True in kwargs.
180
- - The default bar format is set to TQDM_BAR_FORMAT unless overridden in kwargs.
181
- - In GitHub Actions, progress bars only update at completion to keep CI logs clean.
182
-
183
- Examples:
184
- >>> from ultralytics.utils import TQDM
185
- >>> for i in TQDM(range(100)):
186
- ... # Your code here
187
- ... pass
188
- """
189
- warnings.filterwarnings("ignore", category=tqdm.TqdmExperimentalWarning) # suppress tqdm.rich warning
190
- if is_github_action_running():
191
- kwargs["mininterval"] = 60 # only update every 60 seconds
192
- kwargs["disable"] = not VERBOSE or kwargs.get("disable", False) or LOGGER.getEffectiveLevel() > 20
193
- kwargs.setdefault("bar_format", TQDM_BAR_FORMAT) # override default value if passed
194
- super().__init__(*args, **kwargs)
195
-
196
- def __iter__(self):
197
- """Return self as iterator to satisfy Iterable interface."""
198
- return super().__iter__()
199
-
200
131
 
201
132
  class DataExportMixin:
202
133
  """
@@ -49,7 +49,7 @@ class GPUInfo:
49
49
  self.gpu_stats: List[Dict[str, Any]] = []
50
50
 
51
51
  try:
52
- check_requirements("pynvml>=12.0.0")
52
+ check_requirements("nvidia-ml-py>=12.0.0")
53
53
  self.pynvml = __import__("pynvml")
54
54
  self.pynvml.nvmlInit()
55
55
  self.nvml_available = True
@@ -118,11 +118,11 @@ def zip_directory(directory, compress: bool = True, exclude=(".DS_Store", "__MAC
118
118
  raise FileNotFoundError(f"Directory '{directory}' does not exist.")
119
119
 
120
120
  # Zip with progress bar
121
- files_to_zip = [f for f in directory.rglob("*") if f.is_file() and all(x not in f.name for x in exclude)]
121
+ files = [f for f in directory.rglob("*") if f.is_file() and all(x not in f.name for x in exclude)] # files to zip
122
122
  zip_file = directory.with_suffix(".zip")
123
123
  compression = ZIP_DEFLATED if compress else ZIP_STORED
124
124
  with ZipFile(zip_file, "w", compression) as f:
125
- for file in TQDM(files_to_zip, desc=f"Zipping {directory} to {zip_file}...", unit="file", disable=not progress):
125
+ for file in TQDM(files, desc=f"Zipping {directory} to {zip_file}...", unit="files", disable=not progress):
126
126
  f.write(file, file.relative_to(directory))
127
127
 
128
128
  return zip_file # return path to zip file
@@ -187,7 +187,7 @@ def unzip_file(
187
187
  LOGGER.warning(f"Skipping {file} unzip as destination directory {path} is not empty.")
188
188
  return path
189
189
 
190
- for f in TQDM(files, desc=f"Unzipping {file} to {Path(path).resolve()}...", unit="file", disable=not progress):
190
+ for f in TQDM(files, desc=f"Unzipping {file} to {Path(path).resolve()}...", unit="files", disable=not progress):
191
191
  # Ensure the file is within the extract_path to avoid path traversal security vulnerability
192
192
  if ".." in Path(f).parts:
193
193
  LOGGER.warning(f"Potentially insecure file path: {f}, skipping extraction.")
@@ -295,7 +295,8 @@ def safe_download(
295
295
  progress: bool = True,
296
296
  ):
297
297
  """
298
- Download files from a URL with options for retrying, unzipping, and deleting the downloaded file.
298
+ Download files from a URL with options for retrying, unzipping, and deleting the downloaded file. Enhanced with
299
+ robust partial download detection using Content-Length validation.
299
300
 
300
301
  Args:
301
302
  url (str): The URL of the file to be downloaded.
@@ -342,24 +343,33 @@ def safe_download(
342
343
  s = "sS" * (not progress) # silent
343
344
  r = subprocess.run(["curl", "-#", f"-{s}L", url, "-o", f, "--retry", "3", "-C", "-"]).returncode
344
345
  assert r == 0, f"Curl return value {r}"
346
+ expected_size = None # Can't get size with curl
345
347
  else: # urllib download
346
- # torch.hub.download_url_to_file(url, f, progress=progress) # do not use as progress tqdm differs
347
- with request.urlopen(url) as response, TQDM(
348
- total=int(response.getheader("Content-Length", 0)),
349
- desc=desc,
350
- disable=not progress,
351
- unit="B",
352
- unit_scale=True,
353
- unit_divisor=1024,
354
- ) as pbar:
355
- with open(f, "wb") as f_opened:
356
- for data in response:
357
- f_opened.write(data)
358
- pbar.update(len(data))
348
+ with request.urlopen(url) as response:
349
+ expected_size = int(response.getheader("Content-Length", 0))
350
+ with TQDM(
351
+ total=expected_size,
352
+ desc=desc,
353
+ disable=not progress,
354
+ unit="B",
355
+ unit_scale=True,
356
+ unit_divisor=1024,
357
+ ) as pbar:
358
+ with open(f, "wb") as f_opened:
359
+ for data in response:
360
+ f_opened.write(data)
361
+ pbar.update(len(data))
359
362
 
360
363
  if f.exists():
361
- if f.stat().st_size > min_bytes:
362
- break # success
364
+ file_size = f.stat().st_size
365
+ if file_size > min_bytes:
366
+ # Check if download is complete (only if we have expected_size)
367
+ if expected_size and file_size != expected_size:
368
+ LOGGER.warning(
369
+ f"Partial download: {file_size}/{expected_size} bytes ({file_size / expected_size * 100:.1f}%)"
370
+ )
371
+ else:
372
+ break # success
363
373
  f.unlink() # remove partial downloads
364
374
  except Exception as e:
365
375
  if i == 0 and not is_online():
@@ -77,7 +77,7 @@ class ConsoleLogger:
77
77
  # State tracking
78
78
  self.last_line = ""
79
79
  self.last_time = 0.0
80
- self.last_progress_line = "" # Track 100% progress lines separately
80
+ self.last_progress_line = "" # Track last progress line for deduplication
81
81
  self.last_was_progress = False # Track if last line was a progress bar
82
82
 
83
83
  def start_capture(self):
@@ -127,15 +127,14 @@ class ConsoleLogger:
127
127
  for line in lines:
128
128
  line = line.rstrip()
129
129
 
130
- # Handle progress bars - only show 100% completions
131
- if ("it/s" in line and ("%|" in line or "━" in line)) or (
132
- "100%" in line and ("it/s" in line or "[" in line)
133
- ):
134
- if "100%" not in line:
135
- continue
136
- # Dedupe 100% lines by core content (strip timing)
137
- progress_core = line.split("[")[0].split("]")[0].strip()
138
- if progress_core == self.last_progress_line:
130
+ # Skip lines with only thin progress bars (partial progress)
131
+ if "" in line: # Has thin lines but no thick lines
132
+ continue
133
+
134
+ # Deduplicate completed progress bars only if they match the previous progress line
135
+ if " ━━" in line:
136
+ progress_core = line.split(" ━━")[0].strip()
137
+ if progress_core == self.last_progress_line and self.last_was_progress:
139
138
  continue
140
139
  self.last_progress_line = progress_core
141
140
  self.last_was_progress = True
@@ -271,7 +270,7 @@ class SystemLogger:
271
270
  """Initialize NVIDIA GPU monitoring with pynvml."""
272
271
  try:
273
272
  assert not MACOS
274
- check_requirements("pynvml>=12.0.0")
273
+ check_requirements("nvidia-ml-py>=12.0.0")
275
274
  self.pynvml = __import__("pynvml")
276
275
  self.pynvml.nvmlInit()
277
276
  return True
@@ -0,0 +1,462 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+ import time
8
+ from functools import lru_cache
9
+ from typing import IO, Any
10
+
11
+
12
+ @lru_cache(maxsize=1)
13
+ def is_noninteractive_console():
14
+ """Check for known non-interactive console environments."""
15
+ return "GITHUB_ACTIONS" in os.environ or "RUNPOD_POD_ID" in os.environ
16
+
17
+
18
+ class TQDM:
19
+ """
20
+ Lightweight zero-dependency progress bar for Ultralytics.
21
+
22
+ Provides clean, rich-style progress bars suitable for various environments including Weights & Biases,
23
+ console outputs, and other logging systems. Features zero external dependencies, clean single-line output,
24
+ rich-style progress bars with Unicode block characters, context manager support, iterator protocol support,
25
+ and dynamic description updates.
26
+
27
+ Attributes:
28
+ iterable (object): Iterable to wrap with progress bar.
29
+ desc (str): Prefix description for the progress bar.
30
+ total (int): Expected number of iterations.
31
+ disable (bool): Whether to disable the progress bar.
32
+ unit (str): String for units of iteration.
33
+ unit_scale (bool): Auto-scale units flag.
34
+ unit_divisor (int): Divisor for unit scaling.
35
+ leave (bool): Whether to leave the progress bar after completion.
36
+ mininterval (float): Minimum time interval between updates.
37
+ initial (int): Initial counter value.
38
+ n (int): Current iteration count.
39
+ closed (bool): Whether the progress bar is closed.
40
+ bar_format (str): Custom bar format string.
41
+ file (object): Output file stream.
42
+
43
+ Methods:
44
+ update: Update progress by n steps.
45
+ set_description: Set or update the description.
46
+ set_postfix: Set postfix for the progress bar.
47
+ close: Close the progress bar and clean up.
48
+ refresh: Refresh the progress bar display.
49
+ clear: Clear the progress bar from display.
50
+ write: Write a message without breaking the progress bar.
51
+
52
+ Examples:
53
+ Basic usage with iterator:
54
+ >>> for i in TQDM(range(100)):
55
+ ... time.sleep(0.01)
56
+
57
+ With custom description:
58
+ >>> pbar = TQDM(range(100), desc="Processing")
59
+ >>> for i in pbar:
60
+ ... pbar.set_description(f"Processing item {i}")
61
+
62
+ Context manager usage:
63
+ >>> with TQDM(total=100, unit="B", unit_scale=True) as pbar:
64
+ ... for i in range(100):
65
+ ... pbar.update(1)
66
+
67
+ Manual updates:
68
+ >>> pbar = TQDM(total=100, desc="Training")
69
+ >>> for epoch in range(100):
70
+ ... # Do work
71
+ ... pbar.update(1)
72
+ >>> pbar.close()
73
+ """
74
+
75
+ # Constants
76
+ MIN_RATE_CALC_INTERVAL = 0.01 # Minimum time interval for rate calculation
77
+ RATE_SMOOTHING_FACTOR = 0.3 # Factor for exponential smoothing of rates
78
+ MAX_SMOOTHED_RATE = 1000000 # Maximum rate to apply smoothing to
79
+ NONINTERACTIVE_MIN_INTERVAL = 60.0 # Minimum interval for non-interactive environments
80
+
81
+ def __init__(
82
+ self,
83
+ iterable: Any = None,
84
+ desc: str | None = None,
85
+ total: int | None = None,
86
+ leave: bool = True,
87
+ file: IO[str] | None = None,
88
+ mininterval: float = 0.1,
89
+ disable: bool | None = None,
90
+ unit: str = "it",
91
+ unit_scale: bool = False,
92
+ unit_divisor: int = 1000,
93
+ bar_format: str | None = None,
94
+ initial: int = 0,
95
+ **kwargs, # Accept unused args for compatibility
96
+ ) -> None:
97
+ """
98
+ Initialize the TQDM progress bar with specified configuration options.
99
+
100
+ Args:
101
+ iterable (object, optional): Iterable to wrap with progress bar.
102
+ desc (str, optional): Prefix description for the progress bar.
103
+ total (int, optional): Expected number of iterations.
104
+ leave (bool, optional): Whether to leave the progress bar after completion.
105
+ file (object, optional): Output file stream for progress display.
106
+ mininterval (float, optional): Minimum time interval between updates (default 0.1s, 60s in GitHub Actions).
107
+ disable (bool, optional): Whether to disable the progress bar. Auto-detected if None.
108
+ unit (str, optional): String for units of iteration (default "it" for items).
109
+ unit_scale (bool, optional): Auto-scale units for bytes/data units.
110
+ unit_divisor (int, optional): Divisor for unit scaling (default 1000).
111
+ bar_format (str, optional): Custom bar format string.
112
+ initial (int, optional): Initial counter value.
113
+ **kwargs (Any): Additional keyword arguments for compatibility (ignored).
114
+
115
+ Examples:
116
+ >>> pbar = TQDM(range(100), desc="Processing")
117
+ >>> with TQDM(total=1000, unit="B", unit_scale=True) as pbar:
118
+ ... pbar.update(1024) # Updates by 1KB
119
+ """
120
+ # Disable if not verbose
121
+ if disable is None:
122
+ try:
123
+ from ultralytics.utils import LOGGER, VERBOSE
124
+
125
+ disable = not VERBOSE or LOGGER.getEffectiveLevel() > 20
126
+ except ImportError:
127
+ disable = False
128
+
129
+ self.iterable = iterable
130
+ self.desc = desc or ""
131
+ self.total = total if total is not None else (len(iterable) if hasattr(iterable, "__len__") else None)
132
+ self.disable = disable
133
+ self.unit = unit
134
+ self.unit_scale = unit_scale
135
+ self.unit_divisor = unit_divisor
136
+ self.leave = leave
137
+ self.noninteractive = is_noninteractive_console()
138
+ self.mininterval = max(mininterval, self.NONINTERACTIVE_MIN_INTERVAL) if self.noninteractive else mininterval
139
+ self.initial = initial
140
+
141
+ # Set bar format based on whether we have a total
142
+ if self.total is not None:
143
+ self.bar_format = bar_format or "{desc}: {percentage:3.0f}% {bar} {n_fmt}/{total_fmt} {rate_fmt} {elapsed}"
144
+ else:
145
+ self.bar_format = bar_format or "{desc}: {bar} {n_fmt} {rate_fmt} {elapsed}"
146
+
147
+ self.file = file or sys.stdout
148
+
149
+ # Internal state
150
+ self.n = self.initial
151
+ self.last_print_n = self.initial
152
+ self.last_print_t = time.time()
153
+ self.start_t = time.time()
154
+ self.last_rate = 0
155
+ self.closed = False
156
+
157
+ # Display initial bar if we have total and not disabled
158
+ if not self.disable and self.total is not None and not self.noninteractive:
159
+ self._display()
160
+
161
+ def _format_rate(self, rate):
162
+ """Format rate with proper units and reasonable precision."""
163
+ if rate <= 0:
164
+ return ""
165
+
166
+ # For bytes with scaling, use binary units
167
+ if self.unit in ("B", "bytes") and self.unit_scale:
168
+ for threshold, unit in [(1024**3, "GB/s"), (1024**2, "MB/s"), (1024, "KB/s")]:
169
+ if rate >= threshold:
170
+ return f"{rate / threshold:.1f}{unit}"
171
+ return f"{rate:.1f}B/s"
172
+
173
+ # For other scalable units, use decimal units
174
+ if self.unit_scale and self.unit in ("it", "items", ""):
175
+ for threshold, prefix in [(1000000, "M"), (1000, "K")]:
176
+ if rate >= threshold:
177
+ return f"{rate / threshold:.1f}{prefix}{self.unit}/s"
178
+
179
+ # Default formatting
180
+ precision = ".1f" if rate >= 1 else ".2f"
181
+ return f"{rate:{precision}}{self.unit}/s"
182
+
183
+ def _format_num(self, num):
184
+ """Format number with optional unit scaling."""
185
+ if not self.unit_scale or self.unit not in ("B", "bytes"):
186
+ return str(num)
187
+
188
+ for unit in ["", "K", "M", "G", "T"]:
189
+ if abs(num) < self.unit_divisor:
190
+ return f"{num:3.1f}{unit}B" if unit else f"{num:.0f}B"
191
+ num /= self.unit_divisor
192
+ return f"{num:.1f}PB"
193
+
194
+ def _format_time(self, seconds):
195
+ """Format time duration."""
196
+ if seconds < 60:
197
+ return f"{seconds:.1f}s"
198
+ elif seconds < 3600:
199
+ return f"{int(seconds // 60)}:{seconds % 60:02.0f}"
200
+ else:
201
+ h, m = int(seconds // 3600), int((seconds % 3600) // 60)
202
+ return f"{h}:{m:02d}:{seconds % 60:02.0f}"
203
+
204
+ def _generate_bar(self, width=12):
205
+ """Generate progress bar."""
206
+ if self.total is None:
207
+ return "━" * width if self.closed else "─" * width
208
+
209
+ frac = min(1.0, self.n / self.total)
210
+ filled = int(frac * width)
211
+ bar = "━" * filled + "─" * (width - filled)
212
+ if filled < width and frac * width - filled > 0.5:
213
+ bar = bar[:filled] + "╸" + bar[filled + 1 :]
214
+ return bar
215
+
216
+ def _should_update(self, dt, dn):
217
+ """Check if display should update."""
218
+ if self.noninteractive:
219
+ return False
220
+
221
+ if self.total is not None and self.n >= self.total:
222
+ return True
223
+
224
+ return dt >= self.mininterval
225
+
226
+ def _display(self, final=False):
227
+ """Display progress bar."""
228
+ if self.disable or (self.closed and not final):
229
+ return
230
+
231
+ current_time = time.time()
232
+ dt = current_time - self.last_print_t
233
+ dn = self.n - self.last_print_n
234
+
235
+ if not final and not self._should_update(dt, dn):
236
+ return
237
+
238
+ # Calculate rate (avoid crazy numbers)
239
+ if dt > self.MIN_RATE_CALC_INTERVAL: # Only calculate rate if enough time has passed
240
+ rate = dn / dt
241
+ # Smooth rate for reasonable values, use raw rate for very high values
242
+ if rate < self.MAX_SMOOTHED_RATE:
243
+ self.last_rate = self.RATE_SMOOTHING_FACTOR * rate + (1 - self.RATE_SMOOTHING_FACTOR) * self.last_rate
244
+ rate = self.last_rate
245
+ else:
246
+ rate = self.last_rate
247
+
248
+ # At completion, use the overall rate for more accurate display
249
+ if self.n >= (self.total or float("inf")) and self.total and self.total > 0:
250
+ overall_elapsed = current_time - self.start_t
251
+ if overall_elapsed > 0:
252
+ rate = self.n / overall_elapsed
253
+
254
+ # Update counters
255
+ self.last_print_n = self.n
256
+ self.last_print_t = current_time
257
+ elapsed = current_time - self.start_t
258
+
259
+ # Build progress components
260
+ if self.total is not None:
261
+ percentage = (self.n / self.total) * 100
262
+ # For bytes with unit scaling, avoid repeating units: show "5.4/5.4MB" not "5.4MB/5.4MB"
263
+ n_fmt = self._format_num(self.n)
264
+ total_fmt = self._format_num(self.total)
265
+ if self.unit_scale and self.unit in ("B", "bytes"):
266
+ n_fmt = n_fmt.rstrip("KMGTPB") # Remove unit suffix from current
267
+ else:
268
+ percentage = 0
269
+ n_fmt = self._format_num(self.n)
270
+ total_fmt = "?"
271
+
272
+ elapsed_str = self._format_time(elapsed)
273
+ rate_fmt = self._format_rate(rate) or (self._format_rate(self.n / elapsed) if elapsed > 0 else "")
274
+
275
+ # Format progress string
276
+ progress_str = self.bar_format.format(
277
+ desc=self.desc,
278
+ percentage=percentage,
279
+ bar=self._generate_bar(),
280
+ n_fmt=n_fmt,
281
+ total_fmt=total_fmt,
282
+ rate_fmt=rate_fmt,
283
+ elapsed=elapsed_str,
284
+ unit=self.unit,
285
+ )
286
+
287
+ # Write to output
288
+ try:
289
+ if self.noninteractive:
290
+ # In non-interactive environments, avoid carriage return which creates empty lines
291
+ self.file.write(progress_str)
292
+ else:
293
+ # In interactive terminals, use carriage return and clear line for updating display
294
+ self.file.write(f"\r\033[K{progress_str}")
295
+ self.file.flush()
296
+ except Exception:
297
+ pass
298
+
299
+ def update(self, n=1):
300
+ """Update progress by n steps."""
301
+ if not self.disable and not self.closed:
302
+ self.n += n
303
+ self._display()
304
+
305
+ def set_description(self, desc):
306
+ """Set description."""
307
+ self.desc = desc or ""
308
+ if not self.disable:
309
+ self._display()
310
+
311
+ def set_postfix(self, **kwargs):
312
+ """Set postfix (appends to description)."""
313
+ if kwargs:
314
+ postfix = ", ".join(f"{k}={v}" for k, v in kwargs.items())
315
+ base_desc = self.desc.split(" | ")[0] if " | " in self.desc else self.desc
316
+ self.set_description(f"{base_desc} | {postfix}")
317
+
318
+ def close(self):
319
+ """Close progress bar."""
320
+ if self.closed:
321
+ return
322
+
323
+ self.closed = True # Set before final display
324
+
325
+ if not self.disable:
326
+ # Final display
327
+ if self.total and self.n >= self.total:
328
+ self.n = self.total
329
+ self._display(final=True)
330
+
331
+ # Cleanup
332
+ if self.leave:
333
+ self.file.write("\n")
334
+ else:
335
+ self.file.write("\r\033[K")
336
+
337
+ try:
338
+ self.file.flush()
339
+ except Exception:
340
+ pass
341
+
342
+ def __enter__(self):
343
+ """Enter context manager."""
344
+ return self
345
+
346
+ def __exit__(self, *args):
347
+ """Exit context manager and close progress bar."""
348
+ self.close()
349
+
350
+ def __iter__(self):
351
+ """Iterate over the wrapped iterable with progress updates."""
352
+ if self.iterable is None:
353
+ raise TypeError("'NoneType' object is not iterable")
354
+
355
+ try:
356
+ for item in self.iterable:
357
+ yield item
358
+ self.update(1)
359
+ finally:
360
+ self.close()
361
+
362
+ def __del__(self):
363
+ """Destructor to ensure cleanup."""
364
+ try:
365
+ self.close()
366
+ except Exception:
367
+ pass
368
+
369
+ def refresh(self):
370
+ """Refresh display."""
371
+ if not self.disable:
372
+ self._display()
373
+
374
+ def clear(self):
375
+ """Clear progress bar."""
376
+ if not self.disable:
377
+ try:
378
+ self.file.write("\r\033[K")
379
+ self.file.flush()
380
+ except Exception:
381
+ pass
382
+
383
+ @staticmethod
384
+ def write(s, file=None, end="\n"):
385
+ """Static method to write without breaking progress bar."""
386
+ file = file or sys.stdout
387
+ try:
388
+ file.write(s + end)
389
+ file.flush()
390
+ except Exception:
391
+ pass
392
+
393
+
394
+ if __name__ == "__main__":
395
+ import time
396
+
397
+ # Example 1: Basic usage with known total
398
+ print("1. Basic progress bar with known total:")
399
+ for i in TQDM(range(20), desc="Known total"):
400
+ time.sleep(0.05)
401
+ print()
402
+
403
+ # Example 2: Manual updates with known total
404
+ print("2. Manual updates with known total:")
405
+ pbar = TQDM(total=30, desc="Manual updates", unit="files")
406
+ for i in range(30):
407
+ time.sleep(0.03)
408
+ pbar.update(1)
409
+ if i % 10 == 9:
410
+ pbar.set_description(f"Processing batch {i // 10 + 1}")
411
+ pbar.close()
412
+ print()
413
+
414
+ # Example 3: Unknown total - this was the problematic case
415
+ print("3. Progress bar with unknown total:")
416
+ pbar = TQDM(desc="Unknown total", unit="items")
417
+ for i in range(25):
418
+ time.sleep(0.08)
419
+ pbar.update(1)
420
+ if i % 5 == 4:
421
+ pbar.set_postfix(processed=i + 1, status="OK")
422
+ pbar.close()
423
+ print()
424
+
425
+ # Example 4: Context manager with unknown total
426
+ print("4. Context manager with unknown total:")
427
+ with TQDM(desc="Processing stream", unit="B", unit_scale=True, unit_divisor=1024) as pbar:
428
+ for i in range(30):
429
+ time.sleep(0.1)
430
+ pbar.update(1024 * 1024 * i) # Simulate processing MB of data
431
+ print()
432
+
433
+ # Example 5: Generator with unknown length
434
+ print("5. Iterator with unknown length:")
435
+
436
+ def data_stream():
437
+ """Simulate a data stream of unknown length."""
438
+ import random
439
+
440
+ for i in range(random.randint(10, 20)):
441
+ yield f"data_chunk_{i}"
442
+
443
+ for chunk in TQDM(data_stream(), desc="Stream processing", unit="chunks"):
444
+ time.sleep(0.1)
445
+ print()
446
+
447
+ # Example 6: File-like processing simulation
448
+ print("6. File processing simulation (unknown size):")
449
+
450
+ def process_files():
451
+ """Simulate processing files of unknown count."""
452
+ files = [f"file_{i}.txt" for i in range(18)]
453
+ return files
454
+
455
+ pbar = TQDM(desc="Scanning files", unit="files")
456
+ files = process_files()
457
+ for i, filename in enumerate(files):
458
+ time.sleep(0.06)
459
+ pbar.update(1)
460
+ pbar.set_description(f"Processing {filename}")
461
+ pbar.close()
462
+ print()