Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .cache/pip/http-v2/0/0/f/7/d/00f7ddf3a227e6778c0f6917d53545d95d52c61e2a4b9eadade80a1f.body +3 -0
- .cache/pip/http-v2/0/4/1/8/c/0418c83b80f7f7bfaec2738bfbbee53d2c1562196c0781702f6eddc8.body +3 -0
- .cache/pip/http-v2/0/4/4/f/2/044f2f53cdcb47194b0e9c6df3c8720ef44d4e5b4d49bedd28cc5434.body +3 -0
- .cache/pip/http-v2/0/4/6/5/1/04651185225d2f4f97326e1133d8157925fc8a7b89e811a1210f6558.body +3 -0
- .cache/pip/http-v2/0/4/8/d/6/048d618cdb8f9b2e00fa25b4d36b401928a1055a3454092f5d83e2a6.body +3 -0
- .cache/pip/http-v2/0/6/d/2/0/06d2035d1be597395f35709a93111f033237824a0527da81903f1e51.body +3 -0
- .cache/pip/http-v2/0/9/e/8/d/09e8d49d90cf63602446195abdd4acc84858ac09aa349cdf244340a8.body +3 -0
- .cache/pip/http-v2/0/d/e/4/3/0de43a9a62b2c4201925bcad7d9e3c7ed32696d87f53f418cc6180d6.body +3 -0
- .cache/pip/http-v2/1/0/9/d/5/109d5b2dca31f1c5d503eacb6150a7023dae79f0a0ffa8626cd6aebc +0 -0
- .cache/pip/http-v2/1/0/a/f/b/10afb50cc46801be2fc892e4233b3d2108242b1030bf5eb3ef6841b2 +0 -0
- .cache/pip/http-v2/1/0/a/f/b/10afb50cc46801be2fc892e4233b3d2108242b1030bf5eb3ef6841b2.body +0 -0
- .cache/pip/http-v2/1/0/e/d/c/10edc2fedb88f9a82f91dc7f8666c74a4e7067dbd945b9923a040482.body +3 -0
- .cache/pip/http-v2/1/2/2/4/d/1224d41bab5732a8d21be164d733fc715ab79618a9f55d40126a01df.body +3 -0
- .cache/pip/http-v2/1/4/e/c/f/14ecf6fdd241cb33c00a29ce0bebfb66e7318a08883e62befaecb50b.body +3 -0
- .cache/pip/http-v2/1/6/6/e/7/166e7181cd955d4375be6f62bbc18729f0ef0f67b8b38d1f1af41dd9.body +3 -0
- .cache/pip/http-v2/1/6/9/3/2/1693297fb9daf7bfe370bf51d371acfeb8ff40759bf8650dfd404ba4.body +3 -0
- .cache/pip/http-v2/1/7/4/f/6/174f6021fac0ee18a0f262b675a0951543cde2312549c5c235204100.body +0 -0
- .cache/pip/http-v2/1/c/8/6/4/1c86492d6acbc5af64318c535960c6d5478c385252e490d1f93b749d +0 -0
- .cache/pip/http-v2/1/c/8/6/4/1c86492d6acbc5af64318c535960c6d5478c385252e490d1f93b749d.body +3 -0
- .cache/pip/http-v2/1/e/b/f/d/1ebfddf16e338050f3c69ee3fb0551055792844fc428979435d11f85.body +3 -0
- .cache/pip/http-v2/3/3/9/7/4/33974f84394d9a943f68359da08431dab4af9f86c33962982ea21b5f +0 -0
- .cache/pip/http-v2/3/6/f/b/d/36fbd155c6f5dec2384b1e54f14634a717ea60dcc4c5c06c48e023cf.body +3 -0
- .cache/pip/http-v2/3/b/d/1/2/3bd12ba2f1a7c3549643aa50026e0c2f3c9bff69b82de1d294b27485.body +3 -0
- .cache/pip/http-v2/3/e/7/7/c/3e77c51e855cb3eade14cc9448185875f5bf39a6d82c17de40ca94d5.body +3 -0
- .cache/pip/http-v2/4/0/2/6/6/4026631b7adde65b73ce4a6cea321dd15108dd56fcff2185df112775 +0 -0
- .cache/pip/http-v2/4/0/2/6/6/4026631b7adde65b73ce4a6cea321dd15108dd56fcff2185df112775.body +3 -0
- .cache/pip/http-v2/4/0/8/5/1/40851de76d4978ae24522e7edfdeddaba0192993a8db34a4907aafcd +0 -0
- .cache/pip/http-v2/4/0/8/8/f/4088fdf0071639945ee9ad91e70a8acface70d4ed962ddd666f5454e +0 -0
- .cache/pip/http-v2/4/0/a/d/4/40ad437022f8fc2e168397655f44dd5afa1b97acfe941e16aa179e2c +0 -0
- .cache/pip/http-v2/4/0/a/d/4/40ad437022f8fc2e168397655f44dd5afa1b97acfe941e16aa179e2c.body +43 -0
- .cache/pip/http-v2/4/0/f/8/f/40f8f5a7325d13d318e01d17053cf2dadf6b6daa8a7e60583d48809b +0 -0
- .cache/pip/http-v2/4/0/f/8/f/40f8f5a7325d13d318e01d17053cf2dadf6b6daa8a7e60583d48809b.body +0 -0
- .cache/pip/http-v2/4/1/e/7/2/41e7263a9efb3323d3506d54d219d6a951911345e0f82c731aff5a5b +0 -0
- .cache/pip/http-v2/4/1/e/7/2/41e7263a9efb3323d3506d54d219d6a951911345e0f82c731aff5a5b.body +375 -0
- .cache/pip/http-v2/4/2/5/e/e/425ee452eddda30695488b965f5cfa22049bb8f92ad87623f545a8bb +0 -0
- .cache/pip/http-v2/4/2/5/e/e/425ee452eddda30695488b965f5cfa22049bb8f92ad87623f545a8bb.body +324 -0
- .cache/pip/http-v2/4/2/6/6/d/4266da420f80fe5b2de81f440f459cda33c49a87b4c539a917582c18.body +203 -0
- .cache/pip/http-v2/4/3/2/5/0/432508fca4367eb16c5bda476b8ecbf96beccd650c7aea212e59eb40 +0 -0
- .cache/pip/http-v2/4/3/2/5/0/432508fca4367eb16c5bda476b8ecbf96beccd650c7aea212e59eb40.body +490 -0
- .cache/pip/http-v2/4/3/4/e/4/434e4f9063597b6ecac7104d4d3128df26a47ab65e2f09d0f5f7b59d +0 -0
- .cache/pip/http-v2/4/3/4/e/4/434e4f9063597b6ecac7104d4d3128df26a47ab65e2f09d0f5f7b59d.body +408 -0
- .cache/pip/http-v2/4/3/6/8/4/436846b847c9c90a13539a872e2084e3f9ca23eb93b4b1cc44b55964 +0 -0
- .cache/pip/http-v2/4/3/6/8/4/436846b847c9c90a13539a872e2084e3f9ca23eb93b4b1cc44b55964.body +112 -0
- .cache/pip/http-v2/4/4/1/9/6/44196988557c6a112ae696d10605a07ed4576112a509edb0095e3b08 +0 -0
- .cache/pip/http-v2/4/4/1/9/6/44196988557c6a112ae696d10605a07ed4576112a509edb0095e3b08.body +3 -0
- .cache/pip/http-v2/4/4/6/c/5/446c514b42f8098e88d951919b55761fcef1b141bd548733adaddda2 +0 -0
- .cache/pip/http-v2/4/4/6/c/5/446c514b42f8098e88d951919b55761fcef1b141bd548733adaddda2.body +3 -0
- .cache/pip/http-v2/4/4/a/d/5/44ad51ab4fe732177892254938ca19df59a19add805fe17b3b22c658 +0 -0
- .cache/pip/http-v2/4/4/a/d/5/44ad51ab4fe732177892254938ca19df59a19add805fe17b3b22c658.body +1595 -0
- .cache/pip/http-v2/4/4/e/5/b/44e5b11a6caa92636d8ccfe658d420ba4ed8f67f7f4e835b214255aa +0 -0
.cache/pip/http-v2/0/0/f/7/d/00f7ddf3a227e6778c0f6917d53545d95d52c61e2a4b9eadade80a1f.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:729be4a976fb706dcc02d176bcda8a3f32bdf21a294e8f4b3dda6fbcbc9c1ab1
|
| 3 |
+
size 684411
|
.cache/pip/http-v2/0/4/1/8/c/0418c83b80f7f7bfaec2738bfbbee53d2c1562196c0781702f6eddc8.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b9a11a8cc2f49267984ef4fee282f8d544ceae04a4ee7b103cfa0295d1fa2dfd
|
| 3 |
+
size 190689
|
.cache/pip/http-v2/0/4/4/f/2/044f2f53cdcb47194b0e9c6df3c8720ef44d4e5b4d49bedd28cc5434.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf
|
| 3 |
+
size 221575
|
.cache/pip/http-v2/0/4/6/5/1/04651185225d2f4f97326e1133d8157925fc8a7b89e811a1210f6558.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713
|
| 3 |
+
size 309071
|
.cache/pip/http-v2/0/4/8/d/6/048d618cdb8f9b2e00fa25b4d36b401928a1055a3454092f5d83e2a6.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6a498f82e0f4d8904c4e0aea5139cdfac1f39d19a3c51d491292f63a36e83b2e
|
| 3 |
+
size 11616911
|
.cache/pip/http-v2/0/6/d/2/0/06d2035d1be597395f35709a93111f033237824a0527da81903f1e51.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:def5aac47b28e2f1386fa64f2f458a5474ba7733ab74c1765e7c67a79d1f1cbd
|
| 3 |
+
size 10364790
|
.cache/pip/http-v2/0/9/e/8/d/09e8d49d90cf63602446195abdd4acc84858ac09aa349cdf244340a8.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613
|
| 3 |
+
size 110502
|
.cache/pip/http-v2/0/d/e/4/3/0de43a9a62b2c4201925bcad7d9e3c7ed32696d87f53f418cc6180d6.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8ff903295bb61260bc27ee3be4aa55401f1ca39065109f4b127047f82f237642
|
| 3 |
+
size 6090015
|
.cache/pip/http-v2/1/0/9/d/5/109d5b2dca31f1c5d503eacb6150a7023dae79f0a0ffa8626cd6aebc
ADDED
|
Binary file (1.2 kB). View file
|
|
|
.cache/pip/http-v2/1/0/a/f/b/10afb50cc46801be2fc892e4233b3d2108242b1030bf5eb3ef6841b2
ADDED
|
Binary file (1.23 kB). View file
|
|
|
.cache/pip/http-v2/1/0/a/f/b/10afb50cc46801be2fc892e4233b3d2108242b1030bf5eb3ef6841b2.body
ADDED
|
Binary file (61.6 kB). View file
|
|
|
.cache/pip/http-v2/1/0/e/d/c/10edc2fedb88f9a82f91dc7f8666c74a4e7067dbd945b9923a040482.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:89af7581659f9044491f531d538245f272d181bdd301d7c5fbf85f913e723038
|
| 3 |
+
size 188905
|
.cache/pip/http-v2/1/2/2/4/d/1224d41bab5732a8d21be164d733fc715ab79618a9f55d40126a01df.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65
|
| 3 |
+
size 182523
|
.cache/pip/http-v2/1/4/e/c/f/14ecf6fdd241cb33c00a29ce0bebfb66e7318a08883e62befaecb50b.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:688d1c704ddecf382ea3326f21a67453d4caa95592d722b7c780a36a9d23109e
|
| 3 |
+
size 460919
|
.cache/pip/http-v2/1/6/6/e/7/166e7181cd955d4375be6f62bbc18729f0ef0f67b8b38d1f1af41dd9.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:77ccc56582d07671a867b78ced686096ca53c021d79fed38e5aaf4cebbd0450b
|
| 3 |
+
size 26378746
|
.cache/pip/http-v2/1/6/9/3/2/1693297fb9daf7bfe370bf51d371acfeb8ff40759bf8650dfd404ba4.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e6a2d23a49dba526379bfd091dc2b592cda31969301f578f0c673c9457b9f5a1
|
| 3 |
+
size 322045
|
.cache/pip/http-v2/1/7/4/f/6/174f6021fac0ee18a0f262b675a0951543cde2312549c5c235204100.body
ADDED
|
Binary file (15.1 kB). View file
|
|
|
.cache/pip/http-v2/1/c/8/6/4/1c86492d6acbc5af64318c535960c6d5478c385252e490d1f93b749d
ADDED
|
Binary file (1.2 kB). View file
|
|
|
.cache/pip/http-v2/1/c/8/6/4/1c86492d6acbc5af64318c535960c6d5478c385252e490d1f93b749d.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f
|
| 3 |
+
size 117683
|
.cache/pip/http-v2/1/e/b/f/d/1ebfddf16e338050f3c69ee3fb0551055792844fc428979435d11f85.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1f55797419e16e7f30cf88ffb3113ce0467f00cfe3f70d5c281730b21769bfc2
|
| 3 |
+
size 35287115
|
.cache/pip/http-v2/3/3/9/7/4/33974f84394d9a943f68359da08431dab4af9f86c33962982ea21b5f
ADDED
|
Binary file (1.8 kB). View file
|
|
|
.cache/pip/http-v2/3/6/f/b/d/36fbd155c6f5dec2384b1e54f14634a717ea60dcc4c5c06c48e023cf.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:53a0f57e59a530d18a142f4d4ba6dfc708dc5fdedce45e98ff06b44930a2a48f
|
| 3 |
+
size 133624
|
.cache/pip/http-v2/3/b/d/1/2/3bd12ba2f1a7c3549643aa50026e0c2f3c9bff69b82de1d294b27485.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a0d94420d9d52c56568159a69200af7e45eadb29615fa9d09fada140de1c38c7
|
| 3 |
+
size 420090
|
.cache/pip/http-v2/3/e/7/7/c/3e77c51e855cb3eade14cc9448185875f5bf39a6d82c17de40ca94d5.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cdca9bfb89e6f8f281890cc61a8aff2d3cecaff7e1a4d275574d96ca70098557
|
| 3 |
+
size 3552664
|
.cache/pip/http-v2/4/0/2/6/6/4026631b7adde65b73ce4a6cea321dd15108dd56fcff2185df112775
ADDED
|
Binary file (1.15 kB). View file
|
|
|
.cache/pip/http-v2/4/0/2/6/6/4026631b7adde65b73ce4a6cea321dd15108dd56fcff2185df112775.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf
|
| 3 |
+
size 462431
|
.cache/pip/http-v2/4/0/8/5/1/40851de76d4978ae24522e7edfdeddaba0192993a8db34a4907aafcd
ADDED
|
Binary file (1.17 kB). View file
|
|
|
.cache/pip/http-v2/4/0/8/8/f/4088fdf0071639945ee9ad91e70a8acface70d4ed962ddd666f5454e
ADDED
|
Binary file (1.8 kB). View file
|
|
|
.cache/pip/http-v2/4/0/a/d/4/40ad437022f8fc2e168397655f44dd5afa1b97acfe941e16aa179e2c
ADDED
|
Binary file (1.28 kB). View file
|
|
|
.cache/pip/http-v2/4/0/a/d/4/40ad437022f8fc2e168397655f44dd5afa1b97acfe941e16aa179e2c.body
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: python-multipart
|
| 3 |
+
Version: 0.0.27
|
| 4 |
+
Summary: A streaming multipart parser for Python
|
| 5 |
+
Project-URL: Homepage, https://github.com/Kludex/python-multipart
|
| 6 |
+
Project-URL: Documentation, https://kludex.github.io/python-multipart/
|
| 7 |
+
Project-URL: Changelog, https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md
|
| 8 |
+
Project-URL: Source, https://github.com/Kludex/python-multipart
|
| 9 |
+
Author-email: Andrew Dunham <andrew@du.nham.ca>
|
| 10 |
+
Maintainer-email: Marcelo Trylesinski <marcelotryle@gmail.com>
|
| 11 |
+
License-Expression: Apache-2.0
|
| 12 |
+
License-File: LICENSE.txt
|
| 13 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 14 |
+
Classifier: Environment :: Web Environment
|
| 15 |
+
Classifier: Intended Audience :: Developers
|
| 16 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
| 17 |
+
Classifier: Operating System :: OS Independent
|
| 18 |
+
Classifier: Programming Language :: Python :: 3
|
| 19 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 24 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 25 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
| 26 |
+
Requires-Python: >=3.10
|
| 27 |
+
Description-Content-Type: text/markdown
|
| 28 |
+
|
| 29 |
+
# [Python-Multipart](https://kludex.github.io/python-multipart/)
|
| 30 |
+
|
| 31 |
+
[](https://github.com/Kludex/python-multipart/actions)
|
| 32 |
+
[](https://pypi.python.org/pypi/python-multipart)
|
| 33 |
+
[](https://pypi.org/project/python-multipart)
|
| 34 |
+
[](https://discord.gg/RxKUF5JuHs)
|
| 35 |
+
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
`python-multipart` is an Apache2-licensed streaming multipart parser for Python.
|
| 39 |
+
Test coverage is currently 100%.
|
| 40 |
+
|
| 41 |
+
## Why?
|
| 42 |
+
|
| 43 |
+
Because streaming uploads are awesome for large files.
|
.cache/pip/http-v2/4/0/f/8/f/40f8f5a7325d13d318e01d17053cf2dadf6b6daa8a7e60583d48809b
ADDED
|
Binary file (1.8 kB). View file
|
|
|
.cache/pip/http-v2/4/0/f/8/f/40f8f5a7325d13d318e01d17053cf2dadf6b6daa8a7e60583d48809b.body
ADDED
|
Binary file (4.77 kB). View file
|
|
|
.cache/pip/http-v2/4/1/e/7/2/41e7263a9efb3323d3506d54d219d6a951911345e0f82c731aff5a5b
ADDED
|
Binary file (1.29 kB). View file
|
|
|
.cache/pip/http-v2/4/1/e/7/2/41e7263a9efb3323d3506d54d219d6a951911345e0f82c731aff5a5b.body
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: pathspec
|
| 3 |
+
Version: 1.1.0
|
| 4 |
+
Summary: Utility library for gitignore style pattern matching of file paths.
|
| 5 |
+
Author-email: "Caleb P. Burns" <cpburnz@gmail.com>
|
| 6 |
+
Requires-Python: >=3.9
|
| 7 |
+
Description-Content-Type: text/x-rst
|
| 8 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 9 |
+
Classifier: Intended Audience :: Developers
|
| 10 |
+
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
| 11 |
+
Classifier: Operating System :: OS Independent
|
| 12 |
+
Classifier: Programming Language :: Python
|
| 13 |
+
Classifier: Programming Language :: Python :: 3
|
| 14 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 15 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 16 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 17 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 18 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 20 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
| 21 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 22 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
| 23 |
+
Classifier: Topic :: Utilities
|
| 24 |
+
License-File: LICENSE
|
| 25 |
+
Requires-Dist: hyperscan >=0.7 ; extra == "hyperscan"
|
| 26 |
+
Requires-Dist: typing-extensions >=4 ; extra == "optional"
|
| 27 |
+
Requires-Dist: google-re2 >=1.1 ; extra == "re2"
|
| 28 |
+
Project-URL: Change Log, https://python-path-specification.readthedocs.io/en/latest/changes.html
|
| 29 |
+
Project-URL: Documentation, https://python-path-specification.readthedocs.io/en/latest/index.html
|
| 30 |
+
Project-URL: Issue Tracker, https://github.com/cpburnz/python-pathspec/issues
|
| 31 |
+
Project-URL: Source Code, https://github.com/cpburnz/python-pathspec
|
| 32 |
+
Provides-Extra: hyperscan
|
| 33 |
+
Provides-Extra: optional
|
| 34 |
+
Provides-Extra: re2
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
PathSpec
|
| 38 |
+
========
|
| 39 |
+
|
| 40 |
+
*pathspec* is a utility library for pattern matching of file paths. So far this
|
| 41 |
+
only includes Git's `gitignore`_ pattern matching.
|
| 42 |
+
|
| 43 |
+
.. _`gitignore`: http://git-scm.com/docs/gitignore
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
Tutorial
|
| 47 |
+
--------
|
| 48 |
+
|
| 49 |
+
Say you have a "Projects" directory and you want to back it up, but only
|
| 50 |
+
certain files, and ignore others depending on certain conditions::
|
| 51 |
+
|
| 52 |
+
>>> from pathspec import PathSpec
|
| 53 |
+
>>> # The gitignore-style patterns for files to select, but we're including
|
| 54 |
+
>>> # instead of ignoring.
|
| 55 |
+
>>> spec_text = """
|
| 56 |
+
...
|
| 57 |
+
... # This is a comment because the line begins with a hash: "#"
|
| 58 |
+
...
|
| 59 |
+
... # Include several project directories (and all descendants) relative to
|
| 60 |
+
... # the current directory. To reference only a directory you must end with a
|
| 61 |
+
... # slash: "/"
|
| 62 |
+
... /project-a/
|
| 63 |
+
... /project-b/
|
| 64 |
+
... /project-c/
|
| 65 |
+
...
|
| 66 |
+
... # Patterns can be negated by prefixing with exclamation mark: "!"
|
| 67 |
+
...
|
| 68 |
+
... # Ignore temporary files beginning or ending with "~" and ending with
|
| 69 |
+
... # ".swp".
|
| 70 |
+
... !~*
|
| 71 |
+
... !*~
|
| 72 |
+
... !*.swp
|
| 73 |
+
...
|
| 74 |
+
... # These are python projects so ignore compiled python files from
|
| 75 |
+
... # testing.
|
| 76 |
+
... !*.pyc
|
| 77 |
+
...
|
| 78 |
+
... # Ignore the build directories but only directly under the project
|
| 79 |
+
... # directories.
|
| 80 |
+
... !/*/build/
|
| 81 |
+
...
|
| 82 |
+
... """
|
| 83 |
+
|
| 84 |
+
The ``PathSpec`` class provides an abstraction around pattern implementations,
|
| 85 |
+
and we want to compile our patterns as "gitignore" patterns. You could call it a
|
| 86 |
+
wrapper for a list of compiled patterns::
|
| 87 |
+
|
| 88 |
+
>>> spec = PathSpec.from_lines('gitignore', spec_text.splitlines())
|
| 89 |
+
|
| 90 |
+
If we wanted to manually compile the patterns, we can use the ``GitIgnoreBasicPattern``
|
| 91 |
+
class directly. It is used in the background for "gitignore" which internally
|
| 92 |
+
converts patterns to regular expressions::
|
| 93 |
+
|
| 94 |
+
>>> from pathspec.patterns.gitignore.basic import GitIgnoreBasicPattern
|
| 95 |
+
>>> patterns = map(GitIgnoreBasicPattern, spec_text.splitlines())
|
| 96 |
+
>>> spec = PathSpec(patterns)
|
| 97 |
+
|
| 98 |
+
``PathSpec.from_lines()`` is a class method which simplifies that.
|
| 99 |
+
|
| 100 |
+
If you want to load the patterns from file, you can pass the file object
|
| 101 |
+
directly as well::
|
| 102 |
+
|
| 103 |
+
>>> with open('patterns.list', 'r') as fh:
|
| 104 |
+
>>> spec = PathSpec.from_lines('gitignore', fh)
|
| 105 |
+
|
| 106 |
+
You can perform matching on a whole directory tree with::
|
| 107 |
+
|
| 108 |
+
>>> matches = set(spec.match_tree_files('path/to/directory'))
|
| 109 |
+
|
| 110 |
+
Or you can perform matching on a specific set of file paths with::
|
| 111 |
+
|
| 112 |
+
>>> matches = set(spec.match_files(file_paths))
|
| 113 |
+
|
| 114 |
+
Or check to see if an individual file matches::
|
| 115 |
+
|
| 116 |
+
>>> is_matched = spec.match_file(file_path)
|
| 117 |
+
|
| 118 |
+
There's actually two implementations of "gitignore". The basic implementation is
|
| 119 |
+
used by ``PathSpec`` and follows patterns as documented by `gitignore`_.
|
| 120 |
+
However, Git's behavior differs from the documented patterns. There's some
|
| 121 |
+
edge-cases, and in particular, Git allows including files from excluded
|
| 122 |
+
directories which appears to contradict the documentation. ``GitIgnoreSpec``
|
| 123 |
+
handles these cases to more closely replicate Git's behavior::
|
| 124 |
+
|
| 125 |
+
>>> from pathspec import GitIgnoreSpec
|
| 126 |
+
>>> spec = GitIgnoreSpec.from_lines(spec_text.splitlines())
|
| 127 |
+
|
| 128 |
+
You do not specify the style of pattern for ``GitIgnoreSpec`` because it should
|
| 129 |
+
always use ``GitIgnoreSpecPattern`` internally.
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
Performance
|
| 133 |
+
-----------
|
| 134 |
+
|
| 135 |
+
Running lots of regular expression matches against thousands of files in Python
|
| 136 |
+
is slow. Alternate regular expression backends can be used to improve
|
| 137 |
+
performance. ``PathSpec`` and ``GitIgnoreSpec`` both accept a ``backend``
|
| 138 |
+
parameter to control the backend. The default is "best" to automatically choose
|
| 139 |
+
the best available backend. There are currently 3 backends.
|
| 140 |
+
|
| 141 |
+
The "simple" backend is the default and it simply uses Python's ``re.Pattern``
|
| 142 |
+
objects that are normally created. This can be the fastest when there's only 1
|
| 143 |
+
or 2 patterns.
|
| 144 |
+
|
| 145 |
+
The "hyperscan" backend uses the `hyperscan`_ library. Hyperscan tends to be at
|
| 146 |
+
least 2 times faster than "simple", and generally slower than "re2". This can be
|
| 147 |
+
faster than "re2" under the right conditions with pattern counts of 1-25.
|
| 148 |
+
|
| 149 |
+
The "re2" backend uses the `google-re2`_ library (not to be confused with the
|
| 150 |
+
*re2* library on PyPI which is unrelated and abandoned). Google's re2 tends to
|
| 151 |
+
be significantly faster than "simple", and 3 times faster than "hyperscan" at
|
| 152 |
+
high pattern counts.
|
| 153 |
+
|
| 154 |
+
See `benchmarks_backends.md`_ for comparisons between native Python regular
|
| 155 |
+
expressions and the optional backends.
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
.. _`benchmarks_backends.md`: https://github.com/cpburnz/python-pathspec/blob/master/benchmarks_backends.md
|
| 159 |
+
.. _`google-re2`: https://pypi.org/project/google-re2/
|
| 160 |
+
.. _`hyperscan`: https://pypi.org/project/hyperscan/
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
FAQ
|
| 164 |
+
---
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
1. How do I ignore files like *.gitignore*?
|
| 168 |
+
+++++++++++++++++++++++++++++++++++++++++++
|
| 169 |
+
|
| 170 |
+
``GitIgnoreSpec`` (and ``PathSpec``) positively match files by default. To find
|
| 171 |
+
the files to keep, and exclude files like *.gitignore*, you need to set
|
| 172 |
+
``negate=True`` to flip the results::
|
| 173 |
+
|
| 174 |
+
>>> from pathspec import GitIgnoreSpec
|
| 175 |
+
>>> spec = GitIgnoreSpec.from_lines([...])
|
| 176 |
+
>>> keep_files = set(spec.match_tree_files('path/to/directory', negate=True))
|
| 177 |
+
>>> ignore_files = set(spec.match_tree_files('path/to/directory'))
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
License
|
| 181 |
+
-------
|
| 182 |
+
|
| 183 |
+
*pathspec* is licensed under the `Mozilla Public License Version 2.0`_. See
|
| 184 |
+
`LICENSE`_ or the `FAQ`_ for more information.
|
| 185 |
+
|
| 186 |
+
In summary, you may use *pathspec* with any closed or open source project
|
| 187 |
+
without affecting the license of the larger work so long as you:
|
| 188 |
+
|
| 189 |
+
- give credit where credit is due,
|
| 190 |
+
|
| 191 |
+
- and release any custom changes made to *pathspec*.
|
| 192 |
+
|
| 193 |
+
.. _`Mozilla Public License Version 2.0`: http://www.mozilla.org/MPL/2.0
|
| 194 |
+
.. _`LICENSE`: LICENSE
|
| 195 |
+
.. _`FAQ`: http://www.mozilla.org/MPL/2.0/FAQ.html
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
Source
|
| 199 |
+
------
|
| 200 |
+
|
| 201 |
+
The source code for *pathspec* is available from the GitHub repo
|
| 202 |
+
`cpburnz/python-pathspec`_.
|
| 203 |
+
|
| 204 |
+
.. _`cpburnz/python-pathspec`: https://github.com/cpburnz/python-pathspec
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
Installation
|
| 208 |
+
------------
|
| 209 |
+
|
| 210 |
+
*pathspec* is available for install through `PyPI`_::
|
| 211 |
+
|
| 212 |
+
pip install pathspec
|
| 213 |
+
|
| 214 |
+
*pathspec* can also be built from source. The following packages will be
|
| 215 |
+
required:
|
| 216 |
+
|
| 217 |
+
- `build`_ (>=0.6.0)
|
| 218 |
+
|
| 219 |
+
*pathspec* can then be built and installed with::
|
| 220 |
+
|
| 221 |
+
python -m build
|
| 222 |
+
pip install dist/pathspec-*-py3-none-any.whl
|
| 223 |
+
|
| 224 |
+
The following optional dependencies can be installed:
|
| 225 |
+
|
| 226 |
+
- `google-re2`_: Enables optional "re2" backend.
|
| 227 |
+
- `hyperscan`_: Enables optional "hyperscan" backend.
|
| 228 |
+
- `typing-extensions`_: Improves some type hints.
|
| 229 |
+
|
| 230 |
+
.. _`PyPI`: http://pypi.python.org/pypi/pathspec
|
| 231 |
+
.. _`build`: https://pypi.org/project/build/
|
| 232 |
+
.. _`typing-extensions`: https://pypi.org/project/typing-extensions/
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
Documentation
|
| 236 |
+
-------------
|
| 237 |
+
|
| 238 |
+
Documentation for *pathspec* is available on `Read the Docs`_.
|
| 239 |
+
|
| 240 |
+
The full change history can be found in `CHANGES.rst`_ and `Change History`_.
|
| 241 |
+
|
| 242 |
+
An upgrade guide is available in `UPGRADING.rst`_ and `Upgrade Guide`_.
|
| 243 |
+
|
| 244 |
+
.. _`CHANGES.rst`: https://github.com/cpburnz/python-pathspec/blob/master/CHANGES.rst
|
| 245 |
+
.. _`Change History`: https://python-path-specification.readthedocs.io/en/stable/changes.html
|
| 246 |
+
.. _`Read the Docs`: https://python-path-specification.readthedocs.io
|
| 247 |
+
.. _`UPGRADING.rst`: https://github.com/cpburnz/python-pathspec/blob/master/UPGRADING.rst
|
| 248 |
+
.. _`Upgrade Guide`: https://python-path-specification.readthedocs.io/en/stable/upgrading.html
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
Other Languages
|
| 252 |
+
---------------
|
| 253 |
+
|
| 254 |
+
The related project `pathspec-ruby`_ (by *highb*) provides a similar library as
|
| 255 |
+
a `Ruby gem`_.
|
| 256 |
+
|
| 257 |
+
.. _`pathspec-ruby`: https://github.com/highb/pathspec-ruby
|
| 258 |
+
.. _`Ruby gem`: https://rubygems.org/gems/pathspec
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
Change History
|
| 262 |
+
==============
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
1.1.0 (2026-04-22)
|
| 266 |
+
------------------
|
| 267 |
+
|
| 268 |
+
Bug fixes:
|
| 269 |
+
|
| 270 |
+
- `Issue #93`_: Git discards invalid range notation. `GitIgnoreSpecPattern` now discards patterns with invalid range notation like Git.
|
| 271 |
+
- `Pull #106`_: Fix escape() not escaping backslash characters.
|
| 272 |
+
|
| 273 |
+
Improvements:
|
| 274 |
+
|
| 275 |
+
- `Issue #108`_: Specialize pattern type for `PathSpec` as `PathSpec[TPattern]` for better debugging of `PathSpec().patterns`.
|
| 276 |
+
- `Pull #110`_: Nicer debug print outs (and str for regex pattern).
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
.. _`Pull #106`: https://github.com/cpburnz/python-pathspec/pull/106
|
| 280 |
+
.. _`Issue #108`: https://github.com/cpburnz/python-pathspec/issues/108
|
| 281 |
+
.. _`Pull #110`: https://github.com/cpburnz/python-pathspec/pull/110
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
1.0.4 (2026-01-26)
|
| 285 |
+
------------------
|
| 286 |
+
|
| 287 |
+
Bug fixes:
|
| 288 |
+
|
| 289 |
+
- `Issue #103`_: Using re2 fails if pyre2 is also installed.
|
| 290 |
+
|
| 291 |
+
.. _`Issue #103`: https://github.com/cpburnz/python-pathspec/issues/103
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
1.0.3 (2026-01-09)
|
| 295 |
+
------------------
|
| 296 |
+
|
| 297 |
+
Bug fixes:
|
| 298 |
+
|
| 299 |
+
- `Issue #101`_: pyright strict errors with pathspec >= 1.0.0.
|
| 300 |
+
- `Issue #102`_: No module named 'tomllib'.
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
.. _`Issue #101`: https://github.com/cpburnz/python-pathspec/issues/101
|
| 304 |
+
.. _`Issue #102`: https://github.com/cpburnz/python-pathspec/issues/102
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
1.0.2 (2026-01-07)
|
| 308 |
+
------------------
|
| 309 |
+
|
| 310 |
+
Bug fixes:
|
| 311 |
+
|
| 312 |
+
- Type hint `collections.abc.Callable` does not properly replace `typing.Callable` until Python 3.9.2.
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
1.0.1 (2026-01-06)
|
| 316 |
+
------------------
|
| 317 |
+
|
| 318 |
+
Bug fixes:
|
| 319 |
+
|
| 320 |
+
- `Issue #100`_: ValueError(f"{patterns=!r} cannot be empty.") when using black.
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
.. _`Issue #100`: https://github.com/cpburnz/python-pathspec/issues/100
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
1.0.0 (2026-01-05)
|
| 327 |
+
------------------
|
| 328 |
+
|
| 329 |
+
Major changes:
|
| 330 |
+
|
| 331 |
+
- `Issue #91`_: Dropped support of EoL Python 3.8.
|
| 332 |
+
- Added concept of backends to allow for faster regular expression matching. The backend can be controlled using the `backend` argument to `PathSpec()`, `PathSpec.from_lines()`, `GitIgnoreSpec()`, and `GitIgnoreSpec.from_lines()`.
|
| 333 |
+
- Renamed "gitwildmatch" pattern back to "gitignore". The "gitignore" pattern behaves slightly differently when used with `PathSpec` (*gitignore* as documented) than with `GitIgnoreSpec` (replicates *Git*'s edge cases).
|
| 334 |
+
|
| 335 |
+
API changes:
|
| 336 |
+
|
| 337 |
+
- Breaking: protected method `pathspec.pathspec.PathSpec._match_file()` (with a leading underscore) has been removed and replaced by backends. This does not affect normal usage of `PathSpec` or `GitIgnoreSpec`. Only custom subclasses will be affected. If this breaks your usage, let me know by `opening an issue <https://github.com/cpburnz/python-pathspec/issues>`_.
|
| 338 |
+
- Deprecated: "gitwildmatch" is now an alias for "gitignore".
|
| 339 |
+
- Deprecated: `pathspec.patterns.GitWildMatchPattern` is now an alias for `pathspec.patterns.gitignore.spec.GitIgnoreSpecPattern`.
|
| 340 |
+
- Deprecated: `pathspec.patterns.gitwildmatch` module has been replaced by the `pathspec.patterns.gitignore` package.
|
| 341 |
+
- Deprecated: `pathspec.patterns.gitwildmatch.GitWildMatchPattern` is now an alias for `pathspec.patterns.gitignore.spec.GitIgnoreSpecPattern`.
|
| 342 |
+
- Deprecated: `pathspec.patterns.gitwildmatch.GitWildMatchPatternError` is now an alias for `pathspec.patterns.gitignore.GitIgnorePatternError`.
|
| 343 |
+
- Removed: `pathspec.patterns.gitwildmatch.GitIgnorePattern` has been deprecated since v0.4 (2016-07-15).
|
| 344 |
+
- Signature of method `pathspec.pattern.RegexPattern.match_file()` has been changed from `def match_file(self, file: str) -> RegexMatchResult | None` to `def match_file(self, file: AnyStr) -> RegexMatchResult | None` to reflect usage.
|
| 345 |
+
- Signature of class method `pathspec.pattern.RegexPattern.pattern_to_regex()` has been changed from `def pattern_to_regex(cls, pattern: str) -> tuple[str, bool]` to `def pattern_to_regex(cls, pattern: AnyStr) -> tuple[AnyStr | None, bool | None]` to reflect usage and documentation.
|
| 346 |
+
|
| 347 |
+
New features:
|
| 348 |
+
|
| 349 |
+
- Added optional "hyperscan" backend using `hyperscan`_ library. It will automatically be used when installed. This dependency can be installed with ``pip install 'pathspec[hyperscan]'``.
|
| 350 |
+
- Added optional "re2" backend using the `google-re2`_ library. It will automatically be used when installed. This dependency can be installed with ``pip install 'pathspec[re2]'``.
|
| 351 |
+
- Added optional dependency on `typing-extensions`_ library to improve some type hints.
|
| 352 |
+
|
| 353 |
+
Bug fixes:
|
| 354 |
+
|
| 355 |
+
- `Issue #93`_: Do not remove leading spaces.
|
| 356 |
+
- `Issue #95`_: Matching for files inside folder does not seem to behave like .gitignore's.
|
| 357 |
+
- `Issue #98`_: UnboundLocalError in RegexPattern when initialized with `pattern=None`.
|
| 358 |
+
- Type hint on return value of `pathspec.pattern.RegexPattern.match_file()` to match documentation.
|
| 359 |
+
|
| 360 |
+
Improvements:
|
| 361 |
+
|
| 362 |
+
- Mark Python 3.13 and 3.14 as supported.
|
| 363 |
+
- No-op patterns are now filtered out when matching files, slightly improving performance.
|
| 364 |
+
- Fix performance regression in `iter_tree_files()` from v0.10.
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
.. _`Issue #38`: https://github.com/cpburnz/python-pathspec/issues/38
|
| 368 |
+
.. _`Issue #91`: https://github.com/cpburnz/python-pathspec/issues/91
|
| 369 |
+
.. _`Issue #93`: https://github.com/cpburnz/python-pathspec/issues/93
|
| 370 |
+
.. _`Issue #95`: https://github.com/cpburnz/python-pathspec/issues/95
|
| 371 |
+
.. _`Issue #98`: https://github.com/cpburnz/python-pathspec/issues/98
|
| 372 |
+
.. _`google-re2`: https://pypi.org/project/google-re2/
|
| 373 |
+
.. _`hyperscan`: https://pypi.org/project/hyperscan/
|
| 374 |
+
.. _`typing-extensions`: https://pypi.org/project/typing-extensions/
|
| 375 |
+
|
.cache/pip/http-v2/4/2/5/e/e/425ee452eddda30695488b965f5cfa22049bb8f92ad87623f545a8bb
ADDED
|
Binary file (1.22 kB). View file
|
|
|
.cache/pip/http-v2/4/2/5/e/e/425ee452eddda30695488b965f5cfa22049bb8f92ad87623f545a8bb.body
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: huggingface_hub
|
| 3 |
+
Version: 1.9.1
|
| 4 |
+
Summary: Client library to download and publish models, datasets and other repos on the huggingface.co hub
|
| 5 |
+
Home-page: https://github.com/huggingface/huggingface_hub
|
| 6 |
+
Author: Hugging Face, Inc.
|
| 7 |
+
Author-email: julien@huggingface.co
|
| 8 |
+
License: Apache-2.0
|
| 9 |
+
Keywords: model-hub machine-learning models natural-language-processing deep-learning pytorch pretrained-models
|
| 10 |
+
Classifier: Intended Audience :: Developers
|
| 11 |
+
Classifier: Intended Audience :: Education
|
| 12 |
+
Classifier: Intended Audience :: Science/Research
|
| 13 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
| 14 |
+
Classifier: Operating System :: OS Independent
|
| 15 |
+
Classifier: Programming Language :: Python :: 3
|
| 16 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 17 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 18 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 22 |
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
| 23 |
+
Requires-Python: >=3.10.0
|
| 24 |
+
Description-Content-Type: text/markdown
|
| 25 |
+
License-File: LICENSE
|
| 26 |
+
Requires-Dist: filelock>=3.10.0
|
| 27 |
+
Requires-Dist: fsspec>=2023.5.0
|
| 28 |
+
Requires-Dist: hf-xet<2.0.0,>=1.4.3; platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "arm64" or platform_machine == "aarch64"
|
| 29 |
+
Requires-Dist: httpx<1,>=0.23.0
|
| 30 |
+
Requires-Dist: packaging>=20.9
|
| 31 |
+
Requires-Dist: pyyaml>=5.1
|
| 32 |
+
Requires-Dist: tqdm>=4.42.1
|
| 33 |
+
Requires-Dist: typer
|
| 34 |
+
Requires-Dist: typing-extensions>=4.1.0
|
| 35 |
+
Provides-Extra: oauth
|
| 36 |
+
Requires-Dist: authlib>=1.3.2; extra == "oauth"
|
| 37 |
+
Requires-Dist: fastapi; extra == "oauth"
|
| 38 |
+
Requires-Dist: httpx; extra == "oauth"
|
| 39 |
+
Requires-Dist: itsdangerous; extra == "oauth"
|
| 40 |
+
Provides-Extra: torch
|
| 41 |
+
Requires-Dist: torch; extra == "torch"
|
| 42 |
+
Requires-Dist: safetensors[torch]; extra == "torch"
|
| 43 |
+
Provides-Extra: fastai
|
| 44 |
+
Requires-Dist: toml; extra == "fastai"
|
| 45 |
+
Requires-Dist: fastai>=2.4; extra == "fastai"
|
| 46 |
+
Requires-Dist: fastcore>=1.3.27; extra == "fastai"
|
| 47 |
+
Provides-Extra: hf-xet
|
| 48 |
+
Requires-Dist: hf-xet<2.0.0,>=1.4.3; extra == "hf-xet"
|
| 49 |
+
Provides-Extra: mcp
|
| 50 |
+
Requires-Dist: mcp>=1.8.0; extra == "mcp"
|
| 51 |
+
Provides-Extra: testing
|
| 52 |
+
Requires-Dist: authlib>=1.3.2; extra == "testing"
|
| 53 |
+
Requires-Dist: fastapi; extra == "testing"
|
| 54 |
+
Requires-Dist: httpx; extra == "testing"
|
| 55 |
+
Requires-Dist: itsdangerous; extra == "testing"
|
| 56 |
+
Requires-Dist: jedi; extra == "testing"
|
| 57 |
+
Requires-Dist: Jinja2; extra == "testing"
|
| 58 |
+
Requires-Dist: pytest>=8.4.2; extra == "testing"
|
| 59 |
+
Requires-Dist: pytest-cov; extra == "testing"
|
| 60 |
+
Requires-Dist: pytest-env; extra == "testing"
|
| 61 |
+
Requires-Dist: pytest-xdist; extra == "testing"
|
| 62 |
+
Requires-Dist: pytest-vcr; extra == "testing"
|
| 63 |
+
Requires-Dist: pytest-asyncio; extra == "testing"
|
| 64 |
+
Requires-Dist: pytest-rerunfailures<16.0; extra == "testing"
|
| 65 |
+
Requires-Dist: pytest-mock; extra == "testing"
|
| 66 |
+
Requires-Dist: urllib3<2.0; extra == "testing"
|
| 67 |
+
Requires-Dist: soundfile; extra == "testing"
|
| 68 |
+
Requires-Dist: Pillow; extra == "testing"
|
| 69 |
+
Requires-Dist: numpy; extra == "testing"
|
| 70 |
+
Requires-Dist: duckdb; extra == "testing"
|
| 71 |
+
Requires-Dist: fastapi; extra == "testing"
|
| 72 |
+
Provides-Extra: gradio
|
| 73 |
+
Requires-Dist: gradio>=5.0.0; extra == "gradio"
|
| 74 |
+
Requires-Dist: requests; extra == "gradio"
|
| 75 |
+
Provides-Extra: typing
|
| 76 |
+
Requires-Dist: typing-extensions>=4.8.0; extra == "typing"
|
| 77 |
+
Requires-Dist: types-PyYAML; extra == "typing"
|
| 78 |
+
Requires-Dist: types-simplejson; extra == "typing"
|
| 79 |
+
Requires-Dist: types-toml; extra == "typing"
|
| 80 |
+
Requires-Dist: types-tqdm; extra == "typing"
|
| 81 |
+
Requires-Dist: types-urllib3; extra == "typing"
|
| 82 |
+
Provides-Extra: quality
|
| 83 |
+
Requires-Dist: ruff>=0.9.0; extra == "quality"
|
| 84 |
+
Requires-Dist: mypy==1.15.0; extra == "quality"
|
| 85 |
+
Requires-Dist: libcst>=1.4.0; extra == "quality"
|
| 86 |
+
Requires-Dist: ty; extra == "quality"
|
| 87 |
+
Provides-Extra: all
|
| 88 |
+
Requires-Dist: authlib>=1.3.2; extra == "all"
|
| 89 |
+
Requires-Dist: fastapi; extra == "all"
|
| 90 |
+
Requires-Dist: httpx; extra == "all"
|
| 91 |
+
Requires-Dist: itsdangerous; extra == "all"
|
| 92 |
+
Requires-Dist: jedi; extra == "all"
|
| 93 |
+
Requires-Dist: Jinja2; extra == "all"
|
| 94 |
+
Requires-Dist: pytest>=8.4.2; extra == "all"
|
| 95 |
+
Requires-Dist: pytest-cov; extra == "all"
|
| 96 |
+
Requires-Dist: pytest-env; extra == "all"
|
| 97 |
+
Requires-Dist: pytest-xdist; extra == "all"
|
| 98 |
+
Requires-Dist: pytest-vcr; extra == "all"
|
| 99 |
+
Requires-Dist: pytest-asyncio; extra == "all"
|
| 100 |
+
Requires-Dist: pytest-rerunfailures<16.0; extra == "all"
|
| 101 |
+
Requires-Dist: pytest-mock; extra == "all"
|
| 102 |
+
Requires-Dist: urllib3<2.0; extra == "all"
|
| 103 |
+
Requires-Dist: soundfile; extra == "all"
|
| 104 |
+
Requires-Dist: Pillow; extra == "all"
|
| 105 |
+
Requires-Dist: numpy; extra == "all"
|
| 106 |
+
Requires-Dist: duckdb; extra == "all"
|
| 107 |
+
Requires-Dist: fastapi; extra == "all"
|
| 108 |
+
Requires-Dist: ruff>=0.9.0; extra == "all"
|
| 109 |
+
Requires-Dist: mypy==1.15.0; extra == "all"
|
| 110 |
+
Requires-Dist: libcst>=1.4.0; extra == "all"
|
| 111 |
+
Requires-Dist: ty; extra == "all"
|
| 112 |
+
Requires-Dist: typing-extensions>=4.8.0; extra == "all"
|
| 113 |
+
Requires-Dist: types-PyYAML; extra == "all"
|
| 114 |
+
Requires-Dist: types-simplejson; extra == "all"
|
| 115 |
+
Requires-Dist: types-toml; extra == "all"
|
| 116 |
+
Requires-Dist: types-tqdm; extra == "all"
|
| 117 |
+
Requires-Dist: types-urllib3; extra == "all"
|
| 118 |
+
Provides-Extra: dev
|
| 119 |
+
Requires-Dist: authlib>=1.3.2; extra == "dev"
|
| 120 |
+
Requires-Dist: fastapi; extra == "dev"
|
| 121 |
+
Requires-Dist: httpx; extra == "dev"
|
| 122 |
+
Requires-Dist: itsdangerous; extra == "dev"
|
| 123 |
+
Requires-Dist: jedi; extra == "dev"
|
| 124 |
+
Requires-Dist: Jinja2; extra == "dev"
|
| 125 |
+
Requires-Dist: pytest>=8.4.2; extra == "dev"
|
| 126 |
+
Requires-Dist: pytest-cov; extra == "dev"
|
| 127 |
+
Requires-Dist: pytest-env; extra == "dev"
|
| 128 |
+
Requires-Dist: pytest-xdist; extra == "dev"
|
| 129 |
+
Requires-Dist: pytest-vcr; extra == "dev"
|
| 130 |
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
| 131 |
+
Requires-Dist: pytest-rerunfailures<16.0; extra == "dev"
|
| 132 |
+
Requires-Dist: pytest-mock; extra == "dev"
|
| 133 |
+
Requires-Dist: urllib3<2.0; extra == "dev"
|
| 134 |
+
Requires-Dist: soundfile; extra == "dev"
|
| 135 |
+
Requires-Dist: Pillow; extra == "dev"
|
| 136 |
+
Requires-Dist: numpy; extra == "dev"
|
| 137 |
+
Requires-Dist: duckdb; extra == "dev"
|
| 138 |
+
Requires-Dist: fastapi; extra == "dev"
|
| 139 |
+
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
| 140 |
+
Requires-Dist: mypy==1.15.0; extra == "dev"
|
| 141 |
+
Requires-Dist: libcst>=1.4.0; extra == "dev"
|
| 142 |
+
Requires-Dist: ty; extra == "dev"
|
| 143 |
+
Requires-Dist: typing-extensions>=4.8.0; extra == "dev"
|
| 144 |
+
Requires-Dist: types-PyYAML; extra == "dev"
|
| 145 |
+
Requires-Dist: types-simplejson; extra == "dev"
|
| 146 |
+
Requires-Dist: types-toml; extra == "dev"
|
| 147 |
+
Requires-Dist: types-tqdm; extra == "dev"
|
| 148 |
+
Requires-Dist: types-urllib3; extra == "dev"
|
| 149 |
+
Dynamic: author
|
| 150 |
+
Dynamic: author-email
|
| 151 |
+
Dynamic: classifier
|
| 152 |
+
Dynamic: description
|
| 153 |
+
Dynamic: description-content-type
|
| 154 |
+
Dynamic: home-page
|
| 155 |
+
Dynamic: keywords
|
| 156 |
+
Dynamic: license
|
| 157 |
+
Dynamic: license-file
|
| 158 |
+
Dynamic: provides-extra
|
| 159 |
+
Dynamic: requires-dist
|
| 160 |
+
Dynamic: requires-python
|
| 161 |
+
Dynamic: summary
|
| 162 |
+
|
| 163 |
+
<p align="center">
|
| 164 |
+
<picture>
|
| 165 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub-dark.svg">
|
| 166 |
+
<source media="(prefers-color-scheme: light)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg">
|
| 167 |
+
<img alt="huggingface_hub library logo" src="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg" width="352" height="59" style="max-width: 100%">
|
| 168 |
+
</picture>
|
| 169 |
+
<br/>
|
| 170 |
+
<br/>
|
| 171 |
+
</p>
|
| 172 |
+
|
| 173 |
+
<p align="center">
|
| 174 |
+
<i>The official Python client for the Huggingface Hub.</i>
|
| 175 |
+
</p>
|
| 176 |
+
|
| 177 |
+
<p align="center">
|
| 178 |
+
<a href="https://huggingface.co/docs/huggingface_hub/en/index"><img alt="Documentation" src="https://img.shields.io/website/http/huggingface.co/docs/huggingface_hub/index.svg?down_color=red&down_message=offline&up_message=online&label=doc"></a>
|
| 179 |
+
<a href="https://github.com/huggingface/huggingface_hub/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/huggingface/huggingface_hub.svg"></a>
|
| 180 |
+
<a href="https://github.com/huggingface/huggingface_hub"><img alt="PyPi version" src="https://img.shields.io/pypi/pyversions/huggingface_hub.svg"></a>
|
| 181 |
+
<a href="https://pypi.org/project/huggingface-hub"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/huggingface_hub"></a>
|
| 182 |
+
<a href="https://codecov.io/gh/huggingface/huggingface_hub"><img alt="Code coverage" src="https://codecov.io/gh/huggingface/huggingface_hub/branch/main/graph/badge.svg?token=RXP95LE2XL"></a>
|
| 183 |
+
</p>
|
| 184 |
+
|
| 185 |
+
<h4 align="center">
|
| 186 |
+
<p>
|
| 187 |
+
<b>English</b> |
|
| 188 |
+
<a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_de.md">Deutsch</a> |
|
| 189 |
+
<a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_fr.md">Français</a> |
|
| 190 |
+
<a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_hi.md">हिंदी</a> |
|
| 191 |
+
<a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_ko.md">한국어</a> |
|
| 192 |
+
<a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_cn.md">中文 (简体)</a>
|
| 193 |
+
<p>
|
| 194 |
+
</h4>
|
| 195 |
+
|
| 196 |
+
---
|
| 197 |
+
|
| 198 |
+
**Documentation**: <a href="https://hf.co/docs/huggingface_hub" target="_blank">https://hf.co/docs/huggingface_hub</a>
|
| 199 |
+
|
| 200 |
+
**Source Code**: <a href="https://github.com/huggingface/huggingface_hub" target="_blank">https://github.com/huggingface/huggingface_hub</a>
|
| 201 |
+
|
| 202 |
+
---
|
| 203 |
+
|
| 204 |
+
## Welcome to the huggingface_hub library
|
| 205 |
+
|
| 206 |
+
The `huggingface_hub` library allows you to interact with the [Hugging Face Hub](https://huggingface.co/), a platform democratizing open-source Machine Learning for creators and collaborators. Discover pre-trained models and datasets for your projects or play with the thousands of machine learning apps hosted on the Hub. You can also create and share your own models, datasets and demos with the community. The `huggingface_hub` library provides a simple way to do all these things with Python.
|
| 207 |
+
|
| 208 |
+
## Key features
|
| 209 |
+
|
| 210 |
+
- [Download files](https://huggingface.co/docs/huggingface_hub/en/guides/download) from the Hub.
|
| 211 |
+
- [Upload files](https://huggingface.co/docs/huggingface_hub/en/guides/upload) to the Hub.
|
| 212 |
+
- [Manage your repositories](https://huggingface.co/docs/huggingface_hub/en/guides/repository).
|
| 213 |
+
- [Run Inference](https://huggingface.co/docs/huggingface_hub/en/guides/inference) on deployed models.
|
| 214 |
+
- [Search](https://huggingface.co/docs/huggingface_hub/en/guides/search) for models, datasets and Spaces.
|
| 215 |
+
- [Share Model Cards](https://huggingface.co/docs/huggingface_hub/en/guides/model-cards) to document your models.
|
| 216 |
+
- [Engage with the community](https://huggingface.co/docs/huggingface_hub/en/guides/community) through PRs and comments.
|
| 217 |
+
|
| 218 |
+
## Installation
|
| 219 |
+
|
| 220 |
+
Install the `huggingface_hub` package with [pip](https://pypi.org/project/huggingface-hub/):
|
| 221 |
+
|
| 222 |
+
```bash
|
| 223 |
+
pip install huggingface_hub
|
| 224 |
+
```
|
| 225 |
+
|
| 226 |
+
If you prefer, you can also install it with [conda](https://huggingface.co/docs/huggingface_hub/en/installation#install-with-conda).
|
| 227 |
+
|
| 228 |
+
In order to keep the package minimal by default, `huggingface_hub` comes with optional dependencies useful for some use cases. For example, if you want to use the MCP module, run:
|
| 229 |
+
|
| 230 |
+
```bash
|
| 231 |
+
pip install "huggingface_hub[mcp]"
|
| 232 |
+
```
|
| 233 |
+
|
| 234 |
+
To learn more installation and optional dependencies, check out the [installation guide](https://huggingface.co/docs/huggingface_hub/en/installation).
|
| 235 |
+
|
| 236 |
+
## Quick start
|
| 237 |
+
|
| 238 |
+
### Download files
|
| 239 |
+
|
| 240 |
+
Download a single file
|
| 241 |
+
|
| 242 |
+
```py
|
| 243 |
+
from huggingface_hub import hf_hub_download
|
| 244 |
+
|
| 245 |
+
hf_hub_download(repo_id="tiiuae/falcon-7b-instruct", filename="config.json")
|
| 246 |
+
```
|
| 247 |
+
|
| 248 |
+
Or an entire repository
|
| 249 |
+
|
| 250 |
+
```py
|
| 251 |
+
from huggingface_hub import snapshot_download
|
| 252 |
+
|
| 253 |
+
snapshot_download("stabilityai/stable-diffusion-2-1")
|
| 254 |
+
```
|
| 255 |
+
|
| 256 |
+
Files will be downloaded in a local cache folder. More details in [this guide](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache).
|
| 257 |
+
|
| 258 |
+
### Login
|
| 259 |
+
|
| 260 |
+
The Hugging Face Hub uses tokens to authenticate applications (see [docs](https://huggingface.co/docs/hub/security-tokens)). To log in your machine, run the following CLI:
|
| 261 |
+
|
| 262 |
+
```bash
|
| 263 |
+
hf auth login
|
| 264 |
+
# or using an environment variable
|
| 265 |
+
hf auth login --token $HUGGINGFACE_TOKEN
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
### Create a repository
|
| 269 |
+
|
| 270 |
+
```py
|
| 271 |
+
from huggingface_hub import create_repo
|
| 272 |
+
|
| 273 |
+
create_repo(repo_id="super-cool-model")
|
| 274 |
+
```
|
| 275 |
+
|
| 276 |
+
### Upload files
|
| 277 |
+
|
| 278 |
+
Upload a single file
|
| 279 |
+
|
| 280 |
+
```py
|
| 281 |
+
from huggingface_hub import upload_file
|
| 282 |
+
|
| 283 |
+
upload_file(
|
| 284 |
+
path_or_fileobj="/home/lysandre/dummy-test/README.md",
|
| 285 |
+
path_in_repo="README.md",
|
| 286 |
+
repo_id="lysandre/test-model",
|
| 287 |
+
)
|
| 288 |
+
```
|
| 289 |
+
|
| 290 |
+
Or an entire folder
|
| 291 |
+
|
| 292 |
+
```py
|
| 293 |
+
from huggingface_hub import upload_folder
|
| 294 |
+
|
| 295 |
+
upload_folder(
|
| 296 |
+
folder_path="/path/to/local/space",
|
| 297 |
+
repo_id="username/my-cool-space",
|
| 298 |
+
repo_type="space",
|
| 299 |
+
)
|
| 300 |
+
```
|
| 301 |
+
|
| 302 |
+
For details in the [upload guide](https://huggingface.co/docs/huggingface_hub/en/guides/upload).
|
| 303 |
+
|
| 304 |
+
## Integrating to the Hub.
|
| 305 |
+
|
| 306 |
+
We're partnering with cool open source ML libraries to provide free model hosting and versioning. You can find the existing integrations [here](https://huggingface.co/docs/hub/libraries).
|
| 307 |
+
|
| 308 |
+
The advantages are:
|
| 309 |
+
|
| 310 |
+
- Free model or dataset hosting for libraries and their users.
|
| 311 |
+
- Built-in file versioning, even with very large files, thanks to a git-based approach.
|
| 312 |
+
- In-browser widgets to play with the uploaded models.
|
| 313 |
+
- Anyone can upload a new model for your library, they just need to add the corresponding tag for the model to be discoverable.
|
| 314 |
+
- Fast downloads! We use Cloudfront (a CDN) to geo-replicate downloads so they're blazing fast from anywhere on the globe.
|
| 315 |
+
- Usage stats and more features to come.
|
| 316 |
+
|
| 317 |
+
If you would like to integrate your library, feel free to open an issue to begin the discussion. We wrote a [step-by-step guide](https://huggingface.co/docs/hub/adding-a-library) with ❤️ showing how to do this integration.
|
| 318 |
+
|
| 319 |
+
## Contributions (feature requests, bugs, etc.) are super welcome 💙💚💛💜🧡❤️
|
| 320 |
+
|
| 321 |
+
Everyone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community.
|
| 322 |
+
Answering questions, helping others, reaching out and improving the documentations are immensely valuable to the community.
|
| 323 |
+
We wrote a [contribution guide](https://github.com/huggingface/huggingface_hub/blob/main/CONTRIBUTING.md) to summarize
|
| 324 |
+
how to get started to contribute to this repository.
|
.cache/pip/http-v2/4/2/6/6/d/4266da420f80fe5b2de81f440f459cda33c49a87b4c539a917582c18.body
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.1
|
| 2 |
+
Name: multiprocess
|
| 3 |
+
Version: 0.70.16
|
| 4 |
+
Summary: better multiprocessing and multithreading in Python
|
| 5 |
+
Home-page: https://github.com/uqfoundation/multiprocess
|
| 6 |
+
Download-URL: https://pypi.org/project/multiprocess/#files
|
| 7 |
+
Author: Mike McKerns
|
| 8 |
+
Author-email: mmckerns@uqfoundation.org
|
| 9 |
+
Maintainer: Mike McKerns
|
| 10 |
+
Maintainer-email: mmckerns@uqfoundation.org
|
| 11 |
+
License: BSD-3-Clause
|
| 12 |
+
Project-URL: Documentation, http://multiprocess.rtfd.io
|
| 13 |
+
Project-URL: Source Code, https://github.com/uqfoundation/multiprocess
|
| 14 |
+
Project-URL: Bug Tracker, https://github.com/uqfoundation/multiprocess/issues
|
| 15 |
+
Platform: Linux
|
| 16 |
+
Platform: Windows
|
| 17 |
+
Platform: Mac
|
| 18 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 19 |
+
Classifier: Intended Audience :: Developers
|
| 20 |
+
Classifier: Intended Audience :: Science/Research
|
| 21 |
+
Classifier: License :: OSI Approved :: BSD License
|
| 22 |
+
Classifier: Programming Language :: Python :: 3
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 24 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 25 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 26 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 27 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 28 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
| 29 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 30 |
+
Classifier: Topic :: Scientific/Engineering
|
| 31 |
+
Classifier: Topic :: Software Development
|
| 32 |
+
Requires-Python: >=3.8
|
| 33 |
+
License-File: LICENSE
|
| 34 |
+
License-File: COPYING
|
| 35 |
+
Requires-Dist: dill (>=0.3.8)
|
| 36 |
+
|
| 37 |
+
-----------------------------------------------------------------
|
| 38 |
+
multiprocess: better multiprocessing and multithreading in Python
|
| 39 |
+
-----------------------------------------------------------------
|
| 40 |
+
|
| 41 |
+
About Multiprocess
|
| 42 |
+
==================
|
| 43 |
+
|
| 44 |
+
``multiprocess`` is a fork of ``multiprocessing``. ``multiprocess`` extends ``multiprocessing`` to provide enhanced serialization, using `dill`. ``multiprocess`` leverages ``multiprocessing`` to support the spawning of processes using the API of the Python standard library's ``threading`` module. ``multiprocessing`` has been distributed as part of the standard library since Python 2.6.
|
| 45 |
+
|
| 46 |
+
``multiprocess`` is part of ``pathos``, a Python framework for heterogeneous computing.
|
| 47 |
+
``multiprocess`` is in active development, so any user feedback, bug reports, comments,
|
| 48 |
+
or suggestions are highly appreciated. A list of issues is located at https://github.com/uqfoundation/multiprocess/issues, with a legacy list maintained at https://uqfoundation.github.io/project/pathos/query.
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
Major Features
|
| 52 |
+
==============
|
| 53 |
+
|
| 54 |
+
``multiprocess`` enables:
|
| 55 |
+
|
| 56 |
+
- objects to be transferred between processes using pipes or multi-producer/multi-consumer queues
|
| 57 |
+
- objects to be shared between processes using a server process or (for simple data) shared memory
|
| 58 |
+
|
| 59 |
+
``multiprocess`` provides:
|
| 60 |
+
|
| 61 |
+
- equivalents of all the synchronization primitives in ``threading``
|
| 62 |
+
- a ``Pool`` class to facilitate submitting tasks to worker processes
|
| 63 |
+
- enhanced serialization, using ``dill``
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
Current Release
|
| 67 |
+
===============
|
| 68 |
+
|
| 69 |
+
The latest released version of ``multiprocess`` is available from:
|
| 70 |
+
|
| 71 |
+
https://pypi.org/project/multiprocess
|
| 72 |
+
|
| 73 |
+
``multiprocess`` is distributed under a 3-clause BSD license, and is a fork of ``multiprocessing``.
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
Development Version
|
| 77 |
+
===================
|
| 78 |
+
|
| 79 |
+
You can get the latest development version with all the shiny new features at:
|
| 80 |
+
|
| 81 |
+
https://github.com/uqfoundation
|
| 82 |
+
|
| 83 |
+
If you have a new contribution, please submit a pull request.
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
Installation
|
| 87 |
+
============
|
| 88 |
+
|
| 89 |
+
``multiprocess`` can be installed with ``pip``::
|
| 90 |
+
|
| 91 |
+
$ pip install multiprocess
|
| 92 |
+
|
| 93 |
+
For Python 2, a C compiler is required to build the included extension module from source. Python 3 and binary installs do not require a C compiler.
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
Requirements
|
| 97 |
+
============
|
| 98 |
+
|
| 99 |
+
``multiprocess`` requires:
|
| 100 |
+
|
| 101 |
+
- ``python`` (or ``pypy``), **>=3.8**
|
| 102 |
+
- ``setuptools``, **>=42**
|
| 103 |
+
- ``dill``, **>=0.3.8**
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
Basic Usage
|
| 107 |
+
===========
|
| 108 |
+
|
| 109 |
+
The ``multiprocess.Process`` class follows the API of ``threading.Thread``.
|
| 110 |
+
For example ::
|
| 111 |
+
|
| 112 |
+
from multiprocess import Process, Queue
|
| 113 |
+
|
| 114 |
+
def f(q):
|
| 115 |
+
q.put('hello world')
|
| 116 |
+
|
| 117 |
+
if __name__ == '__main__':
|
| 118 |
+
q = Queue()
|
| 119 |
+
p = Process(target=f, args=[q])
|
| 120 |
+
p.start()
|
| 121 |
+
print (q.get())
|
| 122 |
+
p.join()
|
| 123 |
+
|
| 124 |
+
Synchronization primitives like locks, semaphores and conditions are
|
| 125 |
+
available, for example ::
|
| 126 |
+
|
| 127 |
+
>>> from multiprocess import Condition
|
| 128 |
+
>>> c = Condition()
|
| 129 |
+
>>> print (c)
|
| 130 |
+
<Condition(<RLock(None, 0)>), 0>
|
| 131 |
+
>>> c.acquire()
|
| 132 |
+
True
|
| 133 |
+
>>> print (c)
|
| 134 |
+
<Condition(<RLock(MainProcess, 1)>), 0>
|
| 135 |
+
|
| 136 |
+
One can also use a manager to create shared objects either in shared
|
| 137 |
+
memory or in a server process, for example ::
|
| 138 |
+
|
| 139 |
+
>>> from multiprocess import Manager
|
| 140 |
+
>>> manager = Manager()
|
| 141 |
+
>>> l = manager.list(range(10))
|
| 142 |
+
>>> l.reverse()
|
| 143 |
+
>>> print (l)
|
| 144 |
+
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
| 145 |
+
>>> print (repr(l))
|
| 146 |
+
<Proxy[list] object at 0x00E1B3B0>
|
| 147 |
+
|
| 148 |
+
Tasks can be offloaded to a pool of worker processes in various ways,
|
| 149 |
+
for example ::
|
| 150 |
+
|
| 151 |
+
>>> from multiprocess import Pool
|
| 152 |
+
>>> def f(x): return x*x
|
| 153 |
+
...
|
| 154 |
+
>>> p = Pool(4)
|
| 155 |
+
>>> result = p.map_async(f, range(10))
|
| 156 |
+
>>> print (result.get(timeout=1))
|
| 157 |
+
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
| 158 |
+
|
| 159 |
+
When ``dill`` is installed, serialization is extended to most objects,
|
| 160 |
+
for example ::
|
| 161 |
+
|
| 162 |
+
>>> from multiprocess import Pool
|
| 163 |
+
>>> p = Pool(4)
|
| 164 |
+
>>> print (p.map(lambda x: (lambda y:y**2)(x) + x, xrange(10)))
|
| 165 |
+
[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
More Information
|
| 169 |
+
================
|
| 170 |
+
|
| 171 |
+
Probably the best way to get started is to look at the documentation at
|
| 172 |
+
http://multiprocess.rtfd.io. Also see ``multiprocess.tests`` for scripts that
|
| 173 |
+
demonstrate how ``multiprocess`` can be used to leverge multiple processes
|
| 174 |
+
to execute Python in parallel. You can run the test suite with
|
| 175 |
+
``python -m multiprocess.tests``. As ``multiprocess`` conforms to the
|
| 176 |
+
``multiprocessing`` interface, the examples and documentation found at
|
| 177 |
+
http://docs.python.org/library/multiprocessing.html also apply to
|
| 178 |
+
``multiprocess`` if one will ``import multiprocessing as multiprocess``.
|
| 179 |
+
See https://github.com/uqfoundation/multiprocess/tree/master/py3.12/examples
|
| 180 |
+
for a set of examples that demonstrate some basic use cases and benchmarking
|
| 181 |
+
for running Python code in parallel. Please feel free to submit a ticket on
|
| 182 |
+
github, or ask a question on stackoverflow (**@Mike McKerns**). If you would
|
| 183 |
+
like to share how you use ``multiprocess`` in your work, please send an email
|
| 184 |
+
(to **mmckerns at uqfoundation dot org**).
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
Citation
|
| 188 |
+
========
|
| 189 |
+
|
| 190 |
+
If you use ``multiprocess`` to do research that leads to publication, we ask that you
|
| 191 |
+
acknowledge use of ``multiprocess`` by citing the following in your publication::
|
| 192 |
+
|
| 193 |
+
M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis,
|
| 194 |
+
"Building a framework for predictive science", Proceedings of
|
| 195 |
+
the 10th Python in Science Conference, 2011;
|
| 196 |
+
http://arxiv.org/pdf/1202.1056
|
| 197 |
+
|
| 198 |
+
Michael McKerns and Michael Aivazis,
|
| 199 |
+
"pathos: a framework for heterogeneous computing", 2010- ;
|
| 200 |
+
https://uqfoundation.github.io/project/pathos
|
| 201 |
+
|
| 202 |
+
Please see https://uqfoundation.github.io/project/pathos or
|
| 203 |
+
http://arxiv.org/pdf/1202.1056 for further information.
|
.cache/pip/http-v2/4/3/2/5/0/432508fca4367eb16c5bda476b8ecbf96beccd650c7aea212e59eb40
ADDED
|
Binary file (1.31 kB). View file
|
|
|
.cache/pip/http-v2/4/3/2/5/0/432508fca4367eb16c5bda476b8ecbf96beccd650c7aea212e59eb40.body
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: sse-starlette
|
| 3 |
+
Version: 3.4.1
|
| 4 |
+
Summary: SSE plugin for Starlette
|
| 5 |
+
Author-email: sysid <sysid@gmx.de>
|
| 6 |
+
License-Expression: BSD-3-Clause
|
| 7 |
+
Project-URL: Source, https://github.com/sysid/sse-starlette
|
| 8 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 9 |
+
Classifier: Environment :: Web Environment
|
| 10 |
+
Classifier: Intended Audience :: Developers
|
| 11 |
+
Classifier: Operating System :: OS Independent
|
| 12 |
+
Classifier: Programming Language :: Python :: 3
|
| 13 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 14 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 15 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 16 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 17 |
+
Classifier: Topic :: Internet :: WWW/HTTP
|
| 18 |
+
Requires-Python: >=3.10
|
| 19 |
+
Description-Content-Type: text/markdown
|
| 20 |
+
License-File: LICENSE
|
| 21 |
+
License-File: AUTHORS
|
| 22 |
+
Requires-Dist: starlette>=0.49.1
|
| 23 |
+
Requires-Dist: anyio>=4.7.0
|
| 24 |
+
Provides-Extra: examples
|
| 25 |
+
Requires-Dist: uvicorn>=0.34.0; extra == "examples"
|
| 26 |
+
Requires-Dist: fastapi>=0.115.12; extra == "examples"
|
| 27 |
+
Requires-Dist: pydantic>=2; extra == "examples"
|
| 28 |
+
Provides-Extra: examples-db
|
| 29 |
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.41; extra == "examples-db"
|
| 30 |
+
Requires-Dist: aiosqlite>=0.21.0; extra == "examples-db"
|
| 31 |
+
Provides-Extra: uvicorn
|
| 32 |
+
Requires-Dist: uvicorn>=0.34.0; extra == "uvicorn"
|
| 33 |
+
Provides-Extra: granian
|
| 34 |
+
Requires-Dist: granian>=2.3.1; extra == "granian"
|
| 35 |
+
Provides-Extra: daphne
|
| 36 |
+
Requires-Dist: daphne>=4.2.0; extra == "daphne"
|
| 37 |
+
Dynamic: license-file
|
| 38 |
+
|
| 39 |
+
# Server-Sent Events for [Starlette](https://github.com/encode/starlette) and [FastAPI](https://fastapi.tiangolo.com/)
|
| 40 |
+
|
| 41 |
+
[](https://pepy.tech/project/sse-starlette)
|
| 42 |
+
[![PyPI Version][pypi-image]][pypi-url]
|
| 43 |
+
[![Build Status][build-image]][build-url]
|
| 44 |
+
|
| 45 |
+
> Background: https://sysid.github.io/server-sent-events/
|
| 46 |
+
|
| 47 |
+
Production ready Server-Sent Events implementation for Starlette and FastAPI following the [W3C SSE specification](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).
|
| 48 |
+
|
| 49 |
+
## Installation
|
| 50 |
+
|
| 51 |
+
```bash
|
| 52 |
+
pip install sse-starlette
|
| 53 |
+
uv add sse-starlette
|
| 54 |
+
|
| 55 |
+
# To run the examples (fastapi, uvicorn, pydantic)
|
| 56 |
+
uv add sse-starlette[examples]
|
| 57 |
+
|
| 58 |
+
# Example 03 also needs the DB extras (sqlalchemy, aiosqlite)
|
| 59 |
+
uv add sse-starlette[examples,examples-db]
|
| 60 |
+
|
| 61 |
+
# Recommended ASGI server
|
| 62 |
+
uv add sse-starlette[uvicorn,granian,daphne]
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
## Quick Start
|
| 66 |
+
|
| 67 |
+
```python
|
| 68 |
+
import asyncio
|
| 69 |
+
from starlette.applications import Starlette
|
| 70 |
+
from starlette.routing import Route
|
| 71 |
+
from sse_starlette import EventSourceResponse
|
| 72 |
+
|
| 73 |
+
async def generate_events():
|
| 74 |
+
for i in range(10):
|
| 75 |
+
yield {"data": f"Event {i}"}
|
| 76 |
+
await asyncio.sleep(1)
|
| 77 |
+
|
| 78 |
+
async def sse_endpoint(request):
|
| 79 |
+
return EventSourceResponse(generate_events())
|
| 80 |
+
|
| 81 |
+
app = Starlette(routes=[Route("/events", sse_endpoint)])
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
## Core Features
|
| 85 |
+
|
| 86 |
+
- **Standards Compliant**: Full SSE specification implementation
|
| 87 |
+
- **Framework Integration**: Native Starlette and FastAPI support
|
| 88 |
+
- **Async/Await**: Built on modern Python async patterns
|
| 89 |
+
- **Connection Management**: Automatic client disconnect detection
|
| 90 |
+
- **Graceful Shutdown**: Proper cleanup on server termination with cooperative shutdown support
|
| 91 |
+
- **Thread Safety**: Context-local event management for multi-threaded applications
|
| 92 |
+
- **Multi-Loop Support**: Works correctly with multiple asyncio event loops
|
| 93 |
+
|
| 94 |
+
For a detailed look at the internal task coordination, shutdown detection, and cancellation
|
| 95 |
+
flows, see [ARCHITECTURE.md](ARCHITECTURE.md).
|
| 96 |
+
|
| 97 |
+
## Key Components
|
| 98 |
+
|
| 99 |
+
### EventSourceResponse
|
| 100 |
+
|
| 101 |
+
The main response class that handles SSE streaming:
|
| 102 |
+
|
| 103 |
+
```python
|
| 104 |
+
from sse_starlette import EventSourceResponse
|
| 105 |
+
|
| 106 |
+
# Basic usage
|
| 107 |
+
async def stream_data():
|
| 108 |
+
for item in data:
|
| 109 |
+
yield {"data": item, "event": "update", "id": str(item.id)}
|
| 110 |
+
|
| 111 |
+
return EventSourceResponse(stream_data())
|
| 112 |
+
```
|
| 113 |
+
|
| 114 |
+
### ServerSentEvent
|
| 115 |
+
|
| 116 |
+
For structured event creation:
|
| 117 |
+
|
| 118 |
+
```python
|
| 119 |
+
from sse_starlette import ServerSentEvent
|
| 120 |
+
|
| 121 |
+
event = ServerSentEvent(
|
| 122 |
+
data="Custom message",
|
| 123 |
+
event="notification",
|
| 124 |
+
id="msg-123",
|
| 125 |
+
retry=5000
|
| 126 |
+
)
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
### JSONServerSentEvent
|
| 130 |
+
|
| 131 |
+
For an easy way to send json data as SSE events:
|
| 132 |
+
|
| 133 |
+
```python
|
| 134 |
+
from sse_starlette import JSONServerSentEvent
|
| 135 |
+
|
| 136 |
+
event = JSONServerSentEvent(
|
| 137 |
+
data={"field":"value"}, # Anything serializable with json.dumps
|
| 138 |
+
)
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
## Advanced Usage
|
| 142 |
+
|
| 143 |
+
### Custom Ping Configuration
|
| 144 |
+
|
| 145 |
+
```python
|
| 146 |
+
from sse_starlette import ServerSentEvent
|
| 147 |
+
|
| 148 |
+
def custom_ping():
|
| 149 |
+
return ServerSentEvent(comment="Custom ping message")
|
| 150 |
+
|
| 151 |
+
return EventSourceResponse(
|
| 152 |
+
generate_events(),
|
| 153 |
+
ping=10, # Ping every 10 seconds
|
| 154 |
+
ping_message_factory=custom_ping
|
| 155 |
+
)
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### Multi-Threaded Usage
|
| 159 |
+
|
| 160 |
+
sse-starlette now supports usage in multi-threaded applications and with multiple asyncio event loops:
|
| 161 |
+
|
| 162 |
+
```python
|
| 163 |
+
import threading
|
| 164 |
+
import asyncio
|
| 165 |
+
from sse_starlette import EventSourceResponse
|
| 166 |
+
|
| 167 |
+
def run_sse_in_thread():
|
| 168 |
+
"""SSE streaming works correctly in separate threads"""
|
| 169 |
+
loop = asyncio.new_event_loop()
|
| 170 |
+
asyncio.set_event_loop(loop)
|
| 171 |
+
|
| 172 |
+
async def thread_events():
|
| 173 |
+
for i in range(5):
|
| 174 |
+
yield {"data": f"Thread event {i}"}
|
| 175 |
+
await asyncio.sleep(1)
|
| 176 |
+
|
| 177 |
+
# This works without "Event bound to different loop" errors
|
| 178 |
+
response = EventSourceResponse(thread_events())
|
| 179 |
+
loop.close()
|
| 180 |
+
|
| 181 |
+
# Start SSE in multiple threads
|
| 182 |
+
for i in range(3):
|
| 183 |
+
thread = threading.Thread(target=run_sse_in_thread)
|
| 184 |
+
thread.start()
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
+
### Database Streaming (Thread-Safe)
|
| 188 |
+
|
| 189 |
+
```python
|
| 190 |
+
async def stream_database_results(request):
|
| 191 |
+
# CORRECT: Create session within generator context
|
| 192 |
+
async with AsyncSession() as session:
|
| 193 |
+
results = await session.execute(select(User))
|
| 194 |
+
for row in results:
|
| 195 |
+
if await request.is_disconnected():
|
| 196 |
+
break
|
| 197 |
+
yield {"data": row.name, "id": str(row.id)}
|
| 198 |
+
|
| 199 |
+
return EventSourceResponse(stream_database_results(request))
|
| 200 |
+
```
|
| 201 |
+
|
| 202 |
+
### Error Handling and Timeouts
|
| 203 |
+
|
| 204 |
+
```python
|
| 205 |
+
async def robust_stream(request):
|
| 206 |
+
try:
|
| 207 |
+
for i in range(100):
|
| 208 |
+
if await request.is_disconnected():
|
| 209 |
+
break
|
| 210 |
+
yield {"data": f"Item {i}"}
|
| 211 |
+
await asyncio.sleep(0.5)
|
| 212 |
+
except asyncio.CancelledError:
|
| 213 |
+
# Client disconnected - perform cleanup
|
| 214 |
+
raise
|
| 215 |
+
|
| 216 |
+
return EventSourceResponse(
|
| 217 |
+
robust_stream(request),
|
| 218 |
+
send_timeout=30, # Timeout hanging sends
|
| 219 |
+
headers={"Cache-Control": "no-cache"}
|
| 220 |
+
)
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
### Memory Channels Alternative
|
| 224 |
+
|
| 225 |
+
For complex data flows, use memory channels instead of generators:
|
| 226 |
+
|
| 227 |
+
```python
|
| 228 |
+
import anyio
|
| 229 |
+
from functools import partial
|
| 230 |
+
|
| 231 |
+
async def data_producer(send_channel):
|
| 232 |
+
async with send_channel:
|
| 233 |
+
for i in range(10):
|
| 234 |
+
await send_channel.send({"data": f"Item {i}"})
|
| 235 |
+
await anyio.sleep(1)
|
| 236 |
+
|
| 237 |
+
async def channel_endpoint(request):
|
| 238 |
+
send_channel, receive_channel = anyio.create_memory_object_stream(10)
|
| 239 |
+
|
| 240 |
+
return EventSourceResponse(
|
| 241 |
+
receive_channel,
|
| 242 |
+
data_sender_callable=partial(data_producer, send_channel)
|
| 243 |
+
)
|
| 244 |
+
```
|
| 245 |
+
|
| 246 |
+
### Cooperative Shutdown
|
| 247 |
+
|
| 248 |
+
By default, generators receive `CancelledError` immediately when the server shuts down. With
|
| 249 |
+
cooperative shutdown, generators can detect the shutdown signal, send farewell events to clients,
|
| 250 |
+
and exit gracefully within a configurable grace period.
|
| 251 |
+
|
| 252 |
+
```python
|
| 253 |
+
import anyio
|
| 254 |
+
from sse_starlette import EventSourceResponse
|
| 255 |
+
|
| 256 |
+
async def graceful_stream(request):
|
| 257 |
+
shutdown_event = anyio.Event()
|
| 258 |
+
|
| 259 |
+
async def generate():
|
| 260 |
+
try:
|
| 261 |
+
while not shutdown_event.is_set():
|
| 262 |
+
yield {"data": "tick"}
|
| 263 |
+
# Check for shutdown between iterations
|
| 264 |
+
with anyio.move_on_after(1.0):
|
| 265 |
+
await shutdown_event.wait()
|
| 266 |
+
# Shutdown detected — send farewell event
|
| 267 |
+
yield {"event": "shutdown", "data": "Server is shutting down"}
|
| 268 |
+
except anyio.get_cancelled_exc_class():
|
| 269 |
+
# Grace period expired — generator force-cancelled
|
| 270 |
+
raise
|
| 271 |
+
|
| 272 |
+
return EventSourceResponse(
|
| 273 |
+
generate(),
|
| 274 |
+
shutdown_event=shutdown_event, # Library sets this on shutdown
|
| 275 |
+
shutdown_grace_period=5.0, # Seconds to wait before force-cancel
|
| 276 |
+
)
|
| 277 |
+
```
|
| 278 |
+
|
| 279 |
+
**How it works:**
|
| 280 |
+
|
| 281 |
+
1. On server shutdown, the library sets your `shutdown_event`
|
| 282 |
+
2. Your generator sees the event and can yield final events
|
| 283 |
+
3. If the generator exits within `shutdown_grace_period`, shutdown is clean (no `CancelledError`)
|
| 284 |
+
4. If the generator doesn't exit in time, it is force-cancelled as before
|
| 285 |
+
|
| 286 |
+
**Important:** `shutdown_grace_period` should be less than your ASGI server's graceful shutdown
|
| 287 |
+
timeout (e.g. uvicorn's `--timeout-graceful-shutdown`), otherwise the process is killed before the
|
| 288 |
+
grace period expires.
|
| 289 |
+
|
| 290 |
+
Without `shutdown_event` (the default), behavior is identical to previous versions: immediate
|
| 291 |
+
cancellation on server shutdown.
|
| 292 |
+
|
| 293 |
+
## Configuration Options
|
| 294 |
+
|
| 295 |
+
### EventSourceResponse Parameters
|
| 296 |
+
|
| 297 |
+
| Parameter | Type | Default | Description |
|
| 298 |
+
|-----------|------|---------|-------------|
|
| 299 |
+
| `content` | `ContentStream` | Required | Async generator or iterable |
|
| 300 |
+
| `ping` | `int` | 15 | Ping interval in seconds (0 to disable) |
|
| 301 |
+
| `sep` | `str` | `"\r\n"` | Line separator (`\r\n`, `\r`, `\n`) |
|
| 302 |
+
| `send_timeout` | `float` | `None` | Send operation timeout in seconds |
|
| 303 |
+
| `headers` | `dict` | `None` | Additional HTTP headers |
|
| 304 |
+
| `ping_message_factory` | `Callable` | `None` | Custom ping message creator |
|
| 305 |
+
| `shutdown_event` | `anyio.Event` | `None` | Event set by library on server shutdown |
|
| 306 |
+
| `shutdown_grace_period` | `float` | `0` | Seconds to wait after setting `shutdown_event` before force-cancel |
|
| 307 |
+
|
| 308 |
+
### Client Disconnection
|
| 309 |
+
|
| 310 |
+
```python
|
| 311 |
+
async def monitored_stream(request):
|
| 312 |
+
events_sent = 0
|
| 313 |
+
try:
|
| 314 |
+
while events_sent < 100:
|
| 315 |
+
if await request.is_disconnected():
|
| 316 |
+
print(f"Client disconnected after {events_sent} events")
|
| 317 |
+
break
|
| 318 |
+
|
| 319 |
+
yield {"data": f"Event {events_sent}"}
|
| 320 |
+
events_sent += 1
|
| 321 |
+
await asyncio.sleep(1)
|
| 322 |
+
|
| 323 |
+
except asyncio.CancelledError:
|
| 324 |
+
print("Stream cancelled")
|
| 325 |
+
raise
|
| 326 |
+
```
|
| 327 |
+
|
| 328 |
+
## Testing
|
| 329 |
+
|
| 330 |
+
sse-starlette includes now comprehensive test isolation without manual setup. The library automatically handles event loop contexts, eliminating the need for manual state resets:
|
| 331 |
+
|
| 332 |
+
```python
|
| 333 |
+
# this is deprecated and not needed since version 3.0.0
|
| 334 |
+
import pytest
|
| 335 |
+
from sse_starlette import EventSourceResponse
|
| 336 |
+
|
| 337 |
+
@pytest.fixture
|
| 338 |
+
def reset_sse_app_status():
|
| 339 |
+
AppStatus.should_exit_event = None
|
| 340 |
+
yield
|
| 341 |
+
AppStatus.should_exit_event = None
|
| 342 |
+
```
|
| 343 |
+
|
| 344 |
+
## Production Considerations
|
| 345 |
+
|
| 346 |
+
### Performance Limits
|
| 347 |
+
|
| 348 |
+
- **Memory**: Each connection maintains a buffer. Monitor memory usage.
|
| 349 |
+
- **Connections**: Limited by system file descriptors and application design.
|
| 350 |
+
- **Network**: High-frequency events can saturate bandwidth.
|
| 351 |
+
|
| 352 |
+
### Error Recovery
|
| 353 |
+
|
| 354 |
+
Implement client-side reconnection logic:
|
| 355 |
+
|
| 356 |
+
```javascript
|
| 357 |
+
function createEventSource(url) {
|
| 358 |
+
const eventSource = new EventSource(url);
|
| 359 |
+
|
| 360 |
+
eventSource.onerror = function() {
|
| 361 |
+
setTimeout(() => {
|
| 362 |
+
createEventSource(url); // Reconnect after delay
|
| 363 |
+
}, 5000);
|
| 364 |
+
};
|
| 365 |
+
|
| 366 |
+
return eventSource;
|
| 367 |
+
}
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
## Learning Resources
|
| 371 |
+
|
| 372 |
+
### Examples Directory
|
| 373 |
+
|
| 374 |
+
The `examples/` directory contains production-ready patterns:
|
| 375 |
+
|
| 376 |
+
- **`01_basic_sse.py`**: Fundamental SSE concepts
|
| 377 |
+
- **`02_message_broadcasting.py`**: Multi-client message distribution
|
| 378 |
+
- **`03_database_streaming.py`**: Thread-safe database integration
|
| 379 |
+
- **`04_advanced_features.py`**: Custom protocols and error handling
|
| 380 |
+
|
| 381 |
+
### Demonstrations Directory
|
| 382 |
+
|
| 383 |
+
The `examples/demonstrations/` directory provides educational scenarios:
|
| 384 |
+
|
| 385 |
+
**Basic Patterns** (`basic_patterns/`):
|
| 386 |
+
- Client disconnect detection and cleanup
|
| 387 |
+
- Graceful server shutdown behavior
|
| 388 |
+
|
| 389 |
+
**Production Scenarios** (`production_scenarios/`):
|
| 390 |
+
- Load testing with concurrent clients
|
| 391 |
+
- Network interruption handling
|
| 392 |
+
|
| 393 |
+
**Advanced Patterns** (`advanced_patterns/`):
|
| 394 |
+
- Memory channels vs generators
|
| 395 |
+
- Error recovery and circuit breakers
|
| 396 |
+
- Custom protocol development
|
| 397 |
+
|
| 398 |
+
Run any demonstration:
|
| 399 |
+
```bash
|
| 400 |
+
python examples/demonstrations/basic_patterns/client_disconnect.py
|
| 401 |
+
python examples/demonstrations/production_scenarios/load_simulations.py
|
| 402 |
+
python examples/demonstrations/advanced_patterns/error_recovery.py
|
| 403 |
+
```
|
| 404 |
+
|
| 405 |
+
## Troubleshooting
|
| 406 |
+
|
| 407 |
+
### Common Issues
|
| 408 |
+
|
| 409 |
+
**Database session errors with async generators**
|
| 410 |
+
- Create database sessions inside generators, not as dependencies
|
| 411 |
+
|
| 412 |
+
**Hanging connections after client disconnect**
|
| 413 |
+
- Always check `await request.is_disconnected()` in loops
|
| 414 |
+
- Use `send_timeout` parameter to detect dead connections
|
| 415 |
+
|
| 416 |
+
If you are using Postman, please see: https://github.com/sysid/sse-starlette/issues/47#issuecomment-1445953826
|
| 417 |
+
|
| 418 |
+
### Performance Optimization
|
| 419 |
+
|
| 420 |
+
```python
|
| 421 |
+
# Connection limits
|
| 422 |
+
class ConnectionLimiter:
|
| 423 |
+
def __init__(self, max_connections=100):
|
| 424 |
+
self.semaphore = asyncio.Semaphore(max_connections)
|
| 425 |
+
|
| 426 |
+
async def limited_endpoint(self, request):
|
| 427 |
+
async with self.semaphore:
|
| 428 |
+
return EventSourceResponse(generate_events())
|
| 429 |
+
```
|
| 430 |
+
|
| 431 |
+
## Network-Level Gotchas
|
| 432 |
+
|
| 433 |
+
Network infrastructure components can buffer SSE streams, breaking real-time delivery. Here are the most common issues and solutions:
|
| 434 |
+
|
| 435 |
+
### Reverse Proxy Buffering (Nginx/Apache)
|
| 436 |
+
|
| 437 |
+
**Problem**: Nginx buffers responses by default, delaying SSE events until ~16KB accumulates.
|
| 438 |
+
|
| 439 |
+
**Solution**: Add the `X-Accel-Buffering: no` header.
|
| 440 |
+
|
| 441 |
+
**Nginx Configuration** (if you can't modify app headers):
|
| 442 |
+
```nginx
|
| 443 |
+
location /events {
|
| 444 |
+
proxy_pass http://localhost:8000;
|
| 445 |
+
proxy_http_version 1.1;
|
| 446 |
+
proxy_set_header Connection '';
|
| 447 |
+
proxy_buffering off; # Disable for this location
|
| 448 |
+
chunked_transfer_encoding off;
|
| 449 |
+
}
|
| 450 |
+
```
|
| 451 |
+
|
| 452 |
+
### CDN Issues
|
| 453 |
+
|
| 454 |
+
**Cloudflare**: Buffers ~100KB before flushing to clients, breaking real-time delivery.
|
| 455 |
+
**Akamai**: Edge servers buffer by default.
|
| 456 |
+
|
| 457 |
+
### Load Balancer Problems
|
| 458 |
+
|
| 459 |
+
**HAProxy**: Timeout settings must exceed heartbeat frequency.
|
| 460 |
+
```haproxy
|
| 461 |
+
# Ensure timeouts > ping interval
|
| 462 |
+
timeout client 60s # If ping every 45s
|
| 463 |
+
timeout server 60s
|
| 464 |
+
```
|
| 465 |
+
|
| 466 |
+
**F5 Load Balancers**: Buffer responses by default.
|
| 467 |
+
|
| 468 |
+
## Contributing
|
| 469 |
+
|
| 470 |
+
See examples and demonstrations for implementation patterns. Run tests with:
|
| 471 |
+
|
| 472 |
+
```bash
|
| 473 |
+
make test-unit # Unit tests only (default dev install)
|
| 474 |
+
make test # Unit + docker integration tests
|
| 475 |
+
make test-experimentation # Optional experimentation tests (multi-consumer load tests)
|
| 476 |
+
# Requires the `experimentation` dependency group:
|
| 477 |
+
# uv sync --group experimentation
|
| 478 |
+
```
|
| 479 |
+
|
| 480 |
+
The `experimentation` group is opt-in (kept out of the default `dev` install) to keep the
|
| 481 |
+
contributor footprint small. See `tests/experimentation/` for the tests it enables.
|
| 482 |
+
|
| 483 |
+
<!-- Badges -->
|
| 484 |
+
[pypi-image]: https://badge.fury.io/py/sse-starlette.svg
|
| 485 |
+
[pypi-url]: https://pypi.org/project/sse-starlette/
|
| 486 |
+
[build-image]: https://github.com/sysid/sse-starlette/actions/workflows/build.yml/badge.svg
|
| 487 |
+
[build-url]: https://github.com/sysid/sse-starlette/actions/workflows/build.yml
|
| 488 |
+
[coverage-image]: https://codecov.io/gh/sysid/sse-starlette/branch/master/graph/badge.svg
|
| 489 |
+
<!--[coverage-url]: https://codecov.io/gh/sysid/sse-starlette-->
|
| 490 |
+
|
.cache/pip/http-v2/4/3/4/e/4/434e4f9063597b6ecac7104d4d3128df26a47ab65e2f09d0f5f7b59d
ADDED
|
Binary file (1.29 kB). View file
|
|
|
.cache/pip/http-v2/4/3/4/e/4/434e4f9063597b6ecac7104d4d3128df26a47ab65e2f09d0f5f7b59d.body
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: typer
|
| 3 |
+
Version: 0.25.0
|
| 4 |
+
Summary: Typer, build great CLIs. Easy to code. Based on Python type hints.
|
| 5 |
+
Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
|
| 6 |
+
License-Expression: MIT
|
| 7 |
+
License-File: LICENSE
|
| 8 |
+
Classifier: Intended Audience :: Information Technology
|
| 9 |
+
Classifier: Intended Audience :: System Administrators
|
| 10 |
+
Classifier: Operating System :: OS Independent
|
| 11 |
+
Classifier: Programming Language :: Python :: 3
|
| 12 |
+
Classifier: Programming Language :: Python
|
| 13 |
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
| 14 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
| 15 |
+
Classifier: Topic :: Software Development :: Libraries
|
| 16 |
+
Classifier: Topic :: Software Development
|
| 17 |
+
Classifier: Typing :: Typed
|
| 18 |
+
Classifier: Development Status :: 4 - Beta
|
| 19 |
+
Classifier: Intended Audience :: Developers
|
| 20 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 24 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 25 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 26 |
+
Project-URL: Homepage, https://github.com/fastapi/typer
|
| 27 |
+
Project-URL: Documentation, https://typer.tiangolo.com
|
| 28 |
+
Project-URL: Repository, https://github.com/fastapi/typer
|
| 29 |
+
Project-URL: Issues, https://github.com/fastapi/typer/issues
|
| 30 |
+
Project-URL: Changelog, https://typer.tiangolo.com/release-notes/
|
| 31 |
+
Requires-Python: >=3.10
|
| 32 |
+
Requires-Dist: click>=8.2.1
|
| 33 |
+
Requires-Dist: shellingham>=1.3.0
|
| 34 |
+
Requires-Dist: rich>=13.8.0
|
| 35 |
+
Requires-Dist: annotated-doc>=0.0.2
|
| 36 |
+
Description-Content-Type: text/markdown
|
| 37 |
+
|
| 38 |
+
<p align="center">
|
| 39 |
+
<a href="https://typer.tiangolo.com"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg#only-light" alt="Typer"></a>
|
| 40 |
+
|
| 41 |
+
</p>
|
| 42 |
+
<p align="center">
|
| 43 |
+
<em>Typer, build great CLIs. Easy to code. Based on Python type hints.</em>
|
| 44 |
+
</p>
|
| 45 |
+
<p align="center">
|
| 46 |
+
<a href="https://github.com/fastapi/typer/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
| 47 |
+
<img src="https://github.com/fastapi/typer/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Test">
|
| 48 |
+
</a>
|
| 49 |
+
<a href="https://github.com/fastapi/typer/actions?query=workflow%3APublish" target="_blank">
|
| 50 |
+
<img src="https://github.com/fastapi/typer/workflows/Publish/badge.svg" alt="Publish">
|
| 51 |
+
</a>
|
| 52 |
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/typer" target="_blank">
|
| 53 |
+
<img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/typer.svg" alt="Coverage">
|
| 54 |
+
<a href="https://pypi.org/project/typer" target="_blank">
|
| 55 |
+
<img src="https://img.shields.io/pypi/v/typer?color=%2334D058&label=pypi%20package" alt="Package version">
|
| 56 |
+
</a>
|
| 57 |
+
</p>
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
**Documentation**: <a href="https://typer.tiangolo.com" target="_blank">https://typer.tiangolo.com</a>
|
| 62 |
+
|
| 63 |
+
**Source Code**: <a href="https://github.com/fastapi/typer" target="_blank">https://github.com/fastapi/typer</a>
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
Typer is a library for building <abbr title="command line interface, programs executed from a terminal">CLI</abbr> applications that users will **love using** and developers will **love creating**. Based on Python type hints.
|
| 68 |
+
|
| 69 |
+
It's also a command line tool to run scripts, automatically converting them to CLI applications.
|
| 70 |
+
|
| 71 |
+
The key features are:
|
| 72 |
+
|
| 73 |
+
* **Intuitive to write**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.
|
| 74 |
+
* **Easy to use**: It's easy to use for the final users. Automatic help, and automatic completion for all shells.
|
| 75 |
+
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
|
| 76 |
+
* **Start simple**: The simplest example adds only 2 lines of code to your app: **1 import, 1 function call**.
|
| 77 |
+
* **Grow large**: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.
|
| 78 |
+
* **Run scripts**: Typer includes a `typer` command/program that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.
|
| 79 |
+
|
| 80 |
+
## FastAPI of CLIs
|
| 81 |
+
|
| 82 |
+
**Typer** is <a href="https://fastapi.tiangolo.com" class="external-link" target="_blank">FastAPI</a>'s little sibling, it's the FastAPI of CLIs.
|
| 83 |
+
|
| 84 |
+
## Installation
|
| 85 |
+
|
| 86 |
+
Create and activate a <a href="https://typer.tiangolo.com/virtual-environments/" class="external-link" target="_blank">virtual environment</a> and then install **Typer**:
|
| 87 |
+
|
| 88 |
+
<div class="termy">
|
| 89 |
+
|
| 90 |
+
```console
|
| 91 |
+
$ pip install typer
|
| 92 |
+
---> 100%
|
| 93 |
+
Successfully installed typer rich shellingham
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
</div>
|
| 97 |
+
|
| 98 |
+
## Example
|
| 99 |
+
|
| 100 |
+
### The absolute minimum
|
| 101 |
+
|
| 102 |
+
* Create a file `main.py` with:
|
| 103 |
+
|
| 104 |
+
```Python
|
| 105 |
+
def main(name: str):
|
| 106 |
+
print(f"Hello {name}")
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
This script doesn't even use Typer internally. But you can use the `typer` command to run it as a CLI application.
|
| 110 |
+
|
| 111 |
+
### Run it
|
| 112 |
+
|
| 113 |
+
Run your application with the `typer` command:
|
| 114 |
+
|
| 115 |
+
<div class="termy">
|
| 116 |
+
|
| 117 |
+
```console
|
| 118 |
+
// Run your application
|
| 119 |
+
$ typer main.py run
|
| 120 |
+
|
| 121 |
+
// You get a nice error, you are missing NAME
|
| 122 |
+
Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME
|
| 123 |
+
Try 'typer [PATH_OR_MODULE] run --help' for help.
|
| 124 |
+
╭─ Error ───────────────────────────────────────────╮
|
| 125 |
+
│ Missing argument 'NAME'. │
|
| 126 |
+
╰───────────────────────────────────────────────────╯
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
// You get a --help for free
|
| 130 |
+
$ typer main.py run --help
|
| 131 |
+
|
| 132 |
+
Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME
|
| 133 |
+
|
| 134 |
+
Run the provided Typer app.
|
| 135 |
+
|
| 136 |
+
╭─ Arguments ───────────────────────────────────────╮
|
| 137 |
+
│ * name TEXT [default: None] [required] |
|
| 138 |
+
╰───────────────────────────────────────────────────╯
|
| 139 |
+
╭─ Options ─────────────────────────────────────────╮
|
| 140 |
+
│ --help Show this message and exit. │
|
| 141 |
+
╰───────────────────────────────────────────────────╯
|
| 142 |
+
|
| 143 |
+
// Now pass the NAME argument
|
| 144 |
+
$ typer main.py run Camila
|
| 145 |
+
|
| 146 |
+
Hello Camila
|
| 147 |
+
|
| 148 |
+
// It works! 🎉
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
</div>
|
| 152 |
+
|
| 153 |
+
This is the simplest use case, not even using Typer internally, but it can already be quite useful for simple scripts.
|
| 154 |
+
|
| 155 |
+
**Note**: auto-completion works when you create a Python package and run it with `--install-completion` or when you use the `typer` command.
|
| 156 |
+
|
| 157 |
+
## Use Typer in your code
|
| 158 |
+
|
| 159 |
+
Now let's start using Typer in your own code, update `main.py` with:
|
| 160 |
+
|
| 161 |
+
```Python
|
| 162 |
+
import typer
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def main(name: str):
|
| 166 |
+
print(f"Hello {name}")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
if __name__ == "__main__":
|
| 170 |
+
typer.run(main)
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
Now you could run it with Python directly:
|
| 174 |
+
|
| 175 |
+
<div class="termy">
|
| 176 |
+
|
| 177 |
+
```console
|
| 178 |
+
// Run your application
|
| 179 |
+
$ python main.py
|
| 180 |
+
|
| 181 |
+
// You get a nice error, you are missing NAME
|
| 182 |
+
Usage: main.py [OPTIONS] NAME
|
| 183 |
+
Try 'main.py --help' for help.
|
| 184 |
+
╭─ Error ───────────────────────────────────────────╮
|
| 185 |
+
│ Missing argument 'NAME'. │
|
| 186 |
+
╰───────────────────────────────────────────────────╯
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
// You get a --help for free
|
| 190 |
+
$ python main.py --help
|
| 191 |
+
|
| 192 |
+
Usage: main.py [OPTIONS] NAME
|
| 193 |
+
|
| 194 |
+
╭─ Arguments ───────────────────────────────────────╮
|
| 195 |
+
│ * name TEXT [default: None] [required] |
|
| 196 |
+
╰───────────────────────────────────────────────────╯
|
| 197 |
+
╭─ Options ─────────────────────────────────────────╮
|
| 198 |
+
│ --help Show this message and exit. │
|
| 199 |
+
╰───────────────────────────────────────────────────╯
|
| 200 |
+
|
| 201 |
+
// Now pass the NAME argument
|
| 202 |
+
$ python main.py Camila
|
| 203 |
+
|
| 204 |
+
Hello Camila
|
| 205 |
+
|
| 206 |
+
// It works! 🎉
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
</div>
|
| 210 |
+
|
| 211 |
+
**Note**: you can also call this same script with the `typer` command, but you don't need to.
|
| 212 |
+
|
| 213 |
+
## Example upgrade
|
| 214 |
+
|
| 215 |
+
This was the simplest example possible.
|
| 216 |
+
|
| 217 |
+
Now let's see one a bit more complex.
|
| 218 |
+
|
| 219 |
+
### An example with two subcommands
|
| 220 |
+
|
| 221 |
+
Modify the file `main.py`.
|
| 222 |
+
|
| 223 |
+
Create a `typer.Typer()` app, and create two subcommands with their parameters.
|
| 224 |
+
|
| 225 |
+
```Python hl_lines="3 6 11 20"
|
| 226 |
+
import typer
|
| 227 |
+
|
| 228 |
+
app = typer.Typer()
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
@app.command()
|
| 232 |
+
def hello(name: str):
|
| 233 |
+
print(f"Hello {name}")
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
@app.command()
|
| 237 |
+
def goodbye(name: str, formal: bool = False):
|
| 238 |
+
if formal:
|
| 239 |
+
print(f"Goodbye Ms. {name}. Have a good day.")
|
| 240 |
+
else:
|
| 241 |
+
print(f"Bye {name}!")
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
if __name__ == "__main__":
|
| 245 |
+
app()
|
| 246 |
+
```
|
| 247 |
+
|
| 248 |
+
And that will:
|
| 249 |
+
|
| 250 |
+
* Explicitly create a `typer.Typer` app.
|
| 251 |
+
* The previous `typer.run` actually creates one implicitly for you.
|
| 252 |
+
* Add two subcommands with `@app.command()`.
|
| 253 |
+
* Execute the `app()` itself, as if it was a function (instead of `typer.run`).
|
| 254 |
+
|
| 255 |
+
### Run the upgraded example
|
| 256 |
+
|
| 257 |
+
Check the new help:
|
| 258 |
+
|
| 259 |
+
<div class="termy">
|
| 260 |
+
|
| 261 |
+
```console
|
| 262 |
+
$ python main.py --help
|
| 263 |
+
|
| 264 |
+
Usage: main.py [OPTIONS] COMMAND [ARGS]...
|
| 265 |
+
|
| 266 |
+
╭─ Options ─────────────────────────────────────────╮
|
| 267 |
+
│ --install-completion Install completion │
|
| 268 |
+
│ for the current │
|
| 269 |
+
│ shell. │
|
| 270 |
+
│ --show-completion Show completion for │
|
| 271 |
+
│ the current shell, │
|
| 272 |
+
│ to copy it or │
|
| 273 |
+
│ customize the │
|
| 274 |
+
│ installation. │
|
| 275 |
+
│ --help Show this message │
|
| 276 |
+
│ and exit. │
|
| 277 |
+
╰───────────────────────────────────────────────────╯
|
| 278 |
+
╭─ Commands ────────────────────────────────────────╮
|
| 279 |
+
│ goodbye │
|
| 280 |
+
│ hello │
|
| 281 |
+
╰───────────────────────────────────────────────────╯
|
| 282 |
+
|
| 283 |
+
// When you create a package you get ✨ auto-completion ✨ for free, installed with --install-completion
|
| 284 |
+
|
| 285 |
+
// You have 2 subcommands (the 2 functions): goodbye and hello
|
| 286 |
+
```
|
| 287 |
+
|
| 288 |
+
</div>
|
| 289 |
+
|
| 290 |
+
Now check the help for the `hello` command:
|
| 291 |
+
|
| 292 |
+
<div class="termy">
|
| 293 |
+
|
| 294 |
+
```console
|
| 295 |
+
$ python main.py hello --help
|
| 296 |
+
|
| 297 |
+
Usage: main.py hello [OPTIONS] NAME
|
| 298 |
+
|
| 299 |
+
╭─ Arguments ───────────────────────────────────────╮
|
| 300 |
+
│ * name TEXT [default: None] [required] │
|
| 301 |
+
╰───────────────────────────────────────────────────╯
|
| 302 |
+
╭─ Options ─────────────────────────────────────────╮
|
| 303 |
+
│ --help Show this message and exit. │
|
| 304 |
+
╰───────────────────────────────────────────────────╯
|
| 305 |
+
```
|
| 306 |
+
|
| 307 |
+
</div>
|
| 308 |
+
|
| 309 |
+
And now check the help for the `goodbye` command:
|
| 310 |
+
|
| 311 |
+
<div class="termy">
|
| 312 |
+
|
| 313 |
+
```console
|
| 314 |
+
$ python main.py goodbye --help
|
| 315 |
+
|
| 316 |
+
Usage: main.py goodbye [OPTIONS] NAME
|
| 317 |
+
|
| 318 |
+
╭─ Arguments ───────────────────────────────────────╮
|
| 319 |
+
│ * name TEXT [default: None] [required] │
|
| 320 |
+
╰───────────────────────────────────────────────────╯
|
| 321 |
+
╭─ Options ─────────────────────────────────────────╮
|
| 322 |
+
│ --formal --no-formal [default: no-formal] │
|
| 323 |
+
│ --help Show this message │
|
| 324 |
+
│ and exit. │
|
| 325 |
+
╰───────────────────────────────────────────────────╯
|
| 326 |
+
|
| 327 |
+
// Automatic --formal and --no-formal for the bool option 🎉
|
| 328 |
+
```
|
| 329 |
+
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
Now you can try out the new command line application:
|
| 333 |
+
|
| 334 |
+
<div class="termy">
|
| 335 |
+
|
| 336 |
+
```console
|
| 337 |
+
// Use it with the hello command
|
| 338 |
+
|
| 339 |
+
$ python main.py hello Camila
|
| 340 |
+
|
| 341 |
+
Hello Camila
|
| 342 |
+
|
| 343 |
+
// And with the goodbye command
|
| 344 |
+
|
| 345 |
+
$ python main.py goodbye Camila
|
| 346 |
+
|
| 347 |
+
Bye Camila!
|
| 348 |
+
|
| 349 |
+
// And with --formal
|
| 350 |
+
|
| 351 |
+
$ python main.py goodbye --formal Camila
|
| 352 |
+
|
| 353 |
+
Goodbye Ms. Camila. Have a good day.
|
| 354 |
+
```
|
| 355 |
+
|
| 356 |
+
</div>
|
| 357 |
+
|
| 358 |
+
**Note**: If your app only has one command, by default the command name is **omitted** in usage: `python main.py Camila`. However, when there are multiple commands, you must **explicitly include the command name**: `python main.py hello Camila`. See [One or Multiple Commands](https://typer.tiangolo.com/tutorial/commands/one-or-multiple/) for more details.
|
| 359 |
+
|
| 360 |
+
### Recap
|
| 361 |
+
|
| 362 |
+
In summary, you declare **once** the types of parameters (*CLI arguments* and *CLI options*) as function parameters.
|
| 363 |
+
|
| 364 |
+
You do that with standard modern Python types.
|
| 365 |
+
|
| 366 |
+
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
|
| 367 |
+
|
| 368 |
+
Just standard **Python**.
|
| 369 |
+
|
| 370 |
+
For example, for an `int`:
|
| 371 |
+
|
| 372 |
+
```Python
|
| 373 |
+
total: int
|
| 374 |
+
```
|
| 375 |
+
|
| 376 |
+
or for a `bool` flag:
|
| 377 |
+
|
| 378 |
+
```Python
|
| 379 |
+
force: bool
|
| 380 |
+
```
|
| 381 |
+
|
| 382 |
+
And similarly for **files**, **paths**, **enums** (choices), etc. And there are tools to create **groups of subcommands**, add metadata, extra **validation**, etc.
|
| 383 |
+
|
| 384 |
+
**You get**: great editor support, including **completion** and **type checks** everywhere.
|
| 385 |
+
|
| 386 |
+
**Your users get**: automatic **`--help`**, **auto-completion** in their terminal (Bash, Zsh, Fish, PowerShell) when they install your package or when using the `typer` command.
|
| 387 |
+
|
| 388 |
+
For a more complete example including more features, see the <a href="https://typer.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
|
| 389 |
+
|
| 390 |
+
## Dependencies
|
| 391 |
+
|
| 392 |
+
**Typer** stands on the shoulders of giants. It has three required dependencies:
|
| 393 |
+
|
| 394 |
+
* <a href="https://click.palletsprojects.com/" class="external-link" target="_blank">Click</a>: a popular tool for building CLIs in Python. Typer is based on it.
|
| 395 |
+
* <a href="https://rich.readthedocs.io/en/stable/index.html" class="external-link" target="_blank"><code>rich</code></a>: to show nicely formatted errors automatically.
|
| 396 |
+
* <a href="https://github.com/sarugaku/shellingham" class="external-link" target="_blank"><code>shellingham</code></a>: to automatically detect the current shell when installing completion.
|
| 397 |
+
|
| 398 |
+
### `typer-slim`
|
| 399 |
+
|
| 400 |
+
There used to be a slimmed-down version of Typer called `typer-slim`, which didn't include the dependencies `rich` and `shellingham`, nor the `typer` command.
|
| 401 |
+
|
| 402 |
+
However, since version 0.22.0, we have stopped supporting this, and `typer-slim` now simply installs (all of) Typer.
|
| 403 |
+
|
| 404 |
+
If you want to disable Rich globally, you can set an environmental variable `TYPER_USE_RICH` to `False` or `0`.
|
| 405 |
+
|
| 406 |
+
## License
|
| 407 |
+
|
| 408 |
+
This project is licensed under the terms of the MIT license.
|
.cache/pip/http-v2/4/3/6/8/4/436846b847c9c90a13539a872e2084e3f9ca23eb93b4b1cc44b55964
ADDED
|
Binary file (1.27 kB). View file
|
|
|
.cache/pip/http-v2/4/3/6/8/4/436846b847c9c90a13539a872e2084e3f9ca23eb93b4b1cc44b55964.body
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: packaging
|
| 3 |
+
Version: 26.2
|
| 4 |
+
Summary: Core utilities for Python packages
|
| 5 |
+
Author-email: Donald Stufft <donald@stufft.io>
|
| 6 |
+
Requires-Python: >=3.8
|
| 7 |
+
Description-Content-Type: text/x-rst
|
| 8 |
+
License-Expression: Apache-2.0 OR BSD-2-Clause
|
| 9 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 10 |
+
Classifier: Intended Audience :: Developers
|
| 11 |
+
Classifier: Programming Language :: Python
|
| 12 |
+
Classifier: Programming Language :: Python :: 3
|
| 13 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 14 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 15 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 16 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 17 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 18 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 21 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
| 22 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 23 |
+
Classifier: Programming Language :: Python :: Free Threading :: 4 - Resilient
|
| 24 |
+
Classifier: Typing :: Typed
|
| 25 |
+
License-File: LICENSE
|
| 26 |
+
License-File: LICENSE.APACHE
|
| 27 |
+
License-File: LICENSE.BSD
|
| 28 |
+
Project-URL: Documentation, https://packaging.pypa.io/
|
| 29 |
+
Project-URL: Source, https://github.com/pypa/packaging
|
| 30 |
+
|
| 31 |
+
packaging
|
| 32 |
+
=========
|
| 33 |
+
|
| 34 |
+
.. start-intro
|
| 35 |
+
|
| 36 |
+
Reusable core utilities for various Python Packaging
|
| 37 |
+
`interoperability specifications <https://packaging.python.org/specifications/>`_.
|
| 38 |
+
|
| 39 |
+
This library provides utilities that implement the interoperability
|
| 40 |
+
specifications which have clearly one correct behaviour (eg: :pep:`440`)
|
| 41 |
+
or benefit greatly from having a single shared implementation (eg: :pep:`425`).
|
| 42 |
+
|
| 43 |
+
.. end-intro
|
| 44 |
+
|
| 45 |
+
The ``packaging`` project includes the following: version handling, specifiers,
|
| 46 |
+
markers, requirements, tags, metadata, lockfiles, utilities.
|
| 47 |
+
|
| 48 |
+
Documentation
|
| 49 |
+
-------------
|
| 50 |
+
|
| 51 |
+
The `documentation`_ provides information and the API for the following:
|
| 52 |
+
|
| 53 |
+
- Version Handling
|
| 54 |
+
- Specifiers
|
| 55 |
+
- Markers
|
| 56 |
+
- Licenses
|
| 57 |
+
- Requirements
|
| 58 |
+
- Metadata
|
| 59 |
+
- Tags
|
| 60 |
+
- Lockfiles (pylock)
|
| 61 |
+
- Direct URL helpers
|
| 62 |
+
- Dependency groups
|
| 63 |
+
- Errors
|
| 64 |
+
- Utilities
|
| 65 |
+
|
| 66 |
+
Installation
|
| 67 |
+
------------
|
| 68 |
+
|
| 69 |
+
Use ``pip`` to install these utilities::
|
| 70 |
+
|
| 71 |
+
pip install packaging
|
| 72 |
+
|
| 73 |
+
The ``packaging`` library uses calendar-based versioning (``YY.N``).
|
| 74 |
+
|
| 75 |
+
Discussion
|
| 76 |
+
----------
|
| 77 |
+
|
| 78 |
+
If you run into bugs, you can file them in our `issue tracker`_.
|
| 79 |
+
|
| 80 |
+
You can also join discussions on `GitHub Discussions`_ to ask questions or get involved.
|
| 81 |
+
|
| 82 |
+
.. _`documentation`: https://packaging.pypa.io/
|
| 83 |
+
.. _`issue tracker`: https://github.com/pypa/packaging/issues
|
| 84 |
+
.. _`GitHub Discussions`: https://github.com/pypa/packaging/discussions
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
Code of Conduct
|
| 88 |
+
---------------
|
| 89 |
+
|
| 90 |
+
Everyone interacting in the packaging project's codebases, issue trackers, chat
|
| 91 |
+
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
|
| 92 |
+
|
| 93 |
+
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
|
| 94 |
+
|
| 95 |
+
Contributing
|
| 96 |
+
------------
|
| 97 |
+
|
| 98 |
+
The ``CONTRIBUTING.rst`` file outlines how to contribute to this project as
|
| 99 |
+
well as how to report a potential security issue. The documentation for this
|
| 100 |
+
project also covers information about `project development`_ and `security`_.
|
| 101 |
+
|
| 102 |
+
.. _`project development`: https://packaging.pypa.io/en/latest/development/
|
| 103 |
+
.. _`security`: https://packaging.pypa.io/en/latest/security/
|
| 104 |
+
|
| 105 |
+
Project History
|
| 106 |
+
---------------
|
| 107 |
+
|
| 108 |
+
Please review the ``CHANGELOG.rst`` file or the `Changelog documentation`_ for
|
| 109 |
+
recent changes and project history.
|
| 110 |
+
|
| 111 |
+
.. _`Changelog documentation`: https://packaging.pypa.io/en/latest/changelog/
|
| 112 |
+
|
.cache/pip/http-v2/4/4/1/9/6/44196988557c6a112ae696d10605a07ed4576112a509edb0095e3b08
ADDED
|
Binary file (1.13 kB). View file
|
|
|
.cache/pip/http-v2/4/4/1/9/6/44196988557c6a112ae696d10605a07ed4576112a509edb0095e3b08.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:813d99f31275919c383aab17f0f455a04f5a429c261cc411b1e9a8f5e4aaaa05
|
| 3 |
+
size 47586063
|
.cache/pip/http-v2/4/4/6/c/5/446c514b42f8098e88d951919b55761fcef1b141bd548733adaddda2
ADDED
|
Binary file (1.2 kB). View file
|
|
|
.cache/pip/http-v2/4/4/6/c/5/446c514b42f8098e88d951919b55761fcef1b141bd548733adaddda2.body
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:27f61d13a86c3c1648dec666dd5a64f79772dd6a84b446f11866601ecab24f6f
|
| 3 |
+
size 490586
|
.cache/pip/http-v2/4/4/a/d/5/44ad51ab4fe732177892254938ca19df59a19add805fe17b3b22c658
ADDED
|
Binary file (1.19 kB). View file
|
|
|
.cache/pip/http-v2/4/4/a/d/5/44ad51ab4fe732177892254938ca19df59a19add805fe17b3b22c658.body
ADDED
|
@@ -0,0 +1,1595 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: tqdm
|
| 3 |
+
Version: 4.67.3
|
| 4 |
+
Summary: Fast, Extensible Progress Meter
|
| 5 |
+
Maintainer-email: tqdm developers <devs@tqdm.ml>
|
| 6 |
+
License: MPL-2.0 AND MIT
|
| 7 |
+
Project-URL: homepage, https://tqdm.github.io
|
| 8 |
+
Project-URL: repository, https://github.com/tqdm/tqdm
|
| 9 |
+
Project-URL: changelog, https://tqdm.github.io/releases
|
| 10 |
+
Project-URL: wiki, https://github.com/tqdm/tqdm/wiki
|
| 11 |
+
Keywords: progressbar,progressmeter,progress,bar,meter,rate,eta,console,terminal,time
|
| 12 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 13 |
+
Classifier: Environment :: Console
|
| 14 |
+
Classifier: Environment :: MacOS X
|
| 15 |
+
Classifier: Environment :: Other Environment
|
| 16 |
+
Classifier: Environment :: Win32 (MS Windows)
|
| 17 |
+
Classifier: Environment :: X11 Applications
|
| 18 |
+
Classifier: Framework :: IPython
|
| 19 |
+
Classifier: Framework :: Jupyter
|
| 20 |
+
Classifier: Intended Audience :: Developers
|
| 21 |
+
Classifier: Intended Audience :: Education
|
| 22 |
+
Classifier: Intended Audience :: End Users/Desktop
|
| 23 |
+
Classifier: Intended Audience :: Other Audience
|
| 24 |
+
Classifier: Intended Audience :: System Administrators
|
| 25 |
+
Classifier: Operating System :: MacOS
|
| 26 |
+
Classifier: Operating System :: MacOS :: MacOS X
|
| 27 |
+
Classifier: Operating System :: Microsoft
|
| 28 |
+
Classifier: Operating System :: Microsoft :: MS-DOS
|
| 29 |
+
Classifier: Operating System :: Microsoft :: Windows
|
| 30 |
+
Classifier: Operating System :: POSIX
|
| 31 |
+
Classifier: Operating System :: POSIX :: BSD
|
| 32 |
+
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
| 33 |
+
Classifier: Operating System :: POSIX :: Linux
|
| 34 |
+
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
| 35 |
+
Classifier: Operating System :: Unix
|
| 36 |
+
Classifier: Programming Language :: Python
|
| 37 |
+
Classifier: Programming Language :: Python :: 3
|
| 38 |
+
Classifier: Programming Language :: Python :: 3.7
|
| 39 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 40 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 41 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 42 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 43 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 44 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 45 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 46 |
+
Classifier: Programming Language :: Python :: Implementation
|
| 47 |
+
Classifier: Programming Language :: Python :: Implementation :: IronPython
|
| 48 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 49 |
+
Classifier: Programming Language :: Unix Shell
|
| 50 |
+
Classifier: Topic :: Desktop Environment
|
| 51 |
+
Classifier: Topic :: Education :: Computer Aided Instruction (CAI)
|
| 52 |
+
Classifier: Topic :: Education :: Testing
|
| 53 |
+
Classifier: Topic :: Office/Business
|
| 54 |
+
Classifier: Topic :: Other/Nonlisted Topic
|
| 55 |
+
Classifier: Topic :: Software Development :: Build Tools
|
| 56 |
+
Classifier: Topic :: Software Development :: Libraries
|
| 57 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
| 58 |
+
Classifier: Topic :: Software Development :: Pre-processors
|
| 59 |
+
Classifier: Topic :: Software Development :: User Interfaces
|
| 60 |
+
Classifier: Topic :: System :: Installation/Setup
|
| 61 |
+
Classifier: Topic :: System :: Logging
|
| 62 |
+
Classifier: Topic :: System :: Monitoring
|
| 63 |
+
Classifier: Topic :: System :: Shells
|
| 64 |
+
Classifier: Topic :: Terminals
|
| 65 |
+
Classifier: Topic :: Utilities
|
| 66 |
+
Requires-Python: >=3.7
|
| 67 |
+
Description-Content-Type: text/x-rst
|
| 68 |
+
License-File: LICENCE
|
| 69 |
+
Requires-Dist: colorama; platform_system == "Windows"
|
| 70 |
+
Requires-Dist: importlib_metadata; python_version < "3.8"
|
| 71 |
+
Provides-Extra: dev
|
| 72 |
+
Requires-Dist: pytest>=6; extra == "dev"
|
| 73 |
+
Requires-Dist: pytest-cov; extra == "dev"
|
| 74 |
+
Requires-Dist: pytest-timeout; extra == "dev"
|
| 75 |
+
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
| 76 |
+
Requires-Dist: nbval; extra == "dev"
|
| 77 |
+
Provides-Extra: discord
|
| 78 |
+
Requires-Dist: requests; extra == "discord"
|
| 79 |
+
Provides-Extra: slack
|
| 80 |
+
Requires-Dist: slack-sdk; extra == "slack"
|
| 81 |
+
Provides-Extra: telegram
|
| 82 |
+
Requires-Dist: requests; extra == "telegram"
|
| 83 |
+
Provides-Extra: notebook
|
| 84 |
+
Requires-Dist: ipywidgets>=6; extra == "notebook"
|
| 85 |
+
Dynamic: license-file
|
| 86 |
+
|
| 87 |
+
|Logo|
|
| 88 |
+
|
| 89 |
+
tqdm
|
| 90 |
+
====
|
| 91 |
+
|
| 92 |
+
|Py-Versions| |Versions| |Conda-Forge-Status| |Docker| |Snapcraft|
|
| 93 |
+
|
| 94 |
+
|Build-Status| |Coverage-Status| |Branch-Coverage-Status| |Codacy-Grade| |Libraries-Rank| |PyPI-Downloads|
|
| 95 |
+
|
| 96 |
+
|LICENCE| |OpenHub-Status| |binder-demo| |awesome-python|
|
| 97 |
+
|
| 98 |
+
``tqdm`` derives from the Arabic word *taqaddum* (تقدّم) which can mean "progress,"
|
| 99 |
+
and is an abbreviation for "I love you so much" in Spanish (*te quiero demasiado*).
|
| 100 |
+
|
| 101 |
+
Instantly make your loops show a smart progress meter - just wrap any
|
| 102 |
+
iterable with ``tqdm(iterable)``, and you're done!
|
| 103 |
+
|
| 104 |
+
.. code:: python
|
| 105 |
+
|
| 106 |
+
from tqdm import tqdm
|
| 107 |
+
for i in tqdm(range(10000)):
|
| 108 |
+
...
|
| 109 |
+
|
| 110 |
+
``76%|████████████████████████ | 7568/10000 [00:33<00:10, 229.00it/s]``
|
| 111 |
+
|
| 112 |
+
``trange(N)`` can be also used as a convenient shortcut for
|
| 113 |
+
``tqdm(range(N))``.
|
| 114 |
+
|
| 115 |
+
|Screenshot|
|
| 116 |
+
|Video| |Slides| |Merch|
|
| 117 |
+
|
| 118 |
+
It can also be executed as a module with pipes:
|
| 119 |
+
|
| 120 |
+
.. code:: sh
|
| 121 |
+
|
| 122 |
+
$ seq 9999999 | tqdm --bytes | wc -l
|
| 123 |
+
75.2MB [00:00, 217MB/s]
|
| 124 |
+
9999999
|
| 125 |
+
|
| 126 |
+
$ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
|
| 127 |
+
> backup.tgz
|
| 128 |
+
32%|██████████▍ | 8.89G/27.9G [00:42<01:31, 223MB/s]
|
| 129 |
+
|
| 130 |
+
Overhead is low -- about 60ns per iteration (80ns with ``tqdm.gui``), and is
|
| 131 |
+
unit tested against performance regression.
|
| 132 |
+
By comparison, the well-established
|
| 133 |
+
`ProgressBar <https://github.com/niltonvolpato/python-progressbar>`__ has
|
| 134 |
+
an 800ns/iter overhead.
|
| 135 |
+
|
| 136 |
+
In addition to its low overhead, ``tqdm`` uses smart algorithms to predict
|
| 137 |
+
the remaining time and to skip unnecessary iteration displays, which allows
|
| 138 |
+
for a negligible overhead in most cases.
|
| 139 |
+
|
| 140 |
+
``tqdm`` works on any platform
|
| 141 |
+
(Linux, Windows, Mac, FreeBSD, NetBSD, Solaris/SunOS),
|
| 142 |
+
in any console or in a GUI, and is also friendly with IPython/Jupyter notebooks.
|
| 143 |
+
|
| 144 |
+
``tqdm`` does not require any dependencies (not even ``curses``!), just
|
| 145 |
+
Python and an environment supporting ``carriage return \r`` and
|
| 146 |
+
``line feed \n`` control characters.
|
| 147 |
+
|
| 148 |
+
------------------------------------------
|
| 149 |
+
|
| 150 |
+
.. contents:: Table of contents
|
| 151 |
+
:backlinks: top
|
| 152 |
+
:local:
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
Installation
|
| 156 |
+
------------
|
| 157 |
+
|
| 158 |
+
Latest PyPI stable release
|
| 159 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 160 |
+
|
| 161 |
+
|Versions| |PyPI-Downloads| |Libraries-Dependents|
|
| 162 |
+
|
| 163 |
+
.. code:: sh
|
| 164 |
+
|
| 165 |
+
pip install tqdm
|
| 166 |
+
|
| 167 |
+
Latest development release on GitHub
|
| 168 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 169 |
+
|
| 170 |
+
|GitHub-Status| |GitHub-Stars| |GitHub-Commits| |GitHub-Forks| |GitHub-Updated|
|
| 171 |
+
|
| 172 |
+
Pull and install pre-release ``devel`` branch:
|
| 173 |
+
|
| 174 |
+
.. code:: sh
|
| 175 |
+
|
| 176 |
+
pip install "git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm"
|
| 177 |
+
|
| 178 |
+
Latest Conda release
|
| 179 |
+
~~~~~~~~~~~~~~~~~~~~
|
| 180 |
+
|
| 181 |
+
|Conda-Forge-Status|
|
| 182 |
+
|
| 183 |
+
.. code:: sh
|
| 184 |
+
|
| 185 |
+
conda install -c conda-forge tqdm
|
| 186 |
+
|
| 187 |
+
Latest Snapcraft release
|
| 188 |
+
~~~~~~~~~~~~~~~~~~~~~~~~
|
| 189 |
+
|
| 190 |
+
|Snapcraft|
|
| 191 |
+
|
| 192 |
+
There are 3 channels to choose from:
|
| 193 |
+
|
| 194 |
+
.. code:: sh
|
| 195 |
+
|
| 196 |
+
snap install tqdm # implies --stable, i.e. latest tagged release
|
| 197 |
+
snap install tqdm --candidate # master branch
|
| 198 |
+
snap install tqdm --edge # devel branch
|
| 199 |
+
|
| 200 |
+
Note that ``snap`` binaries are purely for CLI use (not ``import``-able), and
|
| 201 |
+
automatically set up ``bash`` tab-completion.
|
| 202 |
+
|
| 203 |
+
Latest Docker release
|
| 204 |
+
~~~~~~~~~~~~~~~~~~~~~
|
| 205 |
+
|
| 206 |
+
|Docker|
|
| 207 |
+
|
| 208 |
+
.. code:: sh
|
| 209 |
+
|
| 210 |
+
docker pull tqdm/tqdm
|
| 211 |
+
docker run -i --rm tqdm/tqdm --help
|
| 212 |
+
|
| 213 |
+
Other
|
| 214 |
+
~~~~~
|
| 215 |
+
|
| 216 |
+
There are other (unofficial) places where ``tqdm`` may be downloaded, particularly for CLI use:
|
| 217 |
+
|
| 218 |
+
|Repology|
|
| 219 |
+
|
| 220 |
+
.. |Repology| image:: https://repology.org/badge/tiny-repos/python:tqdm.svg
|
| 221 |
+
:target: https://repology.org/project/python:tqdm/versions
|
| 222 |
+
|
| 223 |
+
Changelog
|
| 224 |
+
---------
|
| 225 |
+
|
| 226 |
+
The list of all changes is available either on GitHub's Releases:
|
| 227 |
+
|GitHub-Status|, on the
|
| 228 |
+
`wiki <https://github.com/tqdm/tqdm/wiki/Releases>`__, or on the
|
| 229 |
+
`website <https://tqdm.github.io/releases>`__.
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
Usage
|
| 233 |
+
-----
|
| 234 |
+
|
| 235 |
+
``tqdm`` is very versatile and can be used in a number of ways.
|
| 236 |
+
The three main ones are given below.
|
| 237 |
+
|
| 238 |
+
Iterable-based
|
| 239 |
+
~~~~~~~~~~~~~~
|
| 240 |
+
|
| 241 |
+
Wrap ``tqdm()`` around any iterable:
|
| 242 |
+
|
| 243 |
+
.. code:: python
|
| 244 |
+
|
| 245 |
+
from tqdm import tqdm
|
| 246 |
+
from time import sleep
|
| 247 |
+
|
| 248 |
+
text = ""
|
| 249 |
+
for char in tqdm(["a", "b", "c", "d"]):
|
| 250 |
+
sleep(0.25)
|
| 251 |
+
text = text + char
|
| 252 |
+
|
| 253 |
+
``trange(i)`` is a special optimised instance of ``tqdm(range(i))``:
|
| 254 |
+
|
| 255 |
+
.. code:: python
|
| 256 |
+
|
| 257 |
+
from tqdm import trange
|
| 258 |
+
|
| 259 |
+
for i in trange(100):
|
| 260 |
+
sleep(0.01)
|
| 261 |
+
|
| 262 |
+
Instantiation outside of the loop allows for manual control over ``tqdm()``:
|
| 263 |
+
|
| 264 |
+
.. code:: python
|
| 265 |
+
|
| 266 |
+
pbar = tqdm(["a", "b", "c", "d"])
|
| 267 |
+
for char in pbar:
|
| 268 |
+
sleep(0.25)
|
| 269 |
+
pbar.set_description("Processing %s" % char)
|
| 270 |
+
|
| 271 |
+
Manual
|
| 272 |
+
~~~~~~
|
| 273 |
+
|
| 274 |
+
Manual control of ``tqdm()`` updates using a ``with`` statement:
|
| 275 |
+
|
| 276 |
+
.. code:: python
|
| 277 |
+
|
| 278 |
+
with tqdm(total=100) as pbar:
|
| 279 |
+
for i in range(10):
|
| 280 |
+
sleep(0.1)
|
| 281 |
+
pbar.update(10)
|
| 282 |
+
|
| 283 |
+
If the optional variable ``total`` (or an iterable with ``len()``) is
|
| 284 |
+
provided, predictive stats are displayed.
|
| 285 |
+
|
| 286 |
+
``with`` is also optional (you can just assign ``tqdm()`` to a variable,
|
| 287 |
+
but in this case don't forget to ``del`` or ``close()`` at the end:
|
| 288 |
+
|
| 289 |
+
.. code:: python
|
| 290 |
+
|
| 291 |
+
pbar = tqdm(total=100)
|
| 292 |
+
for i in range(10):
|
| 293 |
+
sleep(0.1)
|
| 294 |
+
pbar.update(10)
|
| 295 |
+
pbar.close()
|
| 296 |
+
|
| 297 |
+
Module
|
| 298 |
+
~~~~~~
|
| 299 |
+
|
| 300 |
+
Perhaps the most wonderful use of ``tqdm`` is in a script or on the command
|
| 301 |
+
line. Simply inserting ``tqdm`` (or ``python -m tqdm``) between pipes will pass
|
| 302 |
+
through all ``stdin`` to ``stdout`` while printing progress to ``stderr``.
|
| 303 |
+
|
| 304 |
+
The example below demonstrate counting the number of lines in all Python files
|
| 305 |
+
in the current directory, with timing information included.
|
| 306 |
+
|
| 307 |
+
.. code:: sh
|
| 308 |
+
|
| 309 |
+
$ time find . -name '*.py' -type f -exec cat \{} \; | wc -l
|
| 310 |
+
857365
|
| 311 |
+
|
| 312 |
+
real 0m3.458s
|
| 313 |
+
user 0m0.274s
|
| 314 |
+
sys 0m3.325s
|
| 315 |
+
|
| 316 |
+
$ time find . -name '*.py' -type f -exec cat \{} \; | tqdm | wc -l
|
| 317 |
+
857366it [00:03, 246471.31it/s]
|
| 318 |
+
857365
|
| 319 |
+
|
| 320 |
+
real 0m3.585s
|
| 321 |
+
user 0m0.862s
|
| 322 |
+
sys 0m3.358s
|
| 323 |
+
|
| 324 |
+
Note that the usual arguments for ``tqdm`` can also be specified.
|
| 325 |
+
|
| 326 |
+
.. code:: sh
|
| 327 |
+
|
| 328 |
+
$ find . -name '*.py' -type f -exec cat \{} \; |
|
| 329 |
+
tqdm --unit loc --unit_scale --total 857366 >> /dev/null
|
| 330 |
+
100%|█████████████████████████████████| 857K/857K [00:04<00:00, 246Kloc/s]
|
| 331 |
+
|
| 332 |
+
Backing up a large directory?
|
| 333 |
+
|
| 334 |
+
.. code:: sh
|
| 335 |
+
|
| 336 |
+
$ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
|
| 337 |
+
> backup.tgz
|
| 338 |
+
44%|██████████████▊ | 153M/352M [00:14<00:18, 11.0MB/s]
|
| 339 |
+
|
| 340 |
+
This can be beautified further:
|
| 341 |
+
|
| 342 |
+
.. code:: sh
|
| 343 |
+
|
| 344 |
+
$ BYTES=$(du -sb docs/ | cut -f1)
|
| 345 |
+
$ tar -cf - docs/ \
|
| 346 |
+
| tqdm --bytes --total "$BYTES" --desc Processing | gzip \
|
| 347 |
+
| tqdm --bytes --total "$BYTES" --desc Compressed --position 1 \
|
| 348 |
+
> ~/backup.tgz
|
| 349 |
+
Processing: 100%|██████████████████████| 352M/352M [00:14<00:00, 30.2MB/s]
|
| 350 |
+
Compressed: 42%|█████████▎ | 148M/352M [00:14<00:19, 10.9MB/s]
|
| 351 |
+
|
| 352 |
+
Or done on a file level using 7-zip:
|
| 353 |
+
|
| 354 |
+
.. code:: sh
|
| 355 |
+
|
| 356 |
+
$ 7z a -bd -r backup.7z docs/ | grep Compressing \
|
| 357 |
+
| tqdm --total $(find docs/ -type f | wc -l) --unit files \
|
| 358 |
+
| grep -v Compressing
|
| 359 |
+
100%|██████████████████████████▉| 15327/15327 [01:00<00:00, 712.96files/s]
|
| 360 |
+
|
| 361 |
+
Pre-existing CLI programs already outputting basic progress information will
|
| 362 |
+
benefit from ``tqdm``'s ``--update`` and ``--update_to`` flags:
|
| 363 |
+
|
| 364 |
+
.. code:: sh
|
| 365 |
+
|
| 366 |
+
$ seq 3 0.1 5 | tqdm --total 5 --update_to --null
|
| 367 |
+
100%|████████████████████████████████████| 5.0/5 [00:00<00:00, 9673.21it/s]
|
| 368 |
+
$ seq 10 | tqdm --update --null # 1 + 2 + ... + 10 = 55 iterations
|
| 369 |
+
55it [00:00, 90006.52it/s]
|
| 370 |
+
|
| 371 |
+
FAQ and Known Issues
|
| 372 |
+
--------------------
|
| 373 |
+
|
| 374 |
+
|GitHub-Issues|
|
| 375 |
+
|
| 376 |
+
The most common issues relate to excessive output on multiple lines, instead
|
| 377 |
+
of a neat one-line progress bar.
|
| 378 |
+
|
| 379 |
+
- Consoles in general: require support for carriage return (``CR``, ``\r``).
|
| 380 |
+
|
| 381 |
+
* Some cloud logging consoles which don't support ``\r`` properly
|
| 382 |
+
(`cloudwatch <https://github.com/tqdm/tqdm/issues/966>`__,
|
| 383 |
+
`K8s <https://github.com/tqdm/tqdm/issues/1319>`__) may benefit from
|
| 384 |
+
``export TQDM_POSITION=-1``.
|
| 385 |
+
|
| 386 |
+
- Nested progress bars:
|
| 387 |
+
|
| 388 |
+
* Consoles in general: require support for moving cursors up to the
|
| 389 |
+
previous line. For example,
|
| 390 |
+
`IDLE <https://github.com/tqdm/tqdm/issues/191#issuecomment-230168030>`__,
|
| 391 |
+
`ConEmu <https://github.com/tqdm/tqdm/issues/254>`__ and
|
| 392 |
+
`PyCharm <https://github.com/tqdm/tqdm/issues/203>`__ (also
|
| 393 |
+
`here <https://github.com/tqdm/tqdm/issues/208>`__,
|
| 394 |
+
`here <https://github.com/tqdm/tqdm/issues/307>`__, and
|
| 395 |
+
`here <https://github.com/tqdm/tqdm/issues/454#issuecomment-335416815>`__)
|
| 396 |
+
lack full support.
|
| 397 |
+
* Windows: additionally may require the Python module ``colorama``
|
| 398 |
+
to ensure nested bars stay within their respective lines.
|
| 399 |
+
|
| 400 |
+
- Unicode:
|
| 401 |
+
|
| 402 |
+
* Environments which report that they support unicode will have solid smooth
|
| 403 |
+
progressbars. The fallback is an ``ascii``-only bar.
|
| 404 |
+
* Windows consoles often only partially support unicode and thus
|
| 405 |
+
`often require explicit ascii=True <https://github.com/tqdm/tqdm/issues/454#issuecomment-335416815>`__
|
| 406 |
+
(also `here <https://github.com/tqdm/tqdm/issues/499>`__). This is due to
|
| 407 |
+
either normal-width unicode characters being incorrectly displayed as
|
| 408 |
+
"wide", or some unicode characters not rendering.
|
| 409 |
+
|
| 410 |
+
- Wrapping generators:
|
| 411 |
+
|
| 412 |
+
* Generator wrapper functions tend to hide the length of iterables.
|
| 413 |
+
``tqdm`` does not.
|
| 414 |
+
* Replace ``tqdm(enumerate(...))`` with ``enumerate(tqdm(...))`` or
|
| 415 |
+
``tqdm(enumerate(x), total=len(x), ...)``.
|
| 416 |
+
The same applies to ``numpy.ndenumerate``.
|
| 417 |
+
* Replace ``tqdm(zip(a, b))`` with ``zip(tqdm(a), b)`` or even
|
| 418 |
+
``zip(tqdm(a), tqdm(b))``.
|
| 419 |
+
* The same applies to ``itertools``.
|
| 420 |
+
* Some useful convenience functions can be found under ``tqdm.contrib``.
|
| 421 |
+
|
| 422 |
+
- `No intermediate output in docker-compose <https://github.com/tqdm/tqdm/issues/771>`__:
|
| 423 |
+
use ``docker-compose run`` instead of ``docker-compose up`` and ``tty: true``.
|
| 424 |
+
|
| 425 |
+
- Overriding defaults via environment variables:
|
| 426 |
+
e.g. in CI/cloud jobs, ``export TQDM_MININTERVAL=5`` to avoid log spam.
|
| 427 |
+
This override logic is handled by the ``tqdm.utils.envwrap`` decorator
|
| 428 |
+
(useful independent of ``tqdm``).
|
| 429 |
+
|
| 430 |
+
If you come across any other difficulties, browse and file |GitHub-Issues|.
|
| 431 |
+
|
| 432 |
+
Documentation
|
| 433 |
+
-------------
|
| 434 |
+
|
| 435 |
+
|Py-Versions| |README-Hits| (Since 19 May 2016)
|
| 436 |
+
|
| 437 |
+
.. code:: python
|
| 438 |
+
|
| 439 |
+
class tqdm():
|
| 440 |
+
"""
|
| 441 |
+
Decorate an iterable object, returning an iterator which acts exactly
|
| 442 |
+
like the original iterable, but prints a dynamically updating
|
| 443 |
+
progressbar every time a value is requested.
|
| 444 |
+
"""
|
| 445 |
+
|
| 446 |
+
@envwrap("TQDM_") # override defaults via env vars
|
| 447 |
+
def __init__(self, iterable=None, desc=None, total=None, leave=True,
|
| 448 |
+
file=None, ncols=None, mininterval=0.1,
|
| 449 |
+
maxinterval=10.0, miniters=None, ascii=None, disable=False,
|
| 450 |
+
unit='it', unit_scale=False, dynamic_ncols=False,
|
| 451 |
+
smoothing=0.3, bar_format=None, initial=0, position=None,
|
| 452 |
+
postfix=None, unit_divisor=1000, write_bytes=False,
|
| 453 |
+
lock_args=None, nrows=None, colour=None, delay=0):
|
| 454 |
+
|
| 455 |
+
Parameters
|
| 456 |
+
~~~~~~~~~~
|
| 457 |
+
|
| 458 |
+
* iterable : iterable, optional
|
| 459 |
+
Iterable to decorate with a progressbar.
|
| 460 |
+
Leave blank to manually manage the updates.
|
| 461 |
+
* desc : str, optional
|
| 462 |
+
Prefix for the progressbar.
|
| 463 |
+
* total : int or float, optional
|
| 464 |
+
The number of expected iterations. If unspecified,
|
| 465 |
+
len(iterable) is used if possible. If float("inf") or as a last
|
| 466 |
+
resort, only basic progress statistics are displayed
|
| 467 |
+
(no ETA, no progressbar).
|
| 468 |
+
If ``gui`` is True and this parameter needs subsequent updating,
|
| 469 |
+
specify an initial arbitrary large positive number,
|
| 470 |
+
e.g. 9e9.
|
| 471 |
+
* leave : bool, optional
|
| 472 |
+
If [default: True], keeps all traces of the progressbar
|
| 473 |
+
upon termination of iteration.
|
| 474 |
+
If ``None``, will leave only if ``position`` is ``0``.
|
| 475 |
+
* file : ``io.TextIOWrapper`` or ``io.StringIO``, optional
|
| 476 |
+
Specifies where to output the progress messages
|
| 477 |
+
(default: sys.stderr). Uses ``file.write(str)`` and ``file.flush()``
|
| 478 |
+
methods. For encoding, see ``write_bytes``.
|
| 479 |
+
* ncols : int, optional
|
| 480 |
+
The width of the entire output message. If specified,
|
| 481 |
+
dynamically resizes the progressbar to stay within this bound.
|
| 482 |
+
If unspecified, attempts to use environment width. The
|
| 483 |
+
fallback is a meter width of 10 and no limit for the counter and
|
| 484 |
+
statistics. If 0, will not print any meter (only stats).
|
| 485 |
+
* mininterval : float, optional
|
| 486 |
+
Minimum progress display update interval [default: 0.1] seconds.
|
| 487 |
+
* maxinterval : float, optional
|
| 488 |
+
Maximum progress display update interval [default: 10] seconds.
|
| 489 |
+
Automatically adjusts ``miniters`` to correspond to ``mininterval``
|
| 490 |
+
after long display update lag. Only works if ``dynamic_miniters``
|
| 491 |
+
or monitor thread is enabled.
|
| 492 |
+
* miniters : int or float, optional
|
| 493 |
+
Minimum progress display update interval, in iterations.
|
| 494 |
+
If 0 and ``dynamic_miniters``, will automatically adjust to equal
|
| 495 |
+
``mininterval`` (more CPU efficient, good for tight loops).
|
| 496 |
+
If > 0, will skip display of specified number of iterations.
|
| 497 |
+
Tweak this and ``mininterval`` to get very efficient loops.
|
| 498 |
+
If your progress is erratic with both fast and slow iterations
|
| 499 |
+
(network, skipping items, etc) you should set miniters=1.
|
| 500 |
+
* ascii : bool or str, optional
|
| 501 |
+
If unspecified or False, use unicode (smooth blocks) to fill
|
| 502 |
+
the meter. The fallback is to use ASCII characters " 123456789#".
|
| 503 |
+
* disable : bool, optional
|
| 504 |
+
Whether to disable the entire progressbar wrapper
|
| 505 |
+
[default: False]. If set to None, disable on non-TTY.
|
| 506 |
+
* unit : str, optional
|
| 507 |
+
String that will be used to define the unit of each iteration
|
| 508 |
+
[default: it].
|
| 509 |
+
* unit_scale : bool or int or float, optional
|
| 510 |
+
If 1 or True, the number of iterations will be reduced/scaled
|
| 511 |
+
automatically and a metric prefix following the
|
| 512 |
+
International System of Units standard will be added
|
| 513 |
+
(kilo, mega, etc.) [default: False]. If any other non-zero
|
| 514 |
+
number, will scale ``total`` and ``n``.
|
| 515 |
+
* dynamic_ncols : bool, optional
|
| 516 |
+
If set, constantly alters ``ncols`` and ``nrows`` to the
|
| 517 |
+
environment (allowing for window resizes) [default: False].
|
| 518 |
+
* smoothing : float, optional
|
| 519 |
+
Exponential moving average smoothing factor for speed estimates
|
| 520 |
+
(ignored in GUI mode). Ranges from 0 (average speed) to 1
|
| 521 |
+
(current/instantaneous speed) [default: 0.3].
|
| 522 |
+
* bar_format : str, optional
|
| 523 |
+
Specify a custom bar string formatting. May impact performance.
|
| 524 |
+
[default: '{l_bar}{bar}{r_bar}'], where
|
| 525 |
+
l_bar='{desc}: {percentage:3.0f}%|' and
|
| 526 |
+
r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
|
| 527 |
+
'{rate_fmt}{postfix}]'
|
| 528 |
+
Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,
|
| 529 |
+
percentage, elapsed, elapsed_s, ncols, nrows, desc, unit,
|
| 530 |
+
rate, rate_fmt, rate_noinv, rate_noinv_fmt,
|
| 531 |
+
rate_inv, rate_inv_fmt, postfix, unit_divisor,
|
| 532 |
+
remaining, remaining_s, eta.
|
| 533 |
+
Note that a trailing ": " is automatically removed after {desc}
|
| 534 |
+
if the latter is empty.
|
| 535 |
+
* initial : int or float, optional
|
| 536 |
+
The initial counter value. Useful when restarting a progress
|
| 537 |
+
bar [default: 0]. If using float, consider specifying ``{n:.3f}``
|
| 538 |
+
or similar in ``bar_format``, or specifying ``unit_scale``.
|
| 539 |
+
* position : int, optional
|
| 540 |
+
Specify the line offset to print this bar (starting from 0)
|
| 541 |
+
Automatic if unspecified.
|
| 542 |
+
Useful to manage multiple bars at once (eg, from threads).
|
| 543 |
+
* postfix : dict or ``*``, optional
|
| 544 |
+
Specify additional stats to display at the end of the bar.
|
| 545 |
+
Calls ``set_postfix(**postfix)`` if possible (dict).
|
| 546 |
+
* unit_divisor : float, optional
|
| 547 |
+
[default: 1000], ignored unless ``unit_scale`` is True.
|
| 548 |
+
* write_bytes : bool, optional
|
| 549 |
+
Whether to write bytes. If (default: False) will write unicode.
|
| 550 |
+
* lock_args : tuple, optional
|
| 551 |
+
Passed to ``refresh`` for intermediate output
|
| 552 |
+
(initialisation, iterating, and updating).
|
| 553 |
+
* nrows : int, optional
|
| 554 |
+
The screen height. If specified, hides nested bars outside this
|
| 555 |
+
bound. If unspecified, attempts to use environment height.
|
| 556 |
+
The fallback is 20.
|
| 557 |
+
* colour : str, optional
|
| 558 |
+
Bar colour (e.g. 'green', '#00ff00').
|
| 559 |
+
* delay : float, optional
|
| 560 |
+
Don't display until [default: 0] seconds have elapsed.
|
| 561 |
+
|
| 562 |
+
Extra CLI Options
|
| 563 |
+
~~~~~~~~~~~~~~~~~
|
| 564 |
+
|
| 565 |
+
* delim : chr, optional
|
| 566 |
+
Delimiting character [default: '\n']. Use '\0' for null.
|
| 567 |
+
N.B.: on Windows systems, Python converts '\n' to '\r\n'.
|
| 568 |
+
* buf_size : int, optional
|
| 569 |
+
String buffer size in bytes [default: 256]
|
| 570 |
+
used when ``delim`` is specified.
|
| 571 |
+
* bytes : bool, optional
|
| 572 |
+
If true, will count bytes, ignore ``delim``, and default
|
| 573 |
+
``unit_scale`` to True, ``unit_divisor`` to 1024, and ``unit`` to 'B'.
|
| 574 |
+
* tee : bool, optional
|
| 575 |
+
If true, passes ``stdin`` to both ``stderr`` and ``stdout``.
|
| 576 |
+
* update : bool, optional
|
| 577 |
+
If true, will treat input as newly elapsed iterations,
|
| 578 |
+
i.e. numbers to pass to ``update()``. Note that this is slow
|
| 579 |
+
(~2e5 it/s) since every input must be decoded as a number.
|
| 580 |
+
* update_to : bool, optional
|
| 581 |
+
If true, will treat input as total elapsed iterations,
|
| 582 |
+
i.e. numbers to assign to ``self.n``. Note that this is slow
|
| 583 |
+
(~2e5 it/s) since every input must be decoded as a number.
|
| 584 |
+
* null : bool, optional
|
| 585 |
+
If true, will discard input (no stdout).
|
| 586 |
+
* manpath : str, optional
|
| 587 |
+
Directory in which to install tqdm man pages.
|
| 588 |
+
* comppath : str, optional
|
| 589 |
+
Directory in which to place tqdm completion.
|
| 590 |
+
* log : str, optional
|
| 591 |
+
CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET.
|
| 592 |
+
|
| 593 |
+
Returns
|
| 594 |
+
~~~~~~~
|
| 595 |
+
|
| 596 |
+
* out : decorated iterator.
|
| 597 |
+
|
| 598 |
+
.. code:: python
|
| 599 |
+
|
| 600 |
+
class tqdm():
|
| 601 |
+
def update(self, n=1):
|
| 602 |
+
"""
|
| 603 |
+
Manually update the progress bar, useful for streams
|
| 604 |
+
such as reading files.
|
| 605 |
+
E.g.:
|
| 606 |
+
>>> t = tqdm(total=filesize) # Initialise
|
| 607 |
+
>>> for current_buffer in stream:
|
| 608 |
+
... ...
|
| 609 |
+
... t.update(len(current_buffer))
|
| 610 |
+
>>> t.close()
|
| 611 |
+
The last line is highly recommended, but possibly not necessary if
|
| 612 |
+
``t.update()`` will be called in such a way that ``filesize`` will be
|
| 613 |
+
exactly reached and printed.
|
| 614 |
+
|
| 615 |
+
Parameters
|
| 616 |
+
----------
|
| 617 |
+
n : int or float, optional
|
| 618 |
+
Increment to add to the internal counter of iterations
|
| 619 |
+
[default: 1]. If using float, consider specifying ``{n:.3f}``
|
| 620 |
+
or similar in ``bar_format``, or specifying ``unit_scale``.
|
| 621 |
+
|
| 622 |
+
Returns
|
| 623 |
+
-------
|
| 624 |
+
out : bool or None
|
| 625 |
+
True if a ``display()`` was triggered.
|
| 626 |
+
"""
|
| 627 |
+
|
| 628 |
+
def close(self):
|
| 629 |
+
"""Cleanup and (if leave=False) close the progressbar."""
|
| 630 |
+
|
| 631 |
+
def clear(self, nomove=False):
|
| 632 |
+
"""Clear current bar display."""
|
| 633 |
+
|
| 634 |
+
def refresh(self):
|
| 635 |
+
"""
|
| 636 |
+
Force refresh the display of this bar.
|
| 637 |
+
|
| 638 |
+
Parameters
|
| 639 |
+
----------
|
| 640 |
+
nolock : bool, optional
|
| 641 |
+
If ``True``, does not lock.
|
| 642 |
+
If [default: ``False``]: calls ``acquire()`` on internal lock.
|
| 643 |
+
lock_args : tuple, optional
|
| 644 |
+
Passed to internal lock's ``acquire()``.
|
| 645 |
+
If specified, will only ``display()`` if ``acquire()`` returns ``True``.
|
| 646 |
+
"""
|
| 647 |
+
|
| 648 |
+
def unpause(self):
|
| 649 |
+
"""Restart tqdm timer from last print time."""
|
| 650 |
+
|
| 651 |
+
def reset(self, total=None):
|
| 652 |
+
"""
|
| 653 |
+
Resets to 0 iterations for repeated use.
|
| 654 |
+
|
| 655 |
+
Consider combining with ``leave=True``.
|
| 656 |
+
|
| 657 |
+
Parameters
|
| 658 |
+
----------
|
| 659 |
+
total : int or float, optional. Total to use for the new bar.
|
| 660 |
+
"""
|
| 661 |
+
|
| 662 |
+
def set_description(self, desc=None, refresh=True):
|
| 663 |
+
"""
|
| 664 |
+
Set/modify description of the progress bar.
|
| 665 |
+
|
| 666 |
+
Parameters
|
| 667 |
+
----------
|
| 668 |
+
desc : str, optional
|
| 669 |
+
refresh : bool, optional
|
| 670 |
+
Forces refresh [default: True].
|
| 671 |
+
"""
|
| 672 |
+
|
| 673 |
+
def set_postfix(self, ordered_dict=None, refresh=True, **tqdm_kwargs):
|
| 674 |
+
"""
|
| 675 |
+
Set/modify postfix (additional stats)
|
| 676 |
+
with automatic formatting based on datatype.
|
| 677 |
+
|
| 678 |
+
Parameters
|
| 679 |
+
----------
|
| 680 |
+
ordered_dict : dict or OrderedDict, optional
|
| 681 |
+
refresh : bool, optional
|
| 682 |
+
Forces refresh [default: True].
|
| 683 |
+
kwargs : dict, optional
|
| 684 |
+
"""
|
| 685 |
+
|
| 686 |
+
@classmethod
|
| 687 |
+
def write(cls, s, file=sys.stdout, end="\n"):
|
| 688 |
+
"""Print a message via tqdm (without overlap with bars)."""
|
| 689 |
+
|
| 690 |
+
@property
|
| 691 |
+
def format_dict(self):
|
| 692 |
+
"""Public API for read-only member access."""
|
| 693 |
+
|
| 694 |
+
def display(self, msg=None, pos=None):
|
| 695 |
+
"""
|
| 696 |
+
Use ``self.sp`` to display ``msg`` in the specified ``pos``.
|
| 697 |
+
|
| 698 |
+
Consider overloading this function when inheriting to use e.g.:
|
| 699 |
+
``self.some_frontend(**self.format_dict)`` instead of ``self.sp``.
|
| 700 |
+
|
| 701 |
+
Parameters
|
| 702 |
+
----------
|
| 703 |
+
msg : str, optional. What to display (default: ``repr(self)``).
|
| 704 |
+
pos : int, optional. Position to ``moveto``
|
| 705 |
+
(default: ``abs(self.pos)``).
|
| 706 |
+
"""
|
| 707 |
+
|
| 708 |
+
@classmethod
|
| 709 |
+
@contextmanager
|
| 710 |
+
def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs):
|
| 711 |
+
"""
|
| 712 |
+
stream : file-like object.
|
| 713 |
+
method : str, "read" or "write". The result of ``read()`` and
|
| 714 |
+
the first argument of ``write()`` should have a ``len()``.
|
| 715 |
+
|
| 716 |
+
>>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
|
| 717 |
+
... while True:
|
| 718 |
+
... chunk = fobj.read(chunk_size)
|
| 719 |
+
... if not chunk:
|
| 720 |
+
... break
|
| 721 |
+
"""
|
| 722 |
+
|
| 723 |
+
@classmethod
|
| 724 |
+
def pandas(cls, *targs, **tqdm_kwargs):
|
| 725 |
+
"""Registers the current `tqdm` class with `pandas`."""
|
| 726 |
+
|
| 727 |
+
def trange(*args, **tqdm_kwargs):
|
| 728 |
+
"""Shortcut for `tqdm(range(*args), **tqdm_kwargs)`."""
|
| 729 |
+
|
| 730 |
+
Convenience Functions
|
| 731 |
+
~~~~~~~~~~~~~~~~~~~~~
|
| 732 |
+
|
| 733 |
+
.. code:: python
|
| 734 |
+
|
| 735 |
+
def tqdm.contrib.tenumerate(iterable, start=0, total=None,
|
| 736 |
+
tqdm_class=tqdm.auto.tqdm, **tqdm_kwargs):
|
| 737 |
+
"""Equivalent of `numpy.ndenumerate` or builtin `enumerate`."""
|
| 738 |
+
|
| 739 |
+
def tqdm.contrib.tzip(iter1, *iter2plus, **tqdm_kwargs):
|
| 740 |
+
"""Equivalent of builtin `zip`."""
|
| 741 |
+
|
| 742 |
+
def tqdm.contrib.tmap(function, *sequences, **tqdm_kwargs):
|
| 743 |
+
"""Equivalent of builtin `map`."""
|
| 744 |
+
|
| 745 |
+
Submodules
|
| 746 |
+
~~~~~~~~~~
|
| 747 |
+
|
| 748 |
+
.. code:: python
|
| 749 |
+
|
| 750 |
+
class tqdm.notebook.tqdm(tqdm.tqdm):
|
| 751 |
+
"""IPython/Jupyter Notebook widget."""
|
| 752 |
+
|
| 753 |
+
class tqdm.auto.tqdm(tqdm.tqdm):
|
| 754 |
+
"""Automatically chooses beween `tqdm.notebook` and `tqdm.tqdm`."""
|
| 755 |
+
|
| 756 |
+
class tqdm.asyncio.tqdm(tqdm.tqdm):
|
| 757 |
+
"""Asynchronous version."""
|
| 758 |
+
@classmethod
|
| 759 |
+
def as_completed(cls, fs, *, loop=None, timeout=None, total=None,
|
| 760 |
+
**tqdm_kwargs):
|
| 761 |
+
"""Wrapper for `asyncio.as_completed`."""
|
| 762 |
+
|
| 763 |
+
class tqdm.gui.tqdm(tqdm.tqdm):
|
| 764 |
+
"""Matplotlib GUI version."""
|
| 765 |
+
|
| 766 |
+
class tqdm.tk.tqdm(tqdm.tqdm):
|
| 767 |
+
"""Tkinter GUI version."""
|
| 768 |
+
|
| 769 |
+
class tqdm.rich.tqdm(tqdm.tqdm):
|
| 770 |
+
"""`rich.progress` version."""
|
| 771 |
+
|
| 772 |
+
class tqdm.keras.TqdmCallback(keras.callbacks.Callback):
|
| 773 |
+
"""Keras callback for epoch and batch progress."""
|
| 774 |
+
|
| 775 |
+
class tqdm.dask.TqdmCallback(dask.callbacks.Callback):
|
| 776 |
+
"""Dask callback for task progress."""
|
| 777 |
+
|
| 778 |
+
|
| 779 |
+
``contrib``
|
| 780 |
+
+++++++++++
|
| 781 |
+
|
| 782 |
+
The ``tqdm.contrib`` package also contains experimental modules:
|
| 783 |
+
|
| 784 |
+
- ``tqdm.contrib.itertools``: Thin wrappers around ``itertools``
|
| 785 |
+
- ``tqdm.contrib.concurrent``: Thin wrappers around ``concurrent.futures``
|
| 786 |
+
- ``tqdm.contrib.slack``: Posts to `Slack <https://slack.com>`__ bots
|
| 787 |
+
- ``tqdm.contrib.discord``: Posts to `Discord <https://discord.com>`__ bots
|
| 788 |
+
- ``tqdm.contrib.telegram``: Posts to `Telegram <https://telegram.org>`__ bots
|
| 789 |
+
- ``tqdm.contrib.bells``: Automagically enables all optional features
|
| 790 |
+
|
| 791 |
+
* ``auto``, ``pandas``, ``slack``, ``discord``, ``telegram``
|
| 792 |
+
|
| 793 |
+
Examples and Advanced Usage
|
| 794 |
+
---------------------------
|
| 795 |
+
|
| 796 |
+
- See the `examples <https://github.com/tqdm/tqdm/tree/master/examples>`__
|
| 797 |
+
folder;
|
| 798 |
+
- import the module and run ``help()``;
|
| 799 |
+
- consult the `wiki <https://github.com/tqdm/tqdm/wiki>`__;
|
| 800 |
+
|
| 801 |
+
* this has an
|
| 802 |
+
`excellent article <https://github.com/tqdm/tqdm/wiki/How-to-make-a-great-Progress-Bar>`__
|
| 803 |
+
on how to make a **great** progressbar;
|
| 804 |
+
|
| 805 |
+
- check out the `slides from PyData London <https://tqdm.github.io/PyData2019/slides.html>`__, or
|
| 806 |
+
- run the |binder-demo|.
|
| 807 |
+
|
| 808 |
+
Description and additional stats
|
| 809 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 810 |
+
|
| 811 |
+
Custom information can be displayed and updated dynamically on ``tqdm`` bars
|
| 812 |
+
with the ``desc`` and ``postfix`` arguments:
|
| 813 |
+
|
| 814 |
+
.. code:: python
|
| 815 |
+
|
| 816 |
+
from tqdm import tqdm, trange
|
| 817 |
+
from random import random, randint
|
| 818 |
+
from time import sleep
|
| 819 |
+
|
| 820 |
+
with trange(10) as t:
|
| 821 |
+
for i in t:
|
| 822 |
+
# Description will be displayed on the left
|
| 823 |
+
t.set_description('GEN %i' % i)
|
| 824 |
+
# Postfix will be displayed on the right,
|
| 825 |
+
# formatted automatically based on argument's datatype
|
| 826 |
+
t.set_postfix(loss=random(), gen=randint(1,999), str='h',
|
| 827 |
+
lst=[1, 2])
|
| 828 |
+
sleep(0.1)
|
| 829 |
+
|
| 830 |
+
with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}",
|
| 831 |
+
postfix=["Batch", {"value": 0}]) as t:
|
| 832 |
+
for i in range(10):
|
| 833 |
+
sleep(0.1)
|
| 834 |
+
t.postfix[1]["value"] = i / 2
|
| 835 |
+
t.update()
|
| 836 |
+
|
| 837 |
+
Points to remember when using ``{postfix[...]}`` in the ``bar_format`` string:
|
| 838 |
+
|
| 839 |
+
- ``postfix`` also needs to be passed as an initial argument in a compatible
|
| 840 |
+
format, and
|
| 841 |
+
- ``postfix`` will be auto-converted to a string if it is a ``dict``-like
|
| 842 |
+
object. To prevent this behaviour, insert an extra item into the dictionary
|
| 843 |
+
where the key is not a string.
|
| 844 |
+
|
| 845 |
+
Additional ``bar_format`` parameters may also be defined by overriding
|
| 846 |
+
``format_dict``, and the bar itself may be modified using ``ascii``:
|
| 847 |
+
|
| 848 |
+
.. code:: python
|
| 849 |
+
|
| 850 |
+
from tqdm import tqdm
|
| 851 |
+
class TqdmExtraFormat(tqdm):
|
| 852 |
+
"""Provides a `total_time` format parameter"""
|
| 853 |
+
@property
|
| 854 |
+
def format_dict(self):
|
| 855 |
+
d = super().format_dict
|
| 856 |
+
total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1)
|
| 857 |
+
d.update(total_time=self.format_interval(total_time) + " in total")
|
| 858 |
+
return d
|
| 859 |
+
|
| 860 |
+
for i in TqdmExtraFormat(
|
| 861 |
+
range(9), ascii=" .oO0",
|
| 862 |
+
bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"):
|
| 863 |
+
if i == 4:
|
| 864 |
+
break
|
| 865 |
+
|
| 866 |
+
.. code::
|
| 867 |
+
|
| 868 |
+
00:00 in total: 44%|0000. | 4/9 [00:00<00:00, 962.93it/s]
|
| 869 |
+
|
| 870 |
+
Note that ``{bar}`` also supports a format specifier ``[width][type]``.
|
| 871 |
+
|
| 872 |
+
- ``width``
|
| 873 |
+
|
| 874 |
+
* unspecified (default): automatic to fill ``ncols``
|
| 875 |
+
* ``int >= 0``: fixed width overriding ``ncols`` logic
|
| 876 |
+
* ``int < 0``: subtract from the automatic default
|
| 877 |
+
|
| 878 |
+
- ``type``
|
| 879 |
+
|
| 880 |
+
* ``a``: ascii (``ascii=True`` override)
|
| 881 |
+
* ``u``: unicode (``ascii=False`` override)
|
| 882 |
+
* ``b``: blank (``ascii=" "`` override)
|
| 883 |
+
|
| 884 |
+
This means a fixed bar with right-justified text may be created by using:
|
| 885 |
+
``bar_format="{l_bar}{bar:10}|{bar:-10b}right-justified"``
|
| 886 |
+
|
| 887 |
+
Nested progress bars
|
| 888 |
+
~~~~~~~~~~~~~~~~~~~~
|
| 889 |
+
|
| 890 |
+
``tqdm`` supports nested progress bars. Here's an example:
|
| 891 |
+
|
| 892 |
+
.. code:: python
|
| 893 |
+
|
| 894 |
+
from tqdm.auto import trange
|
| 895 |
+
from time import sleep
|
| 896 |
+
|
| 897 |
+
for i in trange(4, desc='1st loop'):
|
| 898 |
+
for j in trange(5, desc='2nd loop'):
|
| 899 |
+
for k in trange(50, desc='3rd loop', leave=False):
|
| 900 |
+
sleep(0.01)
|
| 901 |
+
|
| 902 |
+
For manual control over positioning (e.g. for multi-processing use),
|
| 903 |
+
you may specify ``position=n`` where ``n=0`` for the outermost bar,
|
| 904 |
+
``n=1`` for the next, and so on.
|
| 905 |
+
However, it's best to check if ``tqdm`` can work without manual ``position``
|
| 906 |
+
first.
|
| 907 |
+
|
| 908 |
+
.. code:: python
|
| 909 |
+
|
| 910 |
+
from time import sleep
|
| 911 |
+
from tqdm import trange, tqdm
|
| 912 |
+
from multiprocessing import Pool, RLock, freeze_support
|
| 913 |
+
|
| 914 |
+
L = list(range(9))
|
| 915 |
+
|
| 916 |
+
def progresser(n):
|
| 917 |
+
interval = 0.001 / (n + 2)
|
| 918 |
+
total = 5000
|
| 919 |
+
text = f"#{n}, est. {interval * total:<04.2}s"
|
| 920 |
+
for _ in trange(total, desc=text, position=n):
|
| 921 |
+
sleep(interval)
|
| 922 |
+
|
| 923 |
+
if __name__ == '__main__':
|
| 924 |
+
freeze_support() # for Windows support
|
| 925 |
+
tqdm.set_lock(RLock()) # for managing output contention
|
| 926 |
+
p = Pool(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),))
|
| 927 |
+
p.map(progresser, L)
|
| 928 |
+
|
| 929 |
+
Note that in Python 3, ``tqdm.write`` is thread-safe:
|
| 930 |
+
|
| 931 |
+
.. code:: python
|
| 932 |
+
|
| 933 |
+
from time import sleep
|
| 934 |
+
from tqdm import tqdm, trange
|
| 935 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 936 |
+
|
| 937 |
+
L = list(range(9))
|
| 938 |
+
|
| 939 |
+
def progresser(n):
|
| 940 |
+
interval = 0.001 / (n + 2)
|
| 941 |
+
total = 5000
|
| 942 |
+
text = f"#{n}, est. {interval * total:<04.2}s"
|
| 943 |
+
for _ in trange(total, desc=text):
|
| 944 |
+
sleep(interval)
|
| 945 |
+
if n == 6:
|
| 946 |
+
tqdm.write("n == 6 completed.")
|
| 947 |
+
tqdm.write("`tqdm.write()` is thread-safe in py3!")
|
| 948 |
+
|
| 949 |
+
if __name__ == '__main__':
|
| 950 |
+
with ThreadPoolExecutor() as p:
|
| 951 |
+
p.map(progresser, L)
|
| 952 |
+
|
| 953 |
+
Hooks and callbacks
|
| 954 |
+
~~~~~~~~~~~~~~~~~~~
|
| 955 |
+
|
| 956 |
+
``tqdm`` can easily support callbacks/hooks and manual updates.
|
| 957 |
+
Here's an example with ``urllib``:
|
| 958 |
+
|
| 959 |
+
**``urllib.urlretrieve`` documentation**
|
| 960 |
+
|
| 961 |
+
| [...]
|
| 962 |
+
| If present, the hook function will be called once
|
| 963 |
+
| on establishment of the network connection and once after each block read
|
| 964 |
+
| thereafter. The hook will be passed three arguments; a count of blocks
|
| 965 |
+
| transferred so far, a block size in bytes, and the total size of the file.
|
| 966 |
+
| [...]
|
| 967 |
+
|
| 968 |
+
.. code:: python
|
| 969 |
+
|
| 970 |
+
import urllib, os
|
| 971 |
+
from tqdm import tqdm
|
| 972 |
+
urllib = getattr(urllib, 'request', urllib)
|
| 973 |
+
|
| 974 |
+
class TqdmUpTo(tqdm):
|
| 975 |
+
"""Provides `update_to(n)` which uses `tqdm.update(delta_n)`."""
|
| 976 |
+
def update_to(self, b=1, bsize=1, tsize=None):
|
| 977 |
+
"""
|
| 978 |
+
b : int, optional
|
| 979 |
+
Number of blocks transferred so far [default: 1].
|
| 980 |
+
bsize : int, optional
|
| 981 |
+
Size of each block (in tqdm units) [default: 1].
|
| 982 |
+
tsize : int, optional
|
| 983 |
+
Total size (in tqdm units). If [default: None] remains unchanged.
|
| 984 |
+
"""
|
| 985 |
+
if tsize is not None:
|
| 986 |
+
self.total = tsize
|
| 987 |
+
return self.update(b * bsize - self.n) # also sets self.n = b * bsize
|
| 988 |
+
|
| 989 |
+
eg_link = "https://caspersci.uk.to/matryoshka.zip"
|
| 990 |
+
with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1,
|
| 991 |
+
desc=eg_link.split('/')[-1]) as t: # all optional kwargs
|
| 992 |
+
urllib.urlretrieve(eg_link, filename=os.devnull,
|
| 993 |
+
reporthook=t.update_to, data=None)
|
| 994 |
+
t.total = t.n
|
| 995 |
+
|
| 996 |
+
Inspired by `twine#242 <https://github.com/pypa/twine/pull/242>`__.
|
| 997 |
+
Functional alternative in
|
| 998 |
+
`examples/tqdm_wget.py <https://github.com/tqdm/tqdm/blob/master/examples/tqdm_wget.py>`__.
|
| 999 |
+
|
| 1000 |
+
It is recommend to use ``miniters=1`` whenever there is potentially
|
| 1001 |
+
large differences in iteration speed (e.g. downloading a file over
|
| 1002 |
+
a patchy connection).
|
| 1003 |
+
|
| 1004 |
+
**Wrapping read/write methods**
|
| 1005 |
+
|
| 1006 |
+
To measure throughput through a file-like object's ``read`` or ``write``
|
| 1007 |
+
methods, use ``CallbackIOWrapper``:
|
| 1008 |
+
|
| 1009 |
+
.. code:: python
|
| 1010 |
+
|
| 1011 |
+
from tqdm.auto import tqdm
|
| 1012 |
+
from tqdm.utils import CallbackIOWrapper
|
| 1013 |
+
|
| 1014 |
+
with tqdm(total=file_obj.size,
|
| 1015 |
+
unit='B', unit_scale=True, unit_divisor=1024) as t:
|
| 1016 |
+
fobj = CallbackIOWrapper(t.update, file_obj, "read")
|
| 1017 |
+
while True:
|
| 1018 |
+
chunk = fobj.read(chunk_size)
|
| 1019 |
+
if not chunk:
|
| 1020 |
+
break
|
| 1021 |
+
t.reset()
|
| 1022 |
+
# ... continue to use `t` for something else
|
| 1023 |
+
|
| 1024 |
+
Alternatively, use the even simpler ``wrapattr`` convenience function,
|
| 1025 |
+
which would condense both the ``urllib`` and ``CallbackIOWrapper`` examples
|
| 1026 |
+
down to:
|
| 1027 |
+
|
| 1028 |
+
.. code:: python
|
| 1029 |
+
|
| 1030 |
+
import urllib, os
|
| 1031 |
+
from tqdm import tqdm
|
| 1032 |
+
|
| 1033 |
+
eg_link = "https://caspersci.uk.to/matryoshka.zip"
|
| 1034 |
+
response = getattr(urllib, 'request', urllib).urlopen(eg_link)
|
| 1035 |
+
with tqdm.wrapattr(open(os.devnull, "wb"), "write",
|
| 1036 |
+
miniters=1, desc=eg_link.split('/')[-1],
|
| 1037 |
+
total=getattr(response, 'length', None)) as fout:
|
| 1038 |
+
for chunk in response:
|
| 1039 |
+
fout.write(chunk)
|
| 1040 |
+
|
| 1041 |
+
The ``requests`` equivalent is nearly identical:
|
| 1042 |
+
|
| 1043 |
+
.. code:: python
|
| 1044 |
+
|
| 1045 |
+
import requests, os
|
| 1046 |
+
from tqdm import tqdm
|
| 1047 |
+
|
| 1048 |
+
eg_link = "https://caspersci.uk.to/matryoshka.zip"
|
| 1049 |
+
response = requests.get(eg_link, stream=True)
|
| 1050 |
+
with tqdm.wrapattr(open(os.devnull, "wb"), "write",
|
| 1051 |
+
miniters=1, desc=eg_link.split('/')[-1],
|
| 1052 |
+
total=int(response.headers.get('content-length', 0))) as fout:
|
| 1053 |
+
for chunk in response.iter_content(chunk_size=4096):
|
| 1054 |
+
fout.write(chunk)
|
| 1055 |
+
|
| 1056 |
+
**Custom callback**
|
| 1057 |
+
|
| 1058 |
+
``tqdm`` is known for intelligently skipping unnecessary displays. To make a
|
| 1059 |
+
custom callback take advantage of this, simply use the return value of
|
| 1060 |
+
``update()``. This is set to ``True`` if a ``display()`` was triggered.
|
| 1061 |
+
|
| 1062 |
+
.. code:: python
|
| 1063 |
+
|
| 1064 |
+
from tqdm.auto import tqdm as std_tqdm
|
| 1065 |
+
|
| 1066 |
+
def external_callback(*args, **kwargs):
|
| 1067 |
+
...
|
| 1068 |
+
|
| 1069 |
+
class TqdmExt(std_tqdm):
|
| 1070 |
+
def update(self, n=1):
|
| 1071 |
+
displayed = super().update(n)
|
| 1072 |
+
if displayed:
|
| 1073 |
+
external_callback(**self.format_dict)
|
| 1074 |
+
return displayed
|
| 1075 |
+
|
| 1076 |
+
``asyncio``
|
| 1077 |
+
~~~~~~~~~~~
|
| 1078 |
+
|
| 1079 |
+
Note that ``break`` isn't currently caught by asynchronous iterators.
|
| 1080 |
+
This means that ``tqdm`` cannot clean up after itself in this case:
|
| 1081 |
+
|
| 1082 |
+
.. code:: python
|
| 1083 |
+
|
| 1084 |
+
from tqdm.asyncio import tqdm
|
| 1085 |
+
|
| 1086 |
+
async for i in tqdm(range(9)):
|
| 1087 |
+
if i == 2:
|
| 1088 |
+
break
|
| 1089 |
+
|
| 1090 |
+
Instead, either call ``pbar.close()`` manually or use the context manager syntax:
|
| 1091 |
+
|
| 1092 |
+
.. code:: python
|
| 1093 |
+
|
| 1094 |
+
from tqdm.asyncio import tqdm
|
| 1095 |
+
|
| 1096 |
+
with tqdm(range(9)) as pbar:
|
| 1097 |
+
async for i in pbar:
|
| 1098 |
+
if i == 2:
|
| 1099 |
+
break
|
| 1100 |
+
|
| 1101 |
+
Pandas Integration
|
| 1102 |
+
~~~~~~~~~~~~~~~~~~
|
| 1103 |
+
|
| 1104 |
+
Due to popular demand we've added support for ``pandas`` -- here's an example
|
| 1105 |
+
for ``DataFrame.progress_apply`` and ``DataFrameGroupBy.progress_apply``:
|
| 1106 |
+
|
| 1107 |
+
.. code:: python
|
| 1108 |
+
|
| 1109 |
+
import pandas as pd
|
| 1110 |
+
import numpy as np
|
| 1111 |
+
from tqdm import tqdm
|
| 1112 |
+
|
| 1113 |
+
df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
|
| 1114 |
+
|
| 1115 |
+
# Register `pandas.progress_apply` and `pandas.Series.map_apply` with `tqdm`
|
| 1116 |
+
# (can use `tqdm.gui.tqdm`, `tqdm.notebook.tqdm`, optional kwargs, etc.)
|
| 1117 |
+
tqdm.pandas(desc="my bar!")
|
| 1118 |
+
|
| 1119 |
+
# Now you can use `progress_apply` instead of `apply`
|
| 1120 |
+
# and `progress_map` instead of `map`
|
| 1121 |
+
df.progress_apply(lambda x: x**2)
|
| 1122 |
+
# can also groupby:
|
| 1123 |
+
# df.groupby(0).progress_apply(lambda x: x**2)
|
| 1124 |
+
|
| 1125 |
+
In case you're interested in how this works (and how to modify it for your
|
| 1126 |
+
own callbacks), see the
|
| 1127 |
+
`examples <https://github.com/tqdm/tqdm/tree/master/examples>`__
|
| 1128 |
+
folder or import the module and run ``help()``.
|
| 1129 |
+
|
| 1130 |
+
Keras Integration
|
| 1131 |
+
~~~~~~~~~~~~~~~~~
|
| 1132 |
+
|
| 1133 |
+
A ``keras`` callback is also available:
|
| 1134 |
+
|
| 1135 |
+
.. code:: python
|
| 1136 |
+
|
| 1137 |
+
from tqdm.keras import TqdmCallback
|
| 1138 |
+
|
| 1139 |
+
...
|
| 1140 |
+
|
| 1141 |
+
model.fit(..., verbose=0, callbacks=[TqdmCallback()])
|
| 1142 |
+
|
| 1143 |
+
Dask Integration
|
| 1144 |
+
~~~~~~~~~~~~~~~~
|
| 1145 |
+
|
| 1146 |
+
A ``dask`` callback is also available:
|
| 1147 |
+
|
| 1148 |
+
.. code:: python
|
| 1149 |
+
|
| 1150 |
+
from tqdm.dask import TqdmCallback
|
| 1151 |
+
|
| 1152 |
+
with TqdmCallback(desc="compute"):
|
| 1153 |
+
...
|
| 1154 |
+
arr.compute()
|
| 1155 |
+
|
| 1156 |
+
# or use callback globally
|
| 1157 |
+
cb = TqdmCallback(desc="global")
|
| 1158 |
+
cb.register()
|
| 1159 |
+
arr.compute()
|
| 1160 |
+
|
| 1161 |
+
IPython/Jupyter Integration
|
| 1162 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1163 |
+
|
| 1164 |
+
IPython/Jupyter is supported via the ``tqdm.notebook`` submodule:
|
| 1165 |
+
|
| 1166 |
+
.. code:: python
|
| 1167 |
+
|
| 1168 |
+
from tqdm.notebook import trange, tqdm
|
| 1169 |
+
from time import sleep
|
| 1170 |
+
|
| 1171 |
+
for i in trange(3, desc='1st loop'):
|
| 1172 |
+
for j in tqdm(range(100), desc='2nd loop'):
|
| 1173 |
+
sleep(0.01)
|
| 1174 |
+
|
| 1175 |
+
In addition to ``tqdm`` features, the submodule provides a native Jupyter
|
| 1176 |
+
widget (compatible with IPython v1-v4 and Jupyter), fully working nested bars
|
| 1177 |
+
and colour hints (blue: normal, green: completed, red: error/interrupt,
|
| 1178 |
+
light blue: no ETA); as demonstrated below.
|
| 1179 |
+
|
| 1180 |
+
|Screenshot-Jupyter1|
|
| 1181 |
+
|Screenshot-Jupyter2|
|
| 1182 |
+
|Screenshot-Jupyter3|
|
| 1183 |
+
|
| 1184 |
+
The ``notebook`` version supports percentage or pixels for overall width
|
| 1185 |
+
(e.g.: ``ncols='100%'`` or ``ncols='480px'``).
|
| 1186 |
+
|
| 1187 |
+
It is also possible to let ``tqdm`` automatically choose between
|
| 1188 |
+
console or notebook versions by using the ``autonotebook`` submodule:
|
| 1189 |
+
|
| 1190 |
+
.. code:: python
|
| 1191 |
+
|
| 1192 |
+
from tqdm.autonotebook import tqdm
|
| 1193 |
+
tqdm.pandas()
|
| 1194 |
+
|
| 1195 |
+
Note that this will issue a ``TqdmExperimentalWarning`` if run in a notebook
|
| 1196 |
+
since it is not meant to be possible to distinguish between ``jupyter notebook``
|
| 1197 |
+
and ``jupyter console``. Use ``auto`` instead of ``autonotebook`` to suppress
|
| 1198 |
+
this warning.
|
| 1199 |
+
|
| 1200 |
+
Note that notebooks will display the bar in the cell where it was created.
|
| 1201 |
+
This may be a different cell from the one where it is used.
|
| 1202 |
+
If this is not desired, either
|
| 1203 |
+
|
| 1204 |
+
- delay the creation of the bar to the cell where it must be displayed, or
|
| 1205 |
+
- create the bar with ``display=False``, and in a later cell call
|
| 1206 |
+
``display(bar.container)``:
|
| 1207 |
+
|
| 1208 |
+
.. code:: python
|
| 1209 |
+
|
| 1210 |
+
from tqdm.notebook import tqdm
|
| 1211 |
+
pbar = tqdm(..., display=False)
|
| 1212 |
+
|
| 1213 |
+
.. code:: python
|
| 1214 |
+
|
| 1215 |
+
# different cell
|
| 1216 |
+
display(pbar.container)
|
| 1217 |
+
|
| 1218 |
+
The ``keras`` callback has a ``display()`` method which can be used likewise:
|
| 1219 |
+
|
| 1220 |
+
.. code:: python
|
| 1221 |
+
|
| 1222 |
+
from tqdm.keras import TqdmCallback
|
| 1223 |
+
cbk = TqdmCallback(display=False)
|
| 1224 |
+
|
| 1225 |
+
.. code:: python
|
| 1226 |
+
|
| 1227 |
+
# different cell
|
| 1228 |
+
cbk.display()
|
| 1229 |
+
model.fit(..., verbose=0, callbacks=[cbk])
|
| 1230 |
+
|
| 1231 |
+
Another possibility is to have a single bar (near the top of the notebook)
|
| 1232 |
+
which is constantly re-used (using ``reset()`` rather than ``close()``).
|
| 1233 |
+
For this reason, the notebook version (unlike the CLI version) does not
|
| 1234 |
+
automatically call ``close()`` upon ``Exception``.
|
| 1235 |
+
|
| 1236 |
+
.. code:: python
|
| 1237 |
+
|
| 1238 |
+
from tqdm.notebook import tqdm
|
| 1239 |
+
pbar = tqdm()
|
| 1240 |
+
|
| 1241 |
+
.. code:: python
|
| 1242 |
+
|
| 1243 |
+
# different cell
|
| 1244 |
+
iterable = range(100)
|
| 1245 |
+
pbar.reset(total=len(iterable)) # initialise with new `total`
|
| 1246 |
+
for i in iterable:
|
| 1247 |
+
pbar.update()
|
| 1248 |
+
pbar.refresh() # force print final status but don't `close()`
|
| 1249 |
+
|
| 1250 |
+
Custom Integration
|
| 1251 |
+
~~~~~~~~~~~~~~~~~~
|
| 1252 |
+
|
| 1253 |
+
To change the default arguments (such as making ``dynamic_ncols=True``),
|
| 1254 |
+
simply use built-in Python magic:
|
| 1255 |
+
|
| 1256 |
+
.. code:: python
|
| 1257 |
+
|
| 1258 |
+
from functools import partial
|
| 1259 |
+
from tqdm import tqdm as std_tqdm
|
| 1260 |
+
tqdm = partial(std_tqdm, dynamic_ncols=True)
|
| 1261 |
+
|
| 1262 |
+
For further customisation,
|
| 1263 |
+
``tqdm`` may be inherited from to create custom callbacks (as with the
|
| 1264 |
+
``TqdmUpTo`` example `above <#hooks-and-callbacks>`__) or for custom frontends
|
| 1265 |
+
(e.g. GUIs such as notebook or plotting packages). In the latter case:
|
| 1266 |
+
|
| 1267 |
+
1. ``def __init__()`` to call ``super().__init__(..., gui=True)`` to disable
|
| 1268 |
+
terminal ``status_printer`` creation.
|
| 1269 |
+
2. Redefine: ``close()``, ``clear()``, ``display()``.
|
| 1270 |
+
|
| 1271 |
+
Consider overloading ``display()`` to use e.g.
|
| 1272 |
+
``self.frontend(**self.format_dict)`` instead of ``self.sp(repr(self))``.
|
| 1273 |
+
|
| 1274 |
+
Some submodule examples of inheritance:
|
| 1275 |
+
|
| 1276 |
+
- `tqdm/notebook.py <https://github.com/tqdm/tqdm/blob/master/tqdm/notebook.py>`__
|
| 1277 |
+
- `tqdm/gui.py <https://github.com/tqdm/tqdm/blob/master/tqdm/gui.py>`__
|
| 1278 |
+
- `tqdm/tk.py <https://github.com/tqdm/tqdm/blob/master/tqdm/tk.py>`__
|
| 1279 |
+
- `tqdm/contrib/slack.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/slack.py>`__
|
| 1280 |
+
- `tqdm/contrib/discord.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/discord.py>`__
|
| 1281 |
+
- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__
|
| 1282 |
+
|
| 1283 |
+
Dynamic Monitor/Meter
|
| 1284 |
+
~~~~~~~~~~~~~~~~~~~~~
|
| 1285 |
+
|
| 1286 |
+
You can use a ``tqdm`` as a meter which is not monotonically increasing.
|
| 1287 |
+
This could be because ``n`` decreases (e.g. a CPU usage monitor) or ``total``
|
| 1288 |
+
changes.
|
| 1289 |
+
|
| 1290 |
+
One example would be recursively searching for files. The ``total`` is the
|
| 1291 |
+
number of objects found so far, while ``n`` is the number of those objects which
|
| 1292 |
+
are files (rather than folders):
|
| 1293 |
+
|
| 1294 |
+
.. code:: python
|
| 1295 |
+
|
| 1296 |
+
from tqdm import tqdm
|
| 1297 |
+
import os.path
|
| 1298 |
+
|
| 1299 |
+
def find_files_recursively(path, show_progress=True):
|
| 1300 |
+
files = []
|
| 1301 |
+
# total=1 assumes `path` is a file
|
| 1302 |
+
t = tqdm(total=1, unit="file", disable=not show_progress)
|
| 1303 |
+
if not os.path.exists(path):
|
| 1304 |
+
raise IOError("Cannot find:" + path)
|
| 1305 |
+
|
| 1306 |
+
def append_found_file(f):
|
| 1307 |
+
files.append(f)
|
| 1308 |
+
t.update()
|
| 1309 |
+
|
| 1310 |
+
def list_found_dir(path):
|
| 1311 |
+
"""returns os.listdir(path) assuming os.path.isdir(path)"""
|
| 1312 |
+
listing = os.listdir(path)
|
| 1313 |
+
# subtract 1 since a "file" we found was actually this directory
|
| 1314 |
+
t.total += len(listing) - 1
|
| 1315 |
+
# fancy way to give info without forcing a refresh
|
| 1316 |
+
t.set_postfix(dir=path[-10:], refresh=False)
|
| 1317 |
+
t.update(0) # may trigger a refresh
|
| 1318 |
+
return listing
|
| 1319 |
+
|
| 1320 |
+
def recursively_search(path):
|
| 1321 |
+
if os.path.isdir(path):
|
| 1322 |
+
for f in list_found_dir(path):
|
| 1323 |
+
recursively_search(os.path.join(path, f))
|
| 1324 |
+
else:
|
| 1325 |
+
append_found_file(path)
|
| 1326 |
+
|
| 1327 |
+
recursively_search(path)
|
| 1328 |
+
t.set_postfix(dir=path)
|
| 1329 |
+
t.close()
|
| 1330 |
+
return files
|
| 1331 |
+
|
| 1332 |
+
Using ``update(0)`` is a handy way to let ``tqdm`` decide when to trigger a
|
| 1333 |
+
display refresh to avoid console spamming.
|
| 1334 |
+
|
| 1335 |
+
Writing messages
|
| 1336 |
+
~~~~~~~~~~~~~~~~
|
| 1337 |
+
|
| 1338 |
+
This is a work in progress (see
|
| 1339 |
+
`#737 <https://github.com/tqdm/tqdm/issues/737>`__).
|
| 1340 |
+
|
| 1341 |
+
Since ``tqdm`` uses a simple printing mechanism to display progress bars,
|
| 1342 |
+
you should not write any message in the terminal using ``print()`` while
|
| 1343 |
+
a progressbar is open.
|
| 1344 |
+
|
| 1345 |
+
To write messages in the terminal without any collision with ``tqdm`` bar
|
| 1346 |
+
display, a ``.write()`` method is provided:
|
| 1347 |
+
|
| 1348 |
+
.. code:: python
|
| 1349 |
+
|
| 1350 |
+
from tqdm.auto import tqdm, trange
|
| 1351 |
+
from time import sleep
|
| 1352 |
+
|
| 1353 |
+
bar = trange(10)
|
| 1354 |
+
for i in bar:
|
| 1355 |
+
# Print using tqdm class method .write()
|
| 1356 |
+
sleep(0.1)
|
| 1357 |
+
if not (i % 3):
|
| 1358 |
+
tqdm.write("Done task %i" % i)
|
| 1359 |
+
# Can also use bar.write()
|
| 1360 |
+
|
| 1361 |
+
By default, this will print to standard output ``sys.stdout``. but you can
|
| 1362 |
+
specify any file-like object using the ``file`` argument. For example, this
|
| 1363 |
+
can be used to redirect the messages writing to a log file or class.
|
| 1364 |
+
|
| 1365 |
+
Redirecting writing
|
| 1366 |
+
~~~~~~~~~~~~~~~~~~~
|
| 1367 |
+
|
| 1368 |
+
If using a library that can print messages to the console, editing the library
|
| 1369 |
+
by replacing ``print()`` with ``tqdm.write()`` may not be desirable.
|
| 1370 |
+
In that case, redirecting ``sys.stdout`` to ``tqdm.write()`` is an option.
|
| 1371 |
+
|
| 1372 |
+
To redirect ``sys.stdout``, create a file-like class that will write
|
| 1373 |
+
any input string to ``tqdm.write()``, and supply the arguments
|
| 1374 |
+
``file=sys.stdout, dynamic_ncols=True``.
|
| 1375 |
+
|
| 1376 |
+
A reusable canonical example is given below:
|
| 1377 |
+
|
| 1378 |
+
.. code:: python
|
| 1379 |
+
|
| 1380 |
+
from time import sleep
|
| 1381 |
+
import contextlib
|
| 1382 |
+
import sys
|
| 1383 |
+
from tqdm import tqdm
|
| 1384 |
+
from tqdm.contrib import DummyTqdmFile
|
| 1385 |
+
|
| 1386 |
+
|
| 1387 |
+
@contextlib.contextmanager
|
| 1388 |
+
def std_out_err_redirect_tqdm():
|
| 1389 |
+
orig_out_err = sys.stdout, sys.stderr
|
| 1390 |
+
try:
|
| 1391 |
+
sys.stdout, sys.stderr = map(DummyTqdmFile, orig_out_err)
|
| 1392 |
+
yield orig_out_err[0]
|
| 1393 |
+
# Relay exceptions
|
| 1394 |
+
except Exception as exc:
|
| 1395 |
+
raise exc
|
| 1396 |
+
# Always restore sys.stdout/err if necessary
|
| 1397 |
+
finally:
|
| 1398 |
+
sys.stdout, sys.stderr = orig_out_err
|
| 1399 |
+
|
| 1400 |
+
def some_fun(i):
|
| 1401 |
+
print("Fee, fi, fo,".split()[i])
|
| 1402 |
+
|
| 1403 |
+
# Redirect stdout to tqdm.write() (don't forget the `as save_stdout`)
|
| 1404 |
+
with std_out_err_redirect_tqdm() as orig_stdout:
|
| 1405 |
+
# tqdm needs the original stdout
|
| 1406 |
+
# and dynamic_ncols=True to autodetect console width
|
| 1407 |
+
for i in tqdm(range(3), file=orig_stdout, dynamic_ncols=True):
|
| 1408 |
+
sleep(.5)
|
| 1409 |
+
some_fun(i)
|
| 1410 |
+
|
| 1411 |
+
# After the `with`, printing is restored
|
| 1412 |
+
print("Done!")
|
| 1413 |
+
|
| 1414 |
+
Redirecting ``logging``
|
| 1415 |
+
~~~~~~~~~~~~~~~~~~~~~~~
|
| 1416 |
+
|
| 1417 |
+
Similar to ``sys.stdout``/``sys.stderr`` as detailed above, console ``logging``
|
| 1418 |
+
may also be redirected to ``tqdm.write()``.
|
| 1419 |
+
|
| 1420 |
+
Warning: if also redirecting ``sys.stdout``/``sys.stderr``, make sure to
|
| 1421 |
+
redirect ``logging`` first if needed.
|
| 1422 |
+
|
| 1423 |
+
Helper methods are available in ``tqdm.contrib.logging``. For example:
|
| 1424 |
+
|
| 1425 |
+
.. code:: python
|
| 1426 |
+
|
| 1427 |
+
import logging
|
| 1428 |
+
from tqdm import trange
|
| 1429 |
+
from tqdm.contrib.logging import logging_redirect_tqdm
|
| 1430 |
+
|
| 1431 |
+
LOG = logging.getLogger(__name__)
|
| 1432 |
+
|
| 1433 |
+
if __name__ == '__main__':
|
| 1434 |
+
logging.basicConfig(level=logging.INFO)
|
| 1435 |
+
with logging_redirect_tqdm():
|
| 1436 |
+
for i in trange(9):
|
| 1437 |
+
if i == 4:
|
| 1438 |
+
LOG.info("console logging redirected to `tqdm.write()`")
|
| 1439 |
+
# logging restored
|
| 1440 |
+
|
| 1441 |
+
Monitoring thread, intervals and miniters
|
| 1442 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1443 |
+
|
| 1444 |
+
``tqdm`` implements a few tricks to increase efficiency and reduce overhead.
|
| 1445 |
+
|
| 1446 |
+
- Avoid unnecessary frequent bar refreshing: ``mininterval`` defines how long
|
| 1447 |
+
to wait between each refresh. ``tqdm`` always gets updated in the background,
|
| 1448 |
+
but it will display only every ``mininterval``.
|
| 1449 |
+
- Reduce number of calls to check system clock/time.
|
| 1450 |
+
- ``mininterval`` is more intuitive to configure than ``miniters``.
|
| 1451 |
+
A clever adjustment system ``dynamic_miniters`` will automatically adjust
|
| 1452 |
+
``miniters`` to the amount of iterations that fit into time ``mininterval``.
|
| 1453 |
+
Essentially, ``tqdm`` will check if it's time to print without actually
|
| 1454 |
+
checking time. This behaviour can be still be bypassed by manually setting
|
| 1455 |
+
``miniters``.
|
| 1456 |
+
|
| 1457 |
+
However, consider a case with a combination of fast and slow iterations.
|
| 1458 |
+
After a few fast iterations, ``dynamic_miniters`` will set ``miniters`` to a
|
| 1459 |
+
large number. When iteration rate subsequently slows, ``miniters`` will
|
| 1460 |
+
remain large and thus reduce display update frequency. To address this:
|
| 1461 |
+
|
| 1462 |
+
- ``maxinterval`` defines the maximum time between display refreshes.
|
| 1463 |
+
A concurrent monitoring thread checks for overdue updates and forces one
|
| 1464 |
+
where necessary.
|
| 1465 |
+
|
| 1466 |
+
The monitoring thread should not have a noticeable overhead, and guarantees
|
| 1467 |
+
updates at least every 10 seconds by default.
|
| 1468 |
+
This value can be directly changed by setting the ``monitor_interval`` of
|
| 1469 |
+
any ``tqdm`` instance (i.e. ``t = tqdm.tqdm(...); t.monitor_interval = 2``).
|
| 1470 |
+
The monitor thread may be disabled application-wide by setting
|
| 1471 |
+
``tqdm.tqdm.monitor_interval = 0`` before instantiation of any ``tqdm`` bar.
|
| 1472 |
+
|
| 1473 |
+
|
| 1474 |
+
Merch
|
| 1475 |
+
-----
|
| 1476 |
+
|
| 1477 |
+
You can buy `tqdm branded merch <https://tqdm.github.io/merch>`__ now!
|
| 1478 |
+
|
| 1479 |
+
Contributions
|
| 1480 |
+
-------------
|
| 1481 |
+
|
| 1482 |
+
|GitHub-Commits| |GitHub-Issues| |GitHub-PRs| |OpenHub-Status| |GitHub-Contributions| |CII Best Practices|
|
| 1483 |
+
|
| 1484 |
+
All source code is hosted on `GitHub <https://github.com/tqdm/tqdm>`__.
|
| 1485 |
+
Contributions are welcome.
|
| 1486 |
+
|
| 1487 |
+
See the
|
| 1488 |
+
`CONTRIBUTING <https://github.com/tqdm/tqdm/blob/master/CONTRIBUTING.md>`__
|
| 1489 |
+
file for more information.
|
| 1490 |
+
|
| 1491 |
+
Developers who have made significant contributions, ranked by *SLoC*
|
| 1492 |
+
(surviving lines of code,
|
| 1493 |
+
`git fame <https://github.com/casperdcl/git-fame>`__ ``-wMC --excl '\.(png|gif|jpg)$'``),
|
| 1494 |
+
are:
|
| 1495 |
+
|
| 1496 |
+
==================== ======================================================== ==== ================================
|
| 1497 |
+
Name ID SLoC Notes
|
| 1498 |
+
==================== ======================================================== ==== ================================
|
| 1499 |
+
Casper da Costa-Luis `casperdcl <https://github.com/casperdcl>`__ ~80% primary maintainer |Gift-Casper|
|
| 1500 |
+
Stephen Larroque `lrq3000 <https://github.com/lrq3000>`__ ~9% team member
|
| 1501 |
+
Martin Zugnoni `martinzugnoni <https://github.com/martinzugnoni>`__ ~3%
|
| 1502 |
+
Daniel Ecer `de-code <https://github.com/de-code>`__ ~2%
|
| 1503 |
+
Richard Sheridan `richardsheridan <https://github.com/richardsheridan>`__ ~1%
|
| 1504 |
+
Guangshuo Chen `chengs <https://github.com/chengs>`__ ~1%
|
| 1505 |
+
Helio Machado `0x2b3bfa0 <https://github.com/0x2b3bfa0>`__ ~1%
|
| 1506 |
+
Kyle Altendorf `altendky <https://github.com/altendky>`__ <1%
|
| 1507 |
+
Noam Yorav-Raphael `noamraph <https://github.com/noamraph>`__ <1% original author
|
| 1508 |
+
Matthew Stevens `mjstevens777 <https://github.com/mjstevens777>`__ <1%
|
| 1509 |
+
Hadrien Mary `hadim <https://github.com/hadim>`__ <1% team member
|
| 1510 |
+
Mikhail Korobov `kmike <https://github.com/kmike>`__ <1% team member
|
| 1511 |
+
==================== ======================================================== ==== ================================
|
| 1512 |
+
|
| 1513 |
+
Ports to Other Languages
|
| 1514 |
+
~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1515 |
+
|
| 1516 |
+
A list is available on
|
| 1517 |
+
`this wiki page <https://github.com/tqdm/tqdm/wiki/tqdm-ports>`__.
|
| 1518 |
+
|
| 1519 |
+
|
| 1520 |
+
LICENCE
|
| 1521 |
+
-------
|
| 1522 |
+
|
| 1523 |
+
Open Source (OSI approved): |LICENCE|
|
| 1524 |
+
|
| 1525 |
+
Citation information: |DOI|
|
| 1526 |
+
|
| 1527 |
+
|README-Hits| (Since 19 May 2016)
|
| 1528 |
+
|
| 1529 |
+
.. |Logo| image:: https://tqdm.github.io/img/logo.gif
|
| 1530 |
+
.. |Screenshot| image:: https://tqdm.github.io/img/tqdm.gif
|
| 1531 |
+
.. |Video| image:: https://tqdm.github.io/img/video.jpg
|
| 1532 |
+
:target: https://tqdm.github.io/video
|
| 1533 |
+
.. |Slides| image:: https://tqdm.github.io/img/slides.jpg
|
| 1534 |
+
:target: https://tqdm.github.io/PyData2019/slides.html
|
| 1535 |
+
.. |Merch| image:: https://tqdm.github.io/img/merch.jpg
|
| 1536 |
+
:target: https://tqdm.github.io/merch
|
| 1537 |
+
.. |Build-Status| image:: https://img.shields.io/github/actions/workflow/status/tqdm/tqdm/test.yml?branch=master&label=tqdm&logo=GitHub
|
| 1538 |
+
:target: https://github.com/tqdm/tqdm/actions/workflows/test.yml
|
| 1539 |
+
.. |Coverage-Status| image:: https://img.shields.io/coveralls/github/tqdm/tqdm/master?logo=coveralls
|
| 1540 |
+
:target: https://coveralls.io/github/tqdm/tqdm
|
| 1541 |
+
.. |Branch-Coverage-Status| image:: https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg
|
| 1542 |
+
:target: https://codecov.io/gh/tqdm/tqdm
|
| 1543 |
+
.. |Codacy-Grade| image:: https://app.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177
|
| 1544 |
+
:target: https://www.codacy.com/gh/tqdm/tqdm/dashboard
|
| 1545 |
+
.. |CII Best Practices| image:: https://bestpractices.coreinfrastructure.org/projects/3264/badge
|
| 1546 |
+
:target: https://bestpractices.coreinfrastructure.org/projects/3264
|
| 1547 |
+
.. |GitHub-Status| image:: https://img.shields.io/github/tag/tqdm/tqdm.svg?maxAge=86400&logo=github&logoColor=white
|
| 1548 |
+
:target: https://github.com/tqdm/tqdm/releases
|
| 1549 |
+
.. |GitHub-Forks| image:: https://img.shields.io/github/forks/tqdm/tqdm.svg?logo=github&logoColor=white
|
| 1550 |
+
:target: https://github.com/tqdm/tqdm/network
|
| 1551 |
+
.. |GitHub-Stars| image:: https://img.shields.io/github/stars/tqdm/tqdm.svg?logo=github&logoColor=white
|
| 1552 |
+
:target: https://github.com/tqdm/tqdm/stargazers
|
| 1553 |
+
.. |GitHub-Commits| image:: https://img.shields.io/github/commit-activity/y/tqdm/tqdm.svg?logo=git&logoColor=white
|
| 1554 |
+
:target: https://github.com/tqdm/tqdm/graphs/commit-activity
|
| 1555 |
+
.. |GitHub-Issues| image:: https://img.shields.io/github/issues-closed/tqdm/tqdm.svg?logo=github&logoColor=white
|
| 1556 |
+
:target: https://github.com/tqdm/tqdm/issues?q=
|
| 1557 |
+
.. |GitHub-PRs| image:: https://img.shields.io/github/issues-pr-closed/tqdm/tqdm.svg?logo=github&logoColor=white
|
| 1558 |
+
:target: https://github.com/tqdm/tqdm/pulls
|
| 1559 |
+
.. |GitHub-Contributions| image:: https://img.shields.io/github/contributors/tqdm/tqdm.svg?logo=github&logoColor=white
|
| 1560 |
+
:target: https://github.com/tqdm/tqdm/graphs/contributors
|
| 1561 |
+
.. |GitHub-Updated| image:: https://img.shields.io/github/last-commit/tqdm/tqdm/master.svg?logo=github&logoColor=white&label=pushed
|
| 1562 |
+
:target: https://github.com/tqdm/tqdm/pulse
|
| 1563 |
+
.. |Gift-Casper| image:: https://img.shields.io/badge/dynamic/json.svg?color=ff69b4&label=gifts%20received&prefix=%C2%A3&query=%24..sum&url=https%3A%2F%2Fcaspersci.uk.to%2Fgifts.json
|
| 1564 |
+
:target: https://cdcl.ml/sponsor
|
| 1565 |
+
.. |Versions| image:: https://img.shields.io/pypi/v/tqdm.svg
|
| 1566 |
+
:target: https://tqdm.github.io/releases
|
| 1567 |
+
.. |PyPI-Downloads| image:: https://img.shields.io/pypi/dm/tqdm.svg?label=pypi%20downloads&logo=PyPI&logoColor=white
|
| 1568 |
+
:target: https://pepy.tech/project/tqdm
|
| 1569 |
+
.. |Py-Versions| image:: https://img.shields.io/pypi/pyversions/tqdm.svg?logo=python&logoColor=white
|
| 1570 |
+
:target: https://pypi.org/project/tqdm
|
| 1571 |
+
.. |Conda-Forge-Status| image:: https://img.shields.io/conda/v/conda-forge/tqdm.svg?label=conda-forge&logo=conda-forge
|
| 1572 |
+
:target: https://anaconda.org/conda-forge/tqdm
|
| 1573 |
+
.. |Snapcraft| image:: https://img.shields.io/badge/snap-install-82BEA0.svg?logo=snapcraft
|
| 1574 |
+
:target: https://snapcraft.io/tqdm
|
| 1575 |
+
.. |Docker| image:: https://img.shields.io/badge/docker-pull-blue.svg?logo=docker&logoColor=white
|
| 1576 |
+
:target: https://hub.docker.com/r/tqdm/tqdm
|
| 1577 |
+
.. |Libraries-Rank| image:: https://img.shields.io/librariesio/sourcerank/pypi/tqdm.svg?logo=koding&logoColor=white
|
| 1578 |
+
:target: https://libraries.io/pypi/tqdm
|
| 1579 |
+
.. |Libraries-Dependents| image:: https://img.shields.io/librariesio/dependent-repos/pypi/tqdm.svg?logo=koding&logoColor=white
|
| 1580 |
+
:target: https://github.com/tqdm/tqdm/network/dependents
|
| 1581 |
+
.. |OpenHub-Status| image:: https://www.openhub.net/p/tqdm/widgets/project_thin_badge?format=gif
|
| 1582 |
+
:target: https://www.openhub.net/p/tqdm?ref=Thin+badge
|
| 1583 |
+
.. |awesome-python| image:: https://awesome.re/mentioned-badge.svg
|
| 1584 |
+
:target: https://github.com/vinta/awesome-python
|
| 1585 |
+
.. |LICENCE| image:: https://img.shields.io/pypi/l/tqdm.svg
|
| 1586 |
+
:target: https://raw.githubusercontent.com/tqdm/tqdm/master/LICENCE
|
| 1587 |
+
.. |DOI| image:: https://img.shields.io/badge/DOI-10.5281/zenodo.595120-blue.svg
|
| 1588 |
+
:target: https://doi.org/10.5281/zenodo.595120
|
| 1589 |
+
.. |binder-demo| image:: https://mybinder.org/badge_logo.svg
|
| 1590 |
+
:target: https://mybinder.org/v2/gh/tqdm/tqdm/master?filepath=DEMO.ipynb
|
| 1591 |
+
.. |Screenshot-Jupyter1| image:: https://tqdm.github.io/img/jupyter-1.gif
|
| 1592 |
+
.. |Screenshot-Jupyter2| image:: https://tqdm.github.io/img/jupyter-2.gif
|
| 1593 |
+
.. |Screenshot-Jupyter3| image:: https://tqdm.github.io/img/jupyter-3.gif
|
| 1594 |
+
.. |README-Hits| image:: https://cgi.cdcl.ml/hits?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif
|
| 1595 |
+
:target: https://cgi.cdcl.ml/hits?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif&style=social
|
.cache/pip/http-v2/4/4/e/5/b/44e5b11a6caa92636d8ccfe658d420ba4ed8f67f7f4e835b214255aa
ADDED
|
Binary file (1.8 kB). View file
|
|
|