barflow 0.6.2__cp315-cp315-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
barflow/__init__.py ADDED
@@ -0,0 +1,180 @@
1
+ """BarFlow — fast Python progress bars with a C++ core.
2
+
3
+ Top-level imports are kept minimal so `from barflow import track` stays
4
+ cold-startup-cheap (~1 ms). Columns, themes, spinners, hooks, and the
5
+ asyncio wrapper are lazy-loaded via `__getattr__` on first access.
6
+ """
7
+
8
+
9
+ # start delvewheel patch
10
+ def _delvewheel_patch_1_13_2():
11
+ import os
12
+ if os.path.isdir(libs_dir := os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'barflow.libs'))):
13
+ os.add_dll_directory(libs_dir)
14
+
15
+
16
+ _delvewheel_patch_1_13_2()
17
+ del _delvewheel_patch_1_13_2
18
+ # end delvewheel patch
19
+
20
+ from . import _core
21
+ from ._core import Tracker
22
+
23
+ __version__ = "0.6.2"
24
+ __all__ = ["Progress", "Tracker", "track", "wrap_file", "wrapattr", "__version__"]
25
+
26
+
27
+ # ---- Fast path -------------------------------------------------------------
28
+
29
+ def _auto_disable():
30
+ """True when stderr is not an interactive terminal. BarFlow renders to
31
+ stderr, so on a pipe/file/redirect we suppress the bar (tqdm's
32
+ `disable=None` behavior) rather than spraying ANSI frames into the sink."""
33
+ import sys
34
+ stream = sys.stderr
35
+ try:
36
+ return not (stream is not None and stream.isatty())
37
+ except Exception:
38
+ return True
39
+
40
+
41
+ def _build_progress(total, desc, columns, theme, disable, min_interval,
42
+ capture_output, smoothing, leave, unit, unit_scale,
43
+ unit_divisor, initial, delay):
44
+ """Construct the Progress backing a track()/atrack() call.
45
+
46
+ Fast path: no columns, no theme, no capture_output → straight to
47
+ `_core.Progress` (one C-extension construction, no Python subclass).
48
+ Slow path: any decoration → route through the Python `Progress` class,
49
+ which resolves themes/columns before calling into the core.
50
+ """
51
+ if columns or theme or capture_output:
52
+ from . import _progress
53
+ return _progress.Progress(
54
+ *(columns or ()),
55
+ total=total,
56
+ desc=desc,
57
+ theme=theme,
58
+ disable=disable,
59
+ min_interval=min_interval,
60
+ capture_output=capture_output,
61
+ smoothing=smoothing,
62
+ leave=leave,
63
+ unit=unit,
64
+ unit_scale=unit_scale,
65
+ unit_divisor=unit_divisor,
66
+ initial=initial,
67
+ delay=delay,
68
+ )
69
+ return _core.Progress(
70
+ total=total,
71
+ desc=desc,
72
+ min_interval=min_interval,
73
+ disable=disable,
74
+ smoothing=smoothing,
75
+ leave=leave,
76
+ unit=unit,
77
+ unit_scale=unit_scale,
78
+ unit_divisor=float(unit_divisor),
79
+ initial=initial,
80
+ delay=delay,
81
+ )
82
+
83
+
84
+ def track(iterable, total=None, desc=None, *, columns=None, theme=None,
85
+ task_id=0, disable=False, min_interval=0.05, capture_output=False,
86
+ smoothing=0.0, leave=True, unit="it", unit_scale=False,
87
+ unit_divisor=1000, initial=0, delay=0.0):
88
+ """Wrap `iterable` in a live progress bar. Returns an iterator.
89
+
90
+ Fast path: no columns, no theme, no capture_output → goes straight to
91
+ `_core.Progress` (one C-extension construction, no Python subclass).
92
+ Slow path: any decoration → route through the Python `Progress` class.
93
+
94
+ `disable` False (default) always shows; True hides; None auto-disables
95
+ when stderr is not a TTY (tqdm's `disable=None` semantics).
96
+ `smoothing` 0 = whole-run average rate (default); (0,1] = EMA weight on
97
+ the most recent interval for a responsive it/s and ETA.
98
+ `leave` False clears the bar on completion instead of leaving it.
99
+ `unit` noun in the rate suffix ("it" → "N it/s", "B" → "N B/s").
100
+ `unit_scale` humanize counts/rates with SI-style k/M/G scaling.
101
+ `unit_divisor` scaling base — 1000 (SI) or 1024 (binary/bytes).
102
+ `initial` count already done (resume); shown but excluded from rate.
103
+ `delay` seconds to wait before showing the bar (hide fast jobs).
104
+ """
105
+ if task_id != 0:
106
+ # track() always builds a single-task (task 0) bar; a non-zero
107
+ # task_id would otherwise reach the C Tracker bounds check and raise
108
+ # an opaque "task_id out of range". Fail fast with guidance instead.
109
+ raise ValueError(
110
+ "track() creates a single-task bar, so task_id must be 0. "
111
+ "For multiple bars use barflow.Progress + add_task()."
112
+ )
113
+
114
+ if disable is None:
115
+ disable = _auto_disable()
116
+
117
+ if total is None:
118
+ try:
119
+ total = len(iterable)
120
+ except TypeError:
121
+ total = 0
122
+
123
+ progress = _build_progress(
124
+ total, desc, columns, theme, disable, min_interval, capture_output,
125
+ smoothing, leave, unit, unit_scale, unit_divisor, initial, delay,
126
+ )
127
+
128
+ progress.__enter__()
129
+ tracker = Tracker(iter(iterable), progress, task_id=task_id, owns_progress=True)
130
+ if capture_output:
131
+ # The C Tracker tears the progress down via close(), which bypasses
132
+ # the Python __exit__ that uninstalls stdout/stderr capture — so an
133
+ # exhausted track(capture_output=True) would otherwise leave sys.stdout
134
+ # permanently replaced. Guard the iteration so __exit__ always runs.
135
+ return _capture_guard(tracker, progress)
136
+ return tracker
137
+
138
+
139
+ def _capture_guard(tracker, progress):
140
+ """Yield from `tracker`, guaranteeing `progress.__exit__` runs on
141
+ exhaustion, early break (generator close), or exception — so the
142
+ stdout/stderr capture is always uninstalled."""
143
+ try:
144
+ yield from tracker
145
+ finally:
146
+ progress.__exit__(None, None, None)
147
+
148
+
149
+ # ---- Lazy layer ------------------------------------------------------------
150
+
151
+ def __getattr__(name):
152
+ # Lazy-load the Progress Python subclass on first access.
153
+ if name == "Progress":
154
+ from . import _progress
155
+ Progress = _progress.Progress
156
+ globals()["Progress"] = Progress
157
+ return Progress
158
+ # File-object progress wrapping (barflow.wrap_file / .wrapattr) is lazy so
159
+ # the byte-humanization import cost is only paid by callers that use it.
160
+ if name in ("wrap_file", "wrapattr"):
161
+ from . import _wrap
162
+ globals()["wrap_file"] = _wrap.wrap_file
163
+ globals()["wrapattr"] = _wrap.wrapattr
164
+ return globals()[name]
165
+ # Hand-rolled dispatch avoids importing `importlib` and building a dict
166
+ # at module-load time. Each branch resolves to a single __import__ call.
167
+ if name == "columns":
168
+ mod = __import__("barflow.columns", fromlist=("columns",))
169
+ elif name == "themes":
170
+ mod = __import__("barflow.themes", fromlist=("themes",))
171
+ elif name == "spinners":
172
+ mod = __import__("barflow.spinners", fromlist=("spinners",))
173
+ elif name == "aio":
174
+ mod = __import__("barflow.aio", fromlist=("aio",))
175
+ elif name == "hooks":
176
+ mod = __import__("barflow.hooks", fromlist=("hooks",))
177
+ else:
178
+ raise AttributeError(f"module 'barflow' has no attribute {name!r}")
179
+ globals()[name] = mod
180
+ return mod
Binary file