cs-progress


Namecs-progress JSON
Version 20241122 PyPI version JSON
download
home_pageNone
SummaryA progress tracker with methods for throughput, ETA and update notification; also a compound progress meter composed from other progress meters.
upload_time2024-11-22 00:53:03
maintainerNone
docs_urlNone
authorNone
requires_pythonNone
licenseGNU General Public License v3 or later (GPLv3+)
keywords python2 python3
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            A progress tracker with methods for throughput, ETA and update notification;
also a compound progress meter composed from other progress meters.

*Latest release 20241122*:
* BaseProgress.bar: default for report_print now comes from not BaseCommand.Options.quiet.
* BaseProgress.bar: always print the final report if report_print.

## <a name="auto_progressbar"></a>`auto_progressbar(*da, **dkw)`

Decorator for a function accepting an optional `progress`
keyword parameter.
If `progress` is `None` and the default `Upd` is not disabled,
run the function with a progress bar.

## <a name="BaseProgress"></a>Class `BaseProgress`

The base class for `Progress` and `OverProcess`
with various common methods.

Note that durations are in seconds
and that absolute time is in seconds since the UNIX epoch
(the basis of `time.time()`).

*`BaseProgress.__init__(self, name=None, start_time=None, units_scale=None)`*:
Initialise a progress instance.

Parameters:
* `name`: optional name
* `start_time`: optional UNIX epoch start time, default from `time.time()`
* `units_scale`: a scale for use with `cs.units.transcribe`,
  default `BINARY_BYTES_SCALE`

*`BaseProgress.__eq__(self, other)`*:
A Progress is equal to another object `other`
if its position equals `int(other)`.

*`BaseProgress.__ge__(self, other, NotImplemented=NotImplemented)`*:
Return a >= b.  Computed by @total_ordering from (not a < b).

*`BaseProgress.__gt__(self, other, NotImplemented=NotImplemented)`*:
Return a > b.  Computed by @total_ordering from (not a < b) and (a != b).

*`BaseProgress.__int__(self)`*:
`int(Progress)` returns the current position.

*`BaseProgress.__le__(self, other, NotImplemented=NotImplemented)`*:
Return a <= b.  Computed by @total_ordering from (a < b) or (a == b).

*`BaseProgress.__lt__(self, other)`*:
A Progress is less then another object `other`
if its position is less than `int(other)`.

*`BaseProgress.arrow(self, width, no_padding=False)`*:
Construct a progress arrow representing completion
to fit in the specified `width`.

*`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10a711cf0>, **kw)`*:
A context manager to create and withdraw a progress bar.
It returns the `UpdProxy` which displays the progress bar.

Parameters:
* `label`: a label for the progress bar,
  default from `self.name`.
* `statusfunc`: an optional function to compute the progress bar text
  accepting `(self,label,width)`.
* `width`: an optional width expressing how wide the progress bar
  text may be.
  The default comes from the `proxy.width` property.
* `recent_window`: optional timeframe to define "recent" in seconds;
  if the default `statusfunc` (`Progress.status`) is used
  this is passed to it
* `report_print`: optional `print` compatible function
  with which to write a report on completion;
  this may also be a `bool`, which if true will use `Upd.print`
  in order to interoperate with `Upd`.
* `stalled`: optional string to replace the word `'stalled'`
  in the status line; for a worked this might be betteer as `'idle'`
* `insert_pos`: where to insert the progress bar, default `1`
* `poll`: an optional callable accepting a `BaseProgress`
  which can be used to update the progress state before
  updating the progress bar display

Example use:

    # display progress reporting during upload_filename()
    # which updates the supplied Progress instance
    # during its operation
    P = Progress(name=label)
    with P.bar(report_print=True):
        upload_filename(src, progress=P)

*`BaseProgress.elapsed_time`*:
Time elapsed since `start_time`.

*`BaseProgress.eta`*:
The projected time of completion: now + `remaining_time`.

If `remaining_time` is `None`, this is also `None`.

*`BaseProgress.format_counter(self, value, scale=None, max_parts=2, sep=',', **kw)`*:
Format `value` accoridng to `scale` and `max_parts`
using `cs.units.transcribe`.

*`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, **bar_kw)`*:
An iterable progress bar: a generator yielding values
from the iterable `it` while updating a progress bar.

Parameters:
* `it`: the iterable to consume and yield.
* `label`: a label for the progress bar,
  default from `self.name`.
* `itemlenfunc`: an optional function returning the "size" of each item
  from `it`, used to advance `self.position`.
  The default is to assume a size of `1`.
  A convenient alternative choice may be the builtin function `len`.
* `incfirst`: whether to advance `self.position` before we
  `yield` an item from `it` or afterwards.
  This reflects whether it is considered that progress is
  made as items are obtained or only after items are processed
  by whatever is consuming this generator.
  The default is `False`, advancing after processing.
* `update_period`: default `DEFAULT_UPDATE_PERIOD`; if `0`
  then update on every iteration, otherwise every `update_period`
  seconds
Other parameters are passed to `Progress.bar`.

Example use:

    from cs.units import DECIMAL_SCALE
    rows = [some list of data]
    P = Progress(total=len(rows), units_scale=DECIMAL_SCALE)
    for row in P.iterbar(rows, incfirst=True):
        ... do something with each row ...

    f = open(data_filename, 'rb')
    datalen = os.stat(f).st_size
    def readfrom(f):
        while True:
            bs = f.read(65536)
            if not bs:
                break
            yield bs
    P = Progress(total=datalen)
    for bs in P.iterbar(readfrom(f), itemlenfunc=len):
        ... process the file data in bs ...

*`BaseProgress.ratio`*:
The fraction of progress completed: `(position-start)/(total-start)`.
Returns `None` if `total` is `None` or `total<=start`.

Example:

    >>> P = Progress()
     P.ratio
    >>> P.total = 16
    >>> P.ratio
    0.0
    >>> P.update(4)
    >>> P.ratio
    0.25

*`BaseProgress.remaining_time`*:
The projected time remaining to end
based on the `throughput` and `total`.

If `total` is `None`, this is `None`.

*`BaseProgress.status(self, label, width, recent_window=None, stalled=None)`*:
A progress string of the form:
*label*`: `*pos*`/`*total*` ==>  ETA '*time*

Parameters:
* `label`: the label for the status line;
  if `None` use `self.name`
* `width`: the available width for the status line;
  if not an `int` use `width.width`
* `recent_window`: optional timeframe to define "recent" in seconds,
  default : `5`
* `stalled`: the label to indicate no throughput, default `'stalled'`;
  for a worker this might often b better as `'idle'`

*`BaseProgress.text_pos_of_total(self, fmt=None, fmt_pos=None, fmt_total=None, pos_first=False)`*:
Return a "total:position" or "position/total" style progress string.

Parameters:
* `fmt`: format string interpolating `pos_text` and `total_text`.
  Default: `"{pos_text}/{total_text}"` if `pos_first`,
  otherwise `"{total_text}:{pos_text}"`
* `fmt_pos`: formatting function for `self.position`,
  default `self.format_counter`
* `fmt_total`: formatting function for `self.total`,
  default from `fmt_pos`
* `pos_first`: put the position first if true (default `False`),
  only consulted if `fmt` is `None`

*`BaseProgress.throughput`*:
The overall throughput: `self.throughput_overall()`.

By comparison,
the `Progress.throughput` property is `self.throughput_recent`
if the `throughput_window` is not `None`,
otherwise it falls back to `throughput_overall`.

*`BaseProgress.throughput_overall(self)`*:
The overall throughput from `start` to `position`
during `elapsed_time`.

*`BaseProgress.throughput_recent(self, time_window)`*:
The recent throughput. Implemented by subclasses.

## <a name="CheckPoint"></a>Class `CheckPoint(builtins.tuple)`

CheckPoint(time, position)

*`CheckPoint.position`*:
Alias for field number 1

*`CheckPoint.time`*:
Alias for field number 0

## <a name="OverProgress"></a>Class `OverProgress(BaseProgress)`

A `Progress`-like class computed from a set of subsidiary `Progress`es.

AN OverProgress instance has an attribute ``notify_update`` which
is a set of callables.
Whenever the position of a subsidiary `Progress` is updated,
each of these will be called with the `Progress` instance and `None`.

Example:

    >>> P = OverProgress(name="over")
    >>> P1 = Progress(name="progress1", position=12)
    >>> P1.total = 100
    >>> P1.advance(7)
    >>> P2 = Progress(name="progress2", position=20)
    >>> P2.total = 50
    >>> P2.advance(9)
    >>> P.add(P1)
    >>> P.add(P2)
    >>> P1.total
    100
    >>> P2.total
    50
    >>> P.total
    150
    >>> P1.start
    12
    >>> P2.start
    20
    >>> P.start
    0
    >>> P1.position
    19
    >>> P2.position
    29
    >>> P.position
    16

*`OverProgress.add(self, subprogress)`*:
Add a subsidairy `Progress` to the contributing set.

*`OverProgress.eta`*:
The `eta` is the maximum of the subsidiary etas.

*`OverProgress.position`*:
The `position` is the sum off the subsidiary position offsets
from their respective starts.

*`OverProgress.remove(self, subprogress, accrue=False)`*:
Remove a subsidairy `Progress` from the contributing set.

*`OverProgress.start`*:
We always return a starting value of 0.

*`OverProgress.throughput`*:
The `throughput` is the sum of the subsidiary throughputs.

*`OverProgress.throughput_recent(self, time_window)`*:
The `throughput_recent` is the sum of the subsidiary throughput_recentss.

*`OverProgress.total`*:
The `total` is the sum of the subsidiary totals.

## <a name="Progress"></a>Class `Progress(BaseProgress)`

A progress counter to track task completion with various utility methods.

Example:

    >>> P = Progress(name="example")
    >>> P                         #doctest: +ELLIPSIS
    Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]
    >>> P.advance(5)
    >>> P                         #doctest: +ELLIPSIS
    Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
    >>> P.total = 100
    >>> P                         #doctest: +ELLIPSIS
    Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]

A Progress instance has an attribute ``notify_update`` which
is a set of callables. Whenever the position is updated, each
of these will be called with the `Progress` instance and the
latest `CheckPoint`.

`Progress` objects also make a small pretense of being an integer.
The expression `int(progress)` returns the current position,
and `+=` and `-=` adjust the position.

This is convenient for coding, but importantly it is also
useful for discretionary use of a Progress with some other
object.
If you want to make a lightweight `Progress` capable class
you can set a position attribute to an `int`
and manipulate it carefully using `+=` and `-=` entirely.
If you decide to incur the cost of maintaining a `Progress` object
you can slot it in:

    # initial setup with just an int
    my_thing.amount = 0

    # later, or on some option, use a Progress instance
    my_thing.amount = Progress(my_thing.amount)

*`Progress.__init__(self, name: Optional[str] = None, *, position: Optional[float] = None, start: Optional[float] = None, start_time: Optional[float] = None, throughput_window: Optional[int] = None, total: Optional[float] = None, units_scale=None)`*:
Initialise the Progesss object.

Parameters:
* `position`: initial position, default `0`.
* `name`: optional name for this instance.
* `start`: starting position of progress range,
  default from `position`.
* `start_time`: start time of the process, default now.
* `throughput_window`: length of throughput time window in seconds,
  default None.
* `total`: expected completion value, default None.

*`Progress.__iadd__(self, delta)`*:
Operator += form of advance().

>>> P = Progress()
>>> P.position
0
>>> P += 4
>>> P.position
4
>>> P += 4
>>> P.position
8

*`Progress.__isub__(self, delta)`*:
Operator -= form of advance().

>>> P = Progress()
>>> P.position
0
>>> P += 4
>>> P.position
4
>>> P -= 4
>>> P.position
0

*`Progress.advance(self, delta, update_time=None)`*:
Record more progress, return the advanced position.

>>> P = Progress()
>>> P.position
0
>>> P.advance(4)
>>> P.position
4
>>> P.advance(4)
>>> P.position
8

*`Progress.advance_total(self, delta)`*:
Function form of addition to the total.

*`Progress.latest`*:
Latest datum.

*`Progress.position`*:
Latest position.

*`Progress.throughput`*:
Current throughput per second.

If `self.throughput_window` is not `None`,
calls `self.throughput_recent(throughput_window)`.
Otherwise call `self.throughput_overall()`.

*`Progress.throughput_recent(self, time_window)`*:
Recent throughput per second within a time window in seconds.

The time span overlapping the start of the window is included
on a flat pro rata basis.

*`Progress.total`*:
Return the current total.

*`Progress.update(self, new_position, update_time=None)`*:
Record more progress.

>>> P = Progress()
>>> P.position
0
>>> P.update(12)
>>> P.position
12

## <a name="progressbar"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10a7135b0>, **kw)`

Convenience function to construct and run a `Progress.iterbar`
wrapping the iterable `it`,
issuing and withdrawning a progress bar during the iteration.

Parameters:
* `it`: the iterable to consume
* `label`: optional label, doubles as the `Progress.name`
* `position`: optional starting position
* `total`: optional value for `Progress.total`,
  default from `len(it)` if supported.
* `units_scale`: optional units scale for `Progress`,
  default `UNSCALED_SCALE`

If `total` is `None` and `it` supports `len()`
then the `Progress.total` is set from it.

All arguments are passed through to `Progress.iterbar`.

Example use:

    for row in progressbar(rows):
        ... do something with row ...

## <a name="selftest"></a>`selftest(argv)`

Exercise some of the functionality.

# Release Log



*Release 20241122*:
* BaseProgress.bar: default for report_print now comes from not BaseCommand.Options.quiet.
* BaseProgress.bar: always print the final report if report_print.

*Release 20240412*:
* BaseProgress.status: fixes for the arrow_width computation.
* BaseProgress.bar: drop existing UpdProxy support, drop deferred, implement update_period using a ticker Thread.
* BaseProgress.bar: set update_period=DEFAULT_UPDATE_PERIOD by default.
* Progress.iterbar: drop preexisting UpdProxy support, update_frequency and update_min_size support.
* Progress: new advance_total(delta) method so that we have a callable for this.
* BaseProgress.bar: new optional poll parameter accepting a callable accepting a BaseProgress to update the state before updating the bar display.
* BaseProgress.bar: new stalled='stalled' parameter to specify the term for no recent throughput, workers might prefer 'idle'.
* progressbar() updated to match.

*Release 20230401*:
progressbar, BaseProgress.iterbar: use @uses_upd to provide a context Upd instance.

*Release 20230212*:
BaseProgress: new update_period=0.2 parameter to constraint updates by elapsed time.

*Release 20221207*:
* BaseProgress.format_counter: accept arbitrary keyword arguments to pass to cs.units.transcribe.
* Progress.__init__: accept floats instead of just ints.

*Release 20220918*:
Progress.iterbar: wrap the iteration in a try/finally for cleanup.

*Release 20211208*:
* Progress.__init__: make the first optional positional parameter be "name", make other parameters keyword only.
* Progress.bar: make "label" the first optional positional parameter, make others keyword only.

*Release 20210803*:
* progressbar,iterbar: accept optional RunState to cancel iteration.
* BaseProgress.iterbar: make update_min_size properly optional, was making update_frequency ineffective.

*Release 20210730*:
When there is no total just report position and no ETA.

*Release 20210717*:
Minor tweaks.

*Release 20210316*:
* Progress.iterbar: only update the status line once per iteration, either before or after the yield according to incfirst.
* Progress.iterbar: fix the meaning of update_frequency to count iterations, add update_min_size to count progress advance.

*Release 20210306*:
progressbar: accept new optional `position` parameter, used to initialise the Progress.

*Release 20201102.1*:
DISTINFO: fix module dependencies.

*Release 20201102*:
* Format/layout changes for the default status line.
* Progress.throughtput_recent: return None if no new positions beyond the starting position.
* BaseProgress.status: accept label=None (default to self.name) and width=UpdProxy (uses width.width).
* BaseProgress.status: new optional window parameter, default 5, defining the recent throughput window size in seconds.
* A few bugfixes.

*Release 20201025*:
* Some formatting improvements.
* BaseProgress.bar: new insert_pos parameter to position the progress bar, default still 1.
* BaseProgress.bar: new deferred parameter putting off the status bar until the first update.
* BaseProgress.bar: accept new optional `proxy` parameter to use (and not delete) an existing UpdProxy for display.
* Progress.text_pos_of_total: new `pos_first=False` parameter, rendering the total before the position by default (less progress bar noise).
* New @auto_progressbar decorator to provide a progress bar and initialise progress= parameter to functions which can use a Progress for reporting.
* Assorted fixes.

*Release 20200718.3*:
BaseProgress.bar, progressbar: new optional report_print parameter for reporting on completion.

*Release 20200718.2*:
Bugfix: BaseProgress.status: handle throughput=0 when total=None.

*Release 20200718.1*:
BaseProgress.bar, progressbar: new optional update_frequency parameter for less frequent updates.

*Release 20200718*:
* Readability improvement for default status line.
* progressbar: default units_scale=UNSCALED_SCALE.

*Release 20200716.1*:
BaseProgress.status: round throughput to an int if >=10.

*Release 20200716*:
* BaseProgress.status: distinguish "idle" (position >= total) from "stalled" (position < total).
* BaseProgress.status: make the status very short if the progress is idle.

*Release 20200627*:
* BaseProgress.status: handle throughput=None (before any activity).
* BaseProgress: drop count_of_total_bytes_text, superceded by format_counter (which honours the units_scale).

*Release 20200626*:
* New Progress.bar generator method iterating over an iterable while displaying a progress bar.
* New convenience function progressbar(it,...) which rolls its own Progress instance.
* Progress: always support a throughput window, default to DEFAULT_THROUGHPUT_WINDOW = 5s.
* Improve the default progress bar render returned by Progress.status().

*Release 20200613*:
* BaseProgress, Progress and OverProgress now accept an optional units_scale, such as cs.units.UNSCALED_SCALE, to use when expressing progress - the default remains BINARY_SCALE.
* New arrow(), format_counter() and text_pos_of_total() methods to produce components of the status string for tuning or external reuse.

*Release 20200520*:
OverProgress: throughput and eta implementations.

*Release 20200129.3*:
Test __version__ machinery again.

*Release 20200129.2*:
set __version__ to '20200129.2'

*Release 20200129.1*:
Dummy release to test new __version__.

*Release 20200129*:
New Progress.count_of_total_bytes_text property presenting "3kB/40MB" style text.

*Release 20190812*:
* New OverProgress class which is a composite of a set of subsidiary Progress instances.
* Assorted other small updates.

*Release 20190220*:
* Progress: be somewhat like an int.
* New status() method returning a convenient one line progress status report.

*Release 20180703.2*:
Progress: make .total into a property in order to fire the update notifications.

*Release 20180703.1*:
Progress: additions and changes to API: new .ratio, .elapsed_time, rename .projected to .remaining_time.

*Release 20180703*:
Initial release of cs.progress.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "cs-progress",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "python2, python3",
    "author": null,
    "author_email": "Cameron Simpson <cs@cskk.id.au>",
    "download_url": "https://files.pythonhosted.org/packages/74/b9/3e7094961ad01e0acb216ee676eac2c3c34591b1819f92b9105614e2461b/cs_progress-20241122.tar.gz",
    "platform": null,
    "description": "A progress tracker with methods for throughput, ETA and update notification;\nalso a compound progress meter composed from other progress meters.\n\n*Latest release 20241122*:\n* BaseProgress.bar: default for report_print now comes from not BaseCommand.Options.quiet.\n* BaseProgress.bar: always print the final report if report_print.\n\n## <a name=\"auto_progressbar\"></a>`auto_progressbar(*da, **dkw)`\n\nDecorator for a function accepting an optional `progress`\nkeyword parameter.\nIf `progress` is `None` and the default `Upd` is not disabled,\nrun the function with a progress bar.\n\n## <a name=\"BaseProgress\"></a>Class `BaseProgress`\n\nThe base class for `Progress` and `OverProcess`\nwith various common methods.\n\nNote that durations are in seconds\nand that absolute time is in seconds since the UNIX epoch\n(the basis of `time.time()`).\n\n*`BaseProgress.__init__(self, name=None, start_time=None, units_scale=None)`*:\nInitialise a progress instance.\n\nParameters:\n* `name`: optional name\n* `start_time`: optional UNIX epoch start time, default from `time.time()`\n* `units_scale`: a scale for use with `cs.units.transcribe`,\n  default `BINARY_BYTES_SCALE`\n\n*`BaseProgress.__eq__(self, other)`*:\nA Progress is equal to another object `other`\nif its position equals `int(other)`.\n\n*`BaseProgress.__ge__(self, other, NotImplemented=NotImplemented)`*:\nReturn a >= b.  Computed by @total_ordering from (not a < b).\n\n*`BaseProgress.__gt__(self, other, NotImplemented=NotImplemented)`*:\nReturn a > b.  Computed by @total_ordering from (not a < b) and (a != b).\n\n*`BaseProgress.__int__(self)`*:\n`int(Progress)` returns the current position.\n\n*`BaseProgress.__le__(self, other, NotImplemented=NotImplemented)`*:\nReturn a <= b.  Computed by @total_ordering from (a < b) or (a == b).\n\n*`BaseProgress.__lt__(self, other)`*:\nA Progress is less then another object `other`\nif its position is less than `int(other)`.\n\n*`BaseProgress.arrow(self, width, no_padding=False)`*:\nConstruct a progress arrow representing completion\nto fit in the specified `width`.\n\n*`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10a711cf0>, **kw)`*:\nA context manager to create and withdraw a progress bar.\nIt returns the `UpdProxy` which displays the progress bar.\n\nParameters:\n* `label`: a label for the progress bar,\n  default from `self.name`.\n* `statusfunc`: an optional function to compute the progress bar text\n  accepting `(self,label,width)`.\n* `width`: an optional width expressing how wide the progress bar\n  text may be.\n  The default comes from the `proxy.width` property.\n* `recent_window`: optional timeframe to define \"recent\" in seconds;\n  if the default `statusfunc` (`Progress.status`) is used\n  this is passed to it\n* `report_print`: optional `print` compatible function\n  with which to write a report on completion;\n  this may also be a `bool`, which if true will use `Upd.print`\n  in order to interoperate with `Upd`.\n* `stalled`: optional string to replace the word `'stalled'`\n  in the status line; for a worked this might be betteer as `'idle'`\n* `insert_pos`: where to insert the progress bar, default `1`\n* `poll`: an optional callable accepting a `BaseProgress`\n  which can be used to update the progress state before\n  updating the progress bar display\n\nExample use:\n\n    # display progress reporting during upload_filename()\n    # which updates the supplied Progress instance\n    # during its operation\n    P = Progress(name=label)\n    with P.bar(report_print=True):\n        upload_filename(src, progress=P)\n\n*`BaseProgress.elapsed_time`*:\nTime elapsed since `start_time`.\n\n*`BaseProgress.eta`*:\nThe projected time of completion: now + `remaining_time`.\n\nIf `remaining_time` is `None`, this is also `None`.\n\n*`BaseProgress.format_counter(self, value, scale=None, max_parts=2, sep=',', **kw)`*:\nFormat `value` accoridng to `scale` and `max_parts`\nusing `cs.units.transcribe`.\n\n*`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, **bar_kw)`*:\nAn iterable progress bar: a generator yielding values\nfrom the iterable `it` while updating a progress bar.\n\nParameters:\n* `it`: the iterable to consume and yield.\n* `label`: a label for the progress bar,\n  default from `self.name`.\n* `itemlenfunc`: an optional function returning the \"size\" of each item\n  from `it`, used to advance `self.position`.\n  The default is to assume a size of `1`.\n  A convenient alternative choice may be the builtin function `len`.\n* `incfirst`: whether to advance `self.position` before we\n  `yield` an item from `it` or afterwards.\n  This reflects whether it is considered that progress is\n  made as items are obtained or only after items are processed\n  by whatever is consuming this generator.\n  The default is `False`, advancing after processing.\n* `update_period`: default `DEFAULT_UPDATE_PERIOD`; if `0`\n  then update on every iteration, otherwise every `update_period`\n  seconds\nOther parameters are passed to `Progress.bar`.\n\nExample use:\n\n    from cs.units import DECIMAL_SCALE\n    rows = [some list of data]\n    P = Progress(total=len(rows), units_scale=DECIMAL_SCALE)\n    for row in P.iterbar(rows, incfirst=True):\n        ... do something with each row ...\n\n    f = open(data_filename, 'rb')\n    datalen = os.stat(f).st_size\n    def readfrom(f):\n        while True:\n            bs = f.read(65536)\n            if not bs:\n                break\n            yield bs\n    P = Progress(total=datalen)\n    for bs in P.iterbar(readfrom(f), itemlenfunc=len):\n        ... process the file data in bs ...\n\n*`BaseProgress.ratio`*:\nThe fraction of progress completed: `(position-start)/(total-start)`.\nReturns `None` if `total` is `None` or `total<=start`.\n\nExample:\n\n    >>> P = Progress()\n     P.ratio\n    >>> P.total = 16\n    >>> P.ratio\n    0.0\n    >>> P.update(4)\n    >>> P.ratio\n    0.25\n\n*`BaseProgress.remaining_time`*:\nThe projected time remaining to end\nbased on the `throughput` and `total`.\n\nIf `total` is `None`, this is `None`.\n\n*`BaseProgress.status(self, label, width, recent_window=None, stalled=None)`*:\nA progress string of the form:\n*label*`: `*pos*`/`*total*` ==>  ETA '*time*\n\nParameters:\n* `label`: the label for the status line;\n  if `None` use `self.name`\n* `width`: the available width for the status line;\n  if not an `int` use `width.width`\n* `recent_window`: optional timeframe to define \"recent\" in seconds,\n  default : `5`\n* `stalled`: the label to indicate no throughput, default `'stalled'`;\n  for a worker this might often b better as `'idle'`\n\n*`BaseProgress.text_pos_of_total(self, fmt=None, fmt_pos=None, fmt_total=None, pos_first=False)`*:\nReturn a \"total:position\" or \"position/total\" style progress string.\n\nParameters:\n* `fmt`: format string interpolating `pos_text` and `total_text`.\n  Default: `\"{pos_text}/{total_text}\"` if `pos_first`,\n  otherwise `\"{total_text}:{pos_text}\"`\n* `fmt_pos`: formatting function for `self.position`,\n  default `self.format_counter`\n* `fmt_total`: formatting function for `self.total`,\n  default from `fmt_pos`\n* `pos_first`: put the position first if true (default `False`),\n  only consulted if `fmt` is `None`\n\n*`BaseProgress.throughput`*:\nThe overall throughput: `self.throughput_overall()`.\n\nBy comparison,\nthe `Progress.throughput` property is `self.throughput_recent`\nif the `throughput_window` is not `None`,\notherwise it falls back to `throughput_overall`.\n\n*`BaseProgress.throughput_overall(self)`*:\nThe overall throughput from `start` to `position`\nduring `elapsed_time`.\n\n*`BaseProgress.throughput_recent(self, time_window)`*:\nThe recent throughput. Implemented by subclasses.\n\n## <a name=\"CheckPoint\"></a>Class `CheckPoint(builtins.tuple)`\n\nCheckPoint(time, position)\n\n*`CheckPoint.position`*:\nAlias for field number 1\n\n*`CheckPoint.time`*:\nAlias for field number 0\n\n## <a name=\"OverProgress\"></a>Class `OverProgress(BaseProgress)`\n\nA `Progress`-like class computed from a set of subsidiary `Progress`es.\n\nAN OverProgress instance has an attribute ``notify_update`` which\nis a set of callables.\nWhenever the position of a subsidiary `Progress` is updated,\neach of these will be called with the `Progress` instance and `None`.\n\nExample:\n\n    >>> P = OverProgress(name=\"over\")\n    >>> P1 = Progress(name=\"progress1\", position=12)\n    >>> P1.total = 100\n    >>> P1.advance(7)\n    >>> P2 = Progress(name=\"progress2\", position=20)\n    >>> P2.total = 50\n    >>> P2.advance(9)\n    >>> P.add(P1)\n    >>> P.add(P2)\n    >>> P1.total\n    100\n    >>> P2.total\n    50\n    >>> P.total\n    150\n    >>> P1.start\n    12\n    >>> P2.start\n    20\n    >>> P.start\n    0\n    >>> P1.position\n    19\n    >>> P2.position\n    29\n    >>> P.position\n    16\n\n*`OverProgress.add(self, subprogress)`*:\nAdd a subsidairy `Progress` to the contributing set.\n\n*`OverProgress.eta`*:\nThe `eta` is the maximum of the subsidiary etas.\n\n*`OverProgress.position`*:\nThe `position` is the sum off the subsidiary position offsets\nfrom their respective starts.\n\n*`OverProgress.remove(self, subprogress, accrue=False)`*:\nRemove a subsidairy `Progress` from the contributing set.\n\n*`OverProgress.start`*:\nWe always return a starting value of 0.\n\n*`OverProgress.throughput`*:\nThe `throughput` is the sum of the subsidiary throughputs.\n\n*`OverProgress.throughput_recent(self, time_window)`*:\nThe `throughput_recent` is the sum of the subsidiary throughput_recentss.\n\n*`OverProgress.total`*:\nThe `total` is the sum of the subsidiary totals.\n\n## <a name=\"Progress\"></a>Class `Progress(BaseProgress)`\n\nA progress counter to track task completion with various utility methods.\n\nExample:\n\n    >>> P = Progress(name=\"example\")\n    >>> P                         #doctest: +ELLIPSIS\n    Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]\n    >>> P.advance(5)\n    >>> P                         #doctest: +ELLIPSIS\n    Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]\n    >>> P.total = 100\n    >>> P                         #doctest: +ELLIPSIS\n    Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]\n\nA Progress instance has an attribute ``notify_update`` which\nis a set of callables. Whenever the position is updated, each\nof these will be called with the `Progress` instance and the\nlatest `CheckPoint`.\n\n`Progress` objects also make a small pretense of being an integer.\nThe expression `int(progress)` returns the current position,\nand `+=` and `-=` adjust the position.\n\nThis is convenient for coding, but importantly it is also\nuseful for discretionary use of a Progress with some other\nobject.\nIf you want to make a lightweight `Progress` capable class\nyou can set a position attribute to an `int`\nand manipulate it carefully using `+=` and `-=` entirely.\nIf you decide to incur the cost of maintaining a `Progress` object\nyou can slot it in:\n\n    # initial setup with just an int\n    my_thing.amount = 0\n\n    # later, or on some option, use a Progress instance\n    my_thing.amount = Progress(my_thing.amount)\n\n*`Progress.__init__(self, name: Optional[str] = None, *, position: Optional[float] = None, start: Optional[float] = None, start_time: Optional[float] = None, throughput_window: Optional[int] = None, total: Optional[float] = None, units_scale=None)`*:\nInitialise the Progesss object.\n\nParameters:\n* `position`: initial position, default `0`.\n* `name`: optional name for this instance.\n* `start`: starting position of progress range,\n  default from `position`.\n* `start_time`: start time of the process, default now.\n* `throughput_window`: length of throughput time window in seconds,\n  default None.\n* `total`: expected completion value, default None.\n\n*`Progress.__iadd__(self, delta)`*:\nOperator += form of advance().\n\n>>> P = Progress()\n>>> P.position\n0\n>>> P += 4\n>>> P.position\n4\n>>> P += 4\n>>> P.position\n8\n\n*`Progress.__isub__(self, delta)`*:\nOperator -= form of advance().\n\n>>> P = Progress()\n>>> P.position\n0\n>>> P += 4\n>>> P.position\n4\n>>> P -= 4\n>>> P.position\n0\n\n*`Progress.advance(self, delta, update_time=None)`*:\nRecord more progress, return the advanced position.\n\n>>> P = Progress()\n>>> P.position\n0\n>>> P.advance(4)\n>>> P.position\n4\n>>> P.advance(4)\n>>> P.position\n8\n\n*`Progress.advance_total(self, delta)`*:\nFunction form of addition to the total.\n\n*`Progress.latest`*:\nLatest datum.\n\n*`Progress.position`*:\nLatest position.\n\n*`Progress.throughput`*:\nCurrent throughput per second.\n\nIf `self.throughput_window` is not `None`,\ncalls `self.throughput_recent(throughput_window)`.\nOtherwise call `self.throughput_overall()`.\n\n*`Progress.throughput_recent(self, time_window)`*:\nRecent throughput per second within a time window in seconds.\n\nThe time span overlapping the start of the window is included\non a flat pro rata basis.\n\n*`Progress.total`*:\nReturn the current total.\n\n*`Progress.update(self, new_position, update_time=None)`*:\nRecord more progress.\n\n>>> P = Progress()\n>>> P.position\n0\n>>> P.update(12)\n>>> P.position\n12\n\n## <a name=\"progressbar\"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10a7135b0>, **kw)`\n\nConvenience function to construct and run a `Progress.iterbar`\nwrapping the iterable `it`,\nissuing and withdrawning a progress bar during the iteration.\n\nParameters:\n* `it`: the iterable to consume\n* `label`: optional label, doubles as the `Progress.name`\n* `position`: optional starting position\n* `total`: optional value for `Progress.total`,\n  default from `len(it)` if supported.\n* `units_scale`: optional units scale for `Progress`,\n  default `UNSCALED_SCALE`\n\nIf `total` is `None` and `it` supports `len()`\nthen the `Progress.total` is set from it.\n\nAll arguments are passed through to `Progress.iterbar`.\n\nExample use:\n\n    for row in progressbar(rows):\n        ... do something with row ...\n\n## <a name=\"selftest\"></a>`selftest(argv)`\n\nExercise some of the functionality.\n\n# Release Log\n\n\n\n*Release 20241122*:\n* BaseProgress.bar: default for report_print now comes from not BaseCommand.Options.quiet.\n* BaseProgress.bar: always print the final report if report_print.\n\n*Release 20240412*:\n* BaseProgress.status: fixes for the arrow_width computation.\n* BaseProgress.bar: drop existing UpdProxy support, drop deferred, implement update_period using a ticker Thread.\n* BaseProgress.bar: set update_period=DEFAULT_UPDATE_PERIOD by default.\n* Progress.iterbar: drop preexisting UpdProxy support, update_frequency and update_min_size support.\n* Progress: new advance_total(delta) method so that we have a callable for this.\n* BaseProgress.bar: new optional poll parameter accepting a callable accepting a BaseProgress to update the state before updating the bar display.\n* BaseProgress.bar: new stalled='stalled' parameter to specify the term for no recent throughput, workers might prefer 'idle'.\n* progressbar() updated to match.\n\n*Release 20230401*:\nprogressbar, BaseProgress.iterbar: use @uses_upd to provide a context Upd instance.\n\n*Release 20230212*:\nBaseProgress: new update_period=0.2 parameter to constraint updates by elapsed time.\n\n*Release 20221207*:\n* BaseProgress.format_counter: accept arbitrary keyword arguments to pass to cs.units.transcribe.\n* Progress.__init__: accept floats instead of just ints.\n\n*Release 20220918*:\nProgress.iterbar: wrap the iteration in a try/finally for cleanup.\n\n*Release 20211208*:\n* Progress.__init__: make the first optional positional parameter be \"name\", make other parameters keyword only.\n* Progress.bar: make \"label\" the first optional positional parameter, make others keyword only.\n\n*Release 20210803*:\n* progressbar,iterbar: accept optional RunState to cancel iteration.\n* BaseProgress.iterbar: make update_min_size properly optional, was making update_frequency ineffective.\n\n*Release 20210730*:\nWhen there is no total just report position and no ETA.\n\n*Release 20210717*:\nMinor tweaks.\n\n*Release 20210316*:\n* Progress.iterbar: only update the status line once per iteration, either before or after the yield according to incfirst.\n* Progress.iterbar: fix the meaning of update_frequency to count iterations, add update_min_size to count progress advance.\n\n*Release 20210306*:\nprogressbar: accept new optional `position` parameter, used to initialise the Progress.\n\n*Release 20201102.1*:\nDISTINFO: fix module dependencies.\n\n*Release 20201102*:\n* Format/layout changes for the default status line.\n* Progress.throughtput_recent: return None if no new positions beyond the starting position.\n* BaseProgress.status: accept label=None (default to self.name) and width=UpdProxy (uses width.width).\n* BaseProgress.status: new optional window parameter, default 5, defining the recent throughput window size in seconds.\n* A few bugfixes.\n\n*Release 20201025*:\n* Some formatting improvements.\n* BaseProgress.bar: new insert_pos parameter to position the progress bar, default still 1.\n* BaseProgress.bar: new deferred parameter putting off the status bar until the first update.\n* BaseProgress.bar: accept new optional `proxy` parameter to use (and not delete) an existing UpdProxy for display.\n* Progress.text_pos_of_total: new `pos_first=False` parameter, rendering the total before the position by default (less progress bar noise).\n* New @auto_progressbar decorator to provide a progress bar and initialise progress= parameter to functions which can use a Progress for reporting.\n* Assorted fixes.\n\n*Release 20200718.3*:\nBaseProgress.bar, progressbar: new optional report_print parameter for reporting on completion.\n\n*Release 20200718.2*:\nBugfix: BaseProgress.status: handle throughput=0 when total=None.\n\n*Release 20200718.1*:\nBaseProgress.bar, progressbar: new optional update_frequency parameter for less frequent updates.\n\n*Release 20200718*:\n* Readability improvement for default status line.\n* progressbar: default units_scale=UNSCALED_SCALE.\n\n*Release 20200716.1*:\nBaseProgress.status: round throughput to an int if >=10.\n\n*Release 20200716*:\n* BaseProgress.status: distinguish \"idle\" (position >= total) from \"stalled\" (position < total).\n* BaseProgress.status: make the status very short if the progress is idle.\n\n*Release 20200627*:\n* BaseProgress.status: handle throughput=None (before any activity).\n* BaseProgress: drop count_of_total_bytes_text, superceded by format_counter (which honours the units_scale).\n\n*Release 20200626*:\n* New Progress.bar generator method iterating over an iterable while displaying a progress bar.\n* New convenience function progressbar(it,...) which rolls its own Progress instance.\n* Progress: always support a throughput window, default to DEFAULT_THROUGHPUT_WINDOW = 5s.\n* Improve the default progress bar render returned by Progress.status().\n\n*Release 20200613*:\n* BaseProgress, Progress and OverProgress now accept an optional units_scale, such as cs.units.UNSCALED_SCALE, to use when expressing progress - the default remains BINARY_SCALE.\n* New arrow(), format_counter() and text_pos_of_total() methods to produce components of the status string for tuning or external reuse.\n\n*Release 20200520*:\nOverProgress: throughput and eta implementations.\n\n*Release 20200129.3*:\nTest __version__ machinery again.\n\n*Release 20200129.2*:\nset __version__ to '20200129.2'\n\n*Release 20200129.1*:\nDummy release to test new __version__.\n\n*Release 20200129*:\nNew Progress.count_of_total_bytes_text property presenting \"3kB/40MB\" style text.\n\n*Release 20190812*:\n* New OverProgress class which is a composite of a set of subsidiary Progress instances.\n* Assorted other small updates.\n\n*Release 20190220*:\n* Progress: be somewhat like an int.\n* New status() method returning a convenient one line progress status report.\n\n*Release 20180703.2*:\nProgress: make .total into a property in order to fire the update notifications.\n\n*Release 20180703.1*:\nProgress: additions and changes to API: new .ratio, .elapsed_time, rename .projected to .remaining_time.\n\n*Release 20180703*:\nInitial release of cs.progress.\n",
    "bugtrack_url": null,
    "license": "GNU General Public License v3 or later (GPLv3+)",
    "summary": "A progress tracker with methods for throughput, ETA and update notification; also a compound progress meter composed from other progress meters.",
    "version": "20241122",
    "project_urls": {
        "MonoRepo Commits": "https://bitbucket.org/cameron_simpson/css/commits/branch/main",
        "Monorepo Git Mirror": "https://github.com/cameron-simpson/css",
        "Monorepo Hg/Mercurial Mirror": "https://hg.sr.ht/~cameron-simpson/css",
        "Source": "https://github.com/cameron-simpson/css/blob/main/lib/python/cs/progress.py"
    },
    "split_keywords": [
        "python2",
        " python3"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "77aabfa2176fabc9a4f21fb560d1efe86b4571757aa3fbeee7e13e80b99a3ce5",
                "md5": "2c8616a55f1e9549e09671005932a2e9",
                "sha256": "c0a9b524f0d0a6d07e418e98b12e47daf3f536676a0e624f7e4fcff4d749a3cf"
            },
            "downloads": -1,
            "filename": "cs_progress-20241122-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2c8616a55f1e9549e09671005932a2e9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 17095,
            "upload_time": "2024-11-22T00:53:01",
            "upload_time_iso_8601": "2024-11-22T00:53:01.403675Z",
            "url": "https://files.pythonhosted.org/packages/77/aa/bfa2176fabc9a4f21fb560d1efe86b4571757aa3fbeee7e13e80b99a3ce5/cs_progress-20241122-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "74b93e7094961ad01e0acb216ee676eac2c3c34591b1819f92b9105614e2461b",
                "md5": "af09372d5caa102ca49e059afcd30a74",
                "sha256": "d86f53be3889503f39680db6828335c9e0b1b9f4499a5b26b78b7bde02ed02e3"
            },
            "downloads": -1,
            "filename": "cs_progress-20241122.tar.gz",
            "has_sig": false,
            "md5_digest": "af09372d5caa102ca49e059afcd30a74",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 21431,
            "upload_time": "2024-11-22T00:53:03",
            "upload_time_iso_8601": "2024-11-22T00:53:03.798355Z",
            "url": "https://files.pythonhosted.org/packages/74/b9/3e7094961ad01e0acb216ee676eac2c3c34591b1819f92b9105614e2461b/cs_progress-20241122.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-22 00:53:03",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "cameron-simpson",
    "github_project": "css",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "cs-progress"
}
        
Elapsed time: 0.35555s