/smooth-progressbar

A smooth progress bar

Primary LanguagePythonGNU General Public License v3.0GPL-3.0


smooth-progressbar:

Description:

This progress bar is a tool that allows users to monitor the progress of long-running tasks, such as data loading and cleaning, and make sure that the task is progressing as expected. The progress bar can also be set to display a message or a comment alongside the progress, providing more information about the current stage of the task. This can be especially useful for debugging or troubleshooting. The library includes examples, which can be found in the tests folder, that demonstrate how to use the progress bar in different contexts. Additionally, the size of the progress bar is calculated according to the terminal environment, so it will always fit the available space and be easy to read. This feature makes it easy to integrate the progress bar into different environments, whether you're working on a local machine or a remote server. Overall, this Python progress bar project is a useful tool for anyone who wants to track the progress of a task or process, and make sure that it's running smoothly.

Use:

import time
from smoothprogressbar import SmoothProgressBar
my_progressbar = SmoothProgressBar()
my_progressbar.start(10)

for i in range(1, 11):
    my_progressbar.update(i, "task "+str(i))
    time.sleep(2)
my_progressbar.stop()

Compatibility:

Python 3.7+

Setup:

  • User:

Get the package:

git clone https://github.com/francois-le-ko4la/smooth-progressbar.git

Change to the folder:

cd smooth-progressbar

Install with make on Linux/Unix/MacOS or use pip3 otherwise:

make install
  • Dev environment:

Get the package:

git clone https://github.com/francois-le-ko4la/smooth-progressbar.git

Change to the folder:

cd smooth-progressbar

Create your environment with all dev prerequisites and install the package:

make venv
source venv/bin/activate
make dev

Test:

This module has been tested and validated on Ubuntu. Test is available if you set up the package with dev environment.

make test

License:

This package is distributed under the GPLv3 license

Todo:

  • Create the project
  • Write code and tests
  • Test installation and requirements (setup.py and/or Makefile)
  • Test code
  • Validate features
  • Write Doc/stringdoc
  • Run PEP8 validation
  • Clean & last check
  • Release 0.3.0
  • add stubs
  • update pyproject.toml
  • update doc
  • Release 0.3.1

Dev notes

TOML file:

# -*- coding: utf-8 -*-
[project]
name = "smoothprogressbar"
version = "0.3.1"
authors = [
  {name = "ko4la" }
]
description = "Smoothprogressbar."
license = {file = "LICENSE"}
readme = "README.md"
requires-python = ">=3.7"
classifiers = [
    "Development Status :: 5 - Stable",
    "Environment :: Console",
    "Intended Audience :: Developers",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3 :: Only",
    "OSI Approved :: GNU General Public License v3 (GPLv3)",
]
dependencies = [
    "importlib-metadata ~= 1.0 ; python_version < '3.8'"
    ]

[project.optional-dependencies]
dev = [
    "pycodestyle>=2.3.1",
    "pytest>=7.2.0",
    "pylint",
    "mypy",
    "pydocstyle",
    "pytest-pylint",
    "pytest-pycodestyle",
    "pytest-mypy",
    "pytest-pydocstyle",
    "pytest-isort",
    "types-setuptools"]

[project.urls]
"Homepage" = "https://github.com/francois-le-ko4la/smooth-progressbar"

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[tool.pytest.ini_options]
minversion = "7.2"
addopts = [
    "-v",
    "--pycodestyle",
    "--doctest-modules",
    "--mypy",
    "--pydocstyle",
    "--pylint",
    "--isort",
    "--strict-markers"
]
xfail_strict = true
filterwarnings = [
    "ignore:.*U.*mode is deprecated:DeprecationWarning",
    "ignore::DeprecationWarning"]

[tool.mypy]
disallow_any_generics = true
disallow_untyped_defs = true
warn_redundant_casts = true
strict_equality = true


UML Diagram:

classDiagram
  class TextIOWrapper {
    close()
    detach()
    fileno()
    flush()
    isatty()
    read()
    readable()
    readline()
    readlines()
    reconfigure()
    seek()
    seekable()
    tell()
    truncate()
    writable()
    write()
    writelines()
  }
  class _IOBase {
    close()
    fileno()
    flush()
    isatty()
    readable()
    readline()
    readlines()
    seek()
    seekable()
    tell()
    truncate()
    writable()
    writelines()
  }
  class _TextIOBase {
    close()
    detach()
    fileno()
    flush()
    isatty()
    read()
    readable()
    readline()
    readlines()
    seek()
    seekable()
    tell()
    truncate()
    writable()
    write()
    writelines()
  }
  class RLock {
    acquire()
    release()
  }
  class deque {
    iterable : list
    maxlen : int
    append(x)
    appendleft(x)
    clear()
    copy()
    count(x)
    extend(iterable)
    extendleft(iterable)
    index(x, start, end)
    insert(i, x)
    pop()
    popleft()
    remove(value)
    reverse()
    rotate(n)
  }
  class date {
    day
    month
    year
    ctime()
    fromisocalendar(year, week, day)
    fromisoformat(date_string)
    fromordinal(n)
    fromtimestamp(t)
    isocalendar()
    isoformat()
    isoweekday()
    replace(year, month, day)
    strftime(fmt)
    timetuple()
    today()
    toordinal()
    weekday()
  }
  class datetime {
    fold
    hour
    microsecond
    minute
    second
    tzinfo
    astimezone(tz)
    combine(date, time, tzinfo)
    ctime()
    date()
    dst()
    fromisoformat(date_string)
    fromtimestamp(t, tz)
    isoformat(sep, timespec)
    now(tz)
    replace(year, month, day, hour, minute, second, microsecond, tzinfo)
    strptime(date_string, format)
    time()
    timestamp()
    timetuple()
    timetz()
    tzname()
    utcfromtimestamp(t)
    utcnow()
    utcoffset()
    utctimetuple()
  }
  class Enum {
    name()
    value()
  }
  class Theme {
    name
  }
  class Console {
    size
    addmsg(msg: str) Console
    addtab() Console
    emptyline() Console
    goback() Console
    newline() Console
    print() None
  }
  class ConsolePrgBr {
    progress_label : str
    size_widgt_label_label : int
    size_widgt_percent : int
    get() str
    update(size: int, percent: Percent, msg: str, elapse: str) ConsolePrgBr
  }
  class ConsoleProgress {
    max_size
    tag_beg : str
    tag_end : str
    text
    update(size: int, ratio: float) ConsoleProgress
  }
  class ConsoleString {
    current_text_size
    enable
    max_size
    max_size : int
    max_text_size
    tag_beg : str
    tag_end : str
    tag_size
    text : str
    align_left() ConsoleString
    align_right() ConsoleString
    update(text: Optional[str], max_size: Optional[int], tag_beg: Optional[str], tag_end: Optional[str]) ConsoleString
  }
  class ElapseTime {
    start() None
  }
  class MultiThread {
    func
    run() None
    stop() None
  }
  class Percent {
    part
    part : int
    value
    whole
  }
  class SmoothProgressBar {
    msg
    start(max_value: int) None
    stop() None
    update(value: int, msg: str) None
  }
  class Condition {
    acquire
    release
    notify(n)
    notifyAll()
    notify_all()
    wait(timeout)
    wait_for(predicate, timeout)
  }
  class Event {
    clear()
    isSet()
    is_set()
    set()
    wait(timeout)
  }
  class Thread {
    daemon
    daemon
    ident
    name
    name
    native_id
    getName()
    isDaemon()
    is_alive()
    join(timeout)
    run()
    setDaemon(daemonic)
    setName(name)
    start()
  }
  class Timer {
    args : list, NoneType
    finished
    function
    interval
    kwargs : dict, NoneType
    cancel()
    run()
  }
  class _RLock {
    acquire(blocking, timeout)
    release()
  }
  class lock {
    acquire(blocking, timeout)
    locked()
    release()
  }
  TextIOWrapper --|> _TextIOBase
  _TextIOBase --|> _IOBase
  datetime --|> date
  Theme --|> Enum
  ConsoleProgress --|> ConsoleString
  MultiThread --|> Thread
  Timer --|> Thread
  TextIOWrapper --* Thread : _stderr
  RLock --* Condition : _lock
  deque --* Condition : _waiters
  datetime --* ElapseTime : __start_time
  datetime --* ElapseTime : __update_time
  Console --* SmoothProgressBar : __console
  ConsolePrgBr --* SmoothProgressBar : __prgbr
  ConsoleProgress --* ConsolePrgBr : __widgt_progress
  ConsoleString --* ConsolePrgBr : __widgt_label
  ConsoleString --* ConsolePrgBr : __widgt_percent
  ConsoleString --* ConsolePrgBr : __widgt_elapse
  ConsoleString --* ConsolePrgBr : __widgt_msg
  ElapseTime --* SmoothProgressBar : __elapse
  MultiThread --* SmoothProgressBar : __mthr
  Percent --* SmoothProgressBar : __percent
  Percent --* SmoothProgressBar : __percent
  Condition --* Event : _cond
  Event --* Thread : _started
  Event --* Timer : finished
  Timer --* MultiThread : __timer
  Timer --* MultiThread : __timer
  _RLock --* Condition : _lock
  lock --* SmoothProgressBar : __lock


Objects:

Theme()
Console()
@Property Console.size()
Console.addmsg()
Console.emptyline()
Console.addtab()
Console.goback()
Console.newline()
Console.print()
ConsolePrgBr()
ConsolePrgBr.update()
ConsolePrgBr.get()
ConsoleProgress()
ConsoleProgress.update()
ConsoleString()
@Property ConsoleString.enable()
@Property ConsoleString.max_size()
ConsoleString.max_size()
@Property ConsoleString.tag_size()
@Property ConsoleString.max_text_size()
@Property ConsoleString.current_text_size()
ConsoleString.align_left()
ConsoleString.align_right()
ConsoleString.update()
ElapseTime()
ElapseTime.start()
MultiThread()
@Property MultiThread.func()
MultiThread.run()
MultiThread.stop()
Percent()
@Property Percent.whole()
@Property Percent.part()
Percent.part()
@Property Percent.value()
SmoothProgressBar()
@Property SmoothProgressBar.msg()
SmoothProgressBar.msg()
SmoothProgressBar.start()
SmoothProgressBar.stop()
SmoothProgressBar.update()

Theme()

class Theme(Enum):
Define constants.

Console()

class Console():
This Class provides a simple way to manage the screen.

Use:
    >>> c = Console()
    >>> c.addmsg("lorem ipsum dolor").print()
    lorem ipsum dolor
    >>> c.addmsg("lorem ipsum dolor").newline().addmsg("LOREM").print()
    lorem ipsum dolor
    LOREM

@Property Console.size()

@property
def Console.size(self) -> int:
Get screen size.

Console.addmsg()

def Console.addmsg(self, msg: str) -> Console:
Store a message.

Console.emptyline()

def Console.emptyline(self) -> Console:
Add an empty line.

Console.addtab()

def Console.addtab(self) -> Console:
Add tab.

Console.goback()

def Console.goback(self) -> Console:
Go back.

Console.newline()

def Console.newline(self) -> Console:
Add a new line.

Console.print()

def Console.print(self) -> None:
Print the buffer.

ConsolePrgBr()

class ConsolePrgBr():
This class print all components according to parameters.

Use:
>>> from smoothprogressbar.percent import Percent
>>> from smoothprogressbar.elapse import ElapseTime
>>> size = 40
>>> percent = Percent(10)
>>> percent.part = 2
>>> msg = "lorem ipsum dolor sit amet consectetur adipiscing elit"
>>> elapse = ElapseTime()
>>> elapse.start()
>>> prgbr = ConsolePrgBr(debug=True)
>>> prgbr.update(size, percent, msg, str(elapse)).get()
'Processing: [ 20.0%] [...] 0:00:00 lorem'
>>> size = 70
>>> prgbr = ConsolePrgBr(debug=True)
>>> prgbr.update(size, percent, msg, str(elapse)).get()
'Processing: [ 20.0%] [###...............] 0:00:00 lorem ipsum dolor si'
>>> prgbr = ConsolePrgBr(enable_elapse=False, enable_msg=False, debug=True)
>>> prgbr.update(size, percent, msg, str(elapse)).get()
'Processing: [ 20.0%] [#########......................................]'
>>> prgbr = ConsolePrgBr(enable_elapse=True, enable_msg=False, debug=True)
>>> prgbr.update(size, percent, msg, str(elapse)).get()
'Processing: [ 20.0%] [#######................................] 0:00:00'
>>> prgbr = ConsolePrgBr(enable_elapse=False, enable_msg=True, debug=True)
>>> prgbr.update(size, percent, msg, str(elapse)).get()
'Processing: [ 20.0%] [####..................] lorem ipsum dolor sit am'

ConsolePrgBr.update()

def ConsolePrgBr.update(self, size: int, percent: Percent, msg: str = "", elapse: str = "") -> ConsolePrgBr:
Update the progress bar.

ConsolePrgBr.get()

def ConsolePrgBr.get(self) -> str:
Get the string.

ConsoleProgress()

class ConsoleProgress(ConsoleString):
Define ConsoleProgress.

Use:
    >>> c = ConsoleProgress()
    >>> str(c.update(12, 0.1))
    '[#.........]'
    >>> str(c.update(12, 0.4))
    '[####......]'
    >>> str(c.update(12, 1))
    '[##########]'
    >>> len(c.update(12, 1))
    12

ConsoleProgress.update()

def ConsoleProgress.update(self, size: int, ratio: float) -> ConsoleProgress:
Update.

ConsoleString()

class ConsoleString():
Print messages.

Console string is a string to print (stdout) with
fixed size.

'[XXXXXXXXX ]                  '
 -          -                    : tag size
  ----------                     : text size
|------------------------------| : max size

Why:
    It's usefull to manage the screen size.

Use:
    >>> c = ConsoleString("lorem", max_size=3)
    >>> c
    lor
    >>> c = ConsoleString("lorem")
    >>> # tag
    >>> c.tag_beg = "["
    >>> c.tag_end="]"
    >>> for i in range(9): c.max_size = i ; str(c)
    ''
    '['
    '[]'
    '[l]'
    '[lo]'
    '[lor]'
    '[lore]'
    '[lorem]'
    '[lorem] '
    >>> len(c)
    8
    >>> c.text
    'lorem'
    >>> c = ConsoleString("lorem")
    >>> for i in range(9): c.max_size = i ; str(c.align_left())
    ''
    'l'
    'lo'
    'lor'
    'lore'
    'lorem'
    'lorem '
    'lorem  '
    'lorem   '
    >>> c = ConsoleString("lorem")
    >>> for i in range(9): c.max_size = i ; str(c.align_right())
    ''
    'l'
    'lo'
    'lor'
    'lore'
    'lorem'
    ' lorem'
    '  lorem'
    '   lorem'
    >>> txt = "lorem ipsum dolor sit amet consectetur adipiscing elit"
    >>> str(c.update(text=txt, max_size=15, tag_beg="*** "))
    '*** lorem ipsum'

@Property ConsoleString.enable()

@property
def ConsoleString.enable(self) -> bool:
Get enable.

@Property ConsoleString.max_size()

@property
def ConsoleString.max_size(self) -> int:
Get max size.

ConsoleString.max_size()

@max_size.setter
def ConsoleString.max_size(self, value: int) -> None:
Set max size.

@Property ConsoleString.tag_size()

@property
def ConsoleString.tag_size(self) -> int:
Get tag_size.

@Property ConsoleString.max_text_size()

@property
def ConsoleString.max_text_size(self) -> int:
Get max_text_size.

@Property ConsoleString.current_text_size()

@property
def ConsoleString.current_text_size(self) -> int:
Get current_text_size.

ConsoleString.align_left()

def ConsoleString.align_left(self) -> ConsoleString:
Apply 'align-left' to the string.

ConsoleString.align_right()

def ConsoleString.align_right(self) -> ConsoleString:
Apply 'align-right' to the string.

ConsoleString.update()

def ConsoleString.update(self, text: Optional[str] = None, max_size: Optional[int] = None, tag_beg: Optional[str] = None, tag_end: Optional[str] = None) -> ConsoleString:
Update the string.

ElapseTime()

class ElapseTime():
Calculate elapse time.

Use:
    >>> import time
    >>> t = ElapseTime()
    >>> #oups...
    >>> t
    Traceback (most recent call last):
    ...
    RuntimeError: start before...
    >>> t.start()
    >>> time.sleep(1)
    >>> t
    0:00:01
    >>> time.sleep(1)
    >>> t
    0:00:02
    >>> str(t)
    '0:00:02'

ElapseTime.start()

def ElapseTime.start(self) -> None:
Store the current timestamp in self.__start_time.

Returns:
    None

MultiThread()

class MultiThread(Thread):
A class that represents a thread of control.

This is used to refresh the progressbar regurarly. (self.__refresh())
This class subclassed Thread class :
    class Thread(builtins.object)

We specify the activity by passing a callable object to the constructor.

Use:
    >>> import time
    >>> def mytask(): print("lorem ipsum dolor sit amet consectetur")
    >>> mthr = MultiThread(mytask, 0.1)
    >>> mthr.start() ; print("other task");time.sleep(0.3) ; mthr.stop()
    lorem ipsum dolor sit amet consectetur
    other task
    lorem ipsum dolor sit amet consectetur
    lorem ipsum dolor sit amet consectetur

@Property MultiThread.func()

@property
def MultiThread.func(self) -> Callable[[], None]:
Get func.

Returns the callable object defined by Thread constructor.

Returns:
    Callable[[], None]: callable object

MultiThread.run()

def MultiThread.run(self) -> None:
Do tasks.

Method (override) representing the thread's activity.
This method will raise a RuntimeError if called more than once on the
same thread object.

Returns:
    None.

MultiThread.stop()

def MultiThread.stop(self) -> None:
Stop multithreading.

Wait until the thread terminates.
This blocks the calling thread until the thread whose join() method is
called terminates -- either normally or through an unhandled exception.

Returns:
    None.

Percent()

class Percent(float):
Calc percent.

Use:
    >>> p = Percent(10)
    >>> p.part = 2
    >>> p.part
    2
    >>> p
     20.0%
    >>> str(p)
    ' 20.0%'
    >>> p.value
    0.2
    >>> p = Percent(8)
    >>> for i in range(9): p.part = i ; print("{}-{}".format(p, p.value))
      0.0%-0.0
     12.5%-0.125
     25.0%-0.25
     37.5%-0.375
     50.0%-0.5
     62.5%-0.625
     75.0%-0.75
     87.5%-0.875
    100.0%-1.0

@Property Percent.whole()

@property
def Percent.whole(self) -> float:
Get whole.

Returns:
    float: X% = 100 * (part / whole)

@Property Percent.part()

@property
def Percent.part(self) -> int:
Get part.

Returns:
    int: X% = 100 * (part / whole)

Percent.part()

@part.setter
def Percent.part(self, value: int) -> None:
Set part.

@Property Percent.value()

@property
def Percent.value(self) -> float:
Get Value.

Returns:
    float: value = X%/100 = part / whole

SmoothProgressBar()

class SmoothProgressBar():
This class use all others component to manage the progressbar.

@Property SmoothProgressBar.msg()

@property
def SmoothProgressBar.msg(self) -> str:
Get message.

SmoothProgressBar.msg()

@msg.setter
def SmoothProgressBar.msg(self, msg: str) -> None:
Set message.

SmoothProgressBar.start()

def SmoothProgressBar.start(self, max_value: int) -> None:
Start the progress bar.

init percent(), screen size, elapse & multithreading

SmoothProgressBar.stop()

def SmoothProgressBar.stop(self) -> None:
Stop the progress bar.

SmoothProgressBar.update()

def SmoothProgressBar.update(self, value: int, msg: str = "") -> None:
Update the progressbar.