From 80c17114eb2acaca5f79424ab24cf6328308d106 Mon Sep 17 00:00:00 2001 From: "Vincent (Leirof)" Date: Sat, 22 Oct 2022 09:48:40 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9E=95=20Added=20average=20ETA=20(progress)?= =?UTF-8?q?=20+=20several=20tweaks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LRFutils.egg-info/PKG-INFO | 13 ++ LRFutils.egg-info/SOURCES.txt | 14 +++ LRFutils.egg-info/dependency_links.txt | 1 + LRFutils.egg-info/requires.txt | 2 + LRFutils.egg-info/top_level.txt | 1 + LRFutils/__init__.py | 2 +- LRFutils/color.py | 103 ++++++++-------- LRFutils/{log.py => logs.py} | 22 ++-- LRFutils/progress.py | 107 ++++++++++++----- Leirof.egg-info/PKG-INFO | 15 +++ Leirof.egg-info/SOURCES.txt | 0 Leirof.egg-info/dependency_links.txt | 1 + Leirof.egg-info/requires.txt | 2 + Leirof.egg-info/top_level.txt | 1 + build/lib/LRFutils/__init__.py | 5 + build/lib/LRFutils/archive.py | 47 ++++++++ build/lib/LRFutils/color.py | 53 ++++++++ build/lib/LRFutils/logs.py | 74 ++++++++++++ build/lib/LRFutils/progress.py | 119 ++++++++++++++++++ build/lib/LRFutils/term.py | 9 ++ changelog.md | 22 ++++ dist/LRFutils-0.0.11.tar.gz | Bin 0 -> 5634 bytes docs/conf.py | 3 +- docs/getting_started.md | 2 +- docs/index.rst | 1 + docs/logs.ipynb | 80 +++++++++++++ docs/progress.ipynb | 160 +++++++++++++++++++++++++ docs/progress.md | 95 --------------- docs/requirements.txt | 3 +- examples.ipynb | 63 ++++++---- setup.py | 4 +- test.py | 2 - upload_on_pip.py | 5 + 33 files changed, 810 insertions(+), 221 deletions(-) create mode 100644 LRFutils.egg-info/PKG-INFO create mode 100644 LRFutils.egg-info/SOURCES.txt create mode 100644 LRFutils.egg-info/dependency_links.txt create mode 100644 LRFutils.egg-info/requires.txt create mode 100644 LRFutils.egg-info/top_level.txt rename LRFutils/{log.py => logs.py} (71%) create mode 100644 Leirof.egg-info/PKG-INFO create mode 100644 Leirof.egg-info/SOURCES.txt create mode 100644 Leirof.egg-info/dependency_links.txt create mode 100644 Leirof.egg-info/requires.txt create mode 100644 Leirof.egg-info/top_level.txt create mode 100644 build/lib/LRFutils/__init__.py create mode 100644 build/lib/LRFutils/archive.py create mode 100644 build/lib/LRFutils/color.py create mode 100644 build/lib/LRFutils/logs.py create mode 100644 build/lib/LRFutils/progress.py create mode 100644 build/lib/LRFutils/term.py create mode 100644 changelog.md create mode 100644 dist/LRFutils-0.0.11.tar.gz create mode 100644 docs/logs.ipynb create mode 100644 docs/progress.ipynb delete mode 100644 docs/progress.md delete mode 100644 test.py create mode 100644 upload_on_pip.py diff --git a/LRFutils.egg-info/PKG-INFO b/LRFutils.egg-info/PKG-INFO new file mode 100644 index 0000000..e5ef366 --- /dev/null +++ b/LRFutils.egg-info/PKG-INFO @@ -0,0 +1,13 @@ +Metadata-Version: 2.1 +Name: LRFutils +Version: 0.0.11 +Summary: Just a custom library to share with some colleagues. Use it at your own risks. +Home-page: https://github.com/LeiRoF/Utils +Author: Leirof +Author-email: vince.lrf@gmail.com +Classifier: Programming Language :: Python :: 3 +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Intended Audience :: Developers +Requires-Python: >=3.10.0 +License-File: LICENSE diff --git a/LRFutils.egg-info/SOURCES.txt b/LRFutils.egg-info/SOURCES.txt new file mode 100644 index 0000000..541d27f --- /dev/null +++ b/LRFutils.egg-info/SOURCES.txt @@ -0,0 +1,14 @@ +LICENSE +README.md +setup.py +LRFutils/__init__.py +LRFutils/archive.py +LRFutils/color.py +LRFutils/logs.py +LRFutils/progress.py +LRFutils/term.py +LRFutils.egg-info/PKG-INFO +LRFutils.egg-info/SOURCES.txt +LRFutils.egg-info/dependency_links.txt +LRFutils.egg-info/requires.txt +LRFutils.egg-info/top_level.txt \ No newline at end of file diff --git a/LRFutils.egg-info/dependency_links.txt b/LRFutils.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/LRFutils.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/LRFutils.egg-info/requires.txt b/LRFutils.egg-info/requires.txt new file mode 100644 index 0000000..b735103 --- /dev/null +++ b/LRFutils.egg-info/requires.txt @@ -0,0 +1,2 @@ +gitpython +regex diff --git a/LRFutils.egg-info/top_level.txt b/LRFutils.egg-info/top_level.txt new file mode 100644 index 0000000..3e8a11a --- /dev/null +++ b/LRFutils.egg-info/top_level.txt @@ -0,0 +1 @@ +LRFutils diff --git a/LRFutils/__init__.py b/LRFutils/__init__.py index e12a987..b7cd16b 100644 --- a/LRFutils/__init__.py +++ b/LRFutils/__init__.py @@ -2,4 +2,4 @@ from .color import * from .term import * from .progress import * -from .log import * \ No newline at end of file +from .logs import * \ No newline at end of file diff --git a/LRFutils/color.py b/LRFutils/color.py index b7ca644..daf7ce8 100644 --- a/LRFutils/color.py +++ b/LRFutils/color.py @@ -1,54 +1,53 @@ import re -class Color: - NC = '\033[0m' # No Color, reset all - - Bold = '\033[1m' - Underlined = '\033[4m' - Blink = '\033[5m' - Inverted = '\033[7m' - Hidden = '\033[8m' - - Black = '\033[30m' - Red = '\033[31m' - Green = '\033[32m' - Yellow = '\033[33m' - Blue = '\033[34m' - Purple = '\033[35m' - Cyan = '\033[36m' - LightGray = '\033[37m' - - Gray = "\u001b[30;1m" - LightRed = "\u001b[31;1m" - LightGreen = "\u001b[32;1m" - LightYellow = "\u001b[33;1m" - LightBlue = "\u001b[34;1m" - LightMagenta = "\u001b[35;1m" - LightCyan = "\u001b[36;1m" - White = "\u001b[37;1m" - - - on_Black = "\u001b[40m" - on_Red = "\u001b[41m" - on_Green = "\u001b[42m" - on_Yellow = "\u001b[43m" - on_Blue = "\u001b[44m" - on_Magenta = "\u001b[45m" - on_Cyan = "\u001b[46m" - on_LightGray = "\u001b[47m" - - - on_Gray = "\u001b[40;1m" - on_LightRed = "\u001b[41;1m" - on_LightGreen = "\u001b[42;1m" - on_LightYellow = "\u001b[43;1m" - on_LightBlue = "\u001b[44;1m" - on_LightMagenta = "\u001b[45;1m" - on_LightCyan = "\u001b[46;1m" - on_White = "\u001b[47;1m" - - def clear(txt): - txt = re.sub("\033\[[0-9][0-9]?m", "", txt) - txt = re.sub("\\u001b\[[0-9][0-9]?m", "", txt) - txt = re.sub("\\u001b\[[0-9][0-9]?;1m", "", txt) - return txt \ No newline at end of file +NC = '\033[0m' # No Color, reset all + +Bold = '\033[1m' +Underlined = '\033[4m' +Blink = '\033[5m' +Inverted = '\033[7m' +Hidden = '\033[8m' + +Black = '\033[30m' +Red = '\033[31m' +Green = '\033[32m' +Yellow = '\033[33m' +Blue = '\033[34m' +Purple = '\033[35m' +Cyan = '\033[36m' +LightGray = '\033[37m' + +Gray = "\u001b[30;1m" +LightRed = "\u001b[31;1m" +LightGreen = "\u001b[32;1m" +LightYellow = "\u001b[33;1m" +LightBlue = "\u001b[34;1m" +LightMagenta = "\u001b[35;1m" +LightCyan = "\u001b[36;1m" +White = "\u001b[37;1m" + + +on_Black = "\u001b[40m" +on_Red = "\u001b[41m" +on_Green = "\u001b[42m" +on_Yellow = "\u001b[43m" +on_Blue = "\u001b[44m" +on_Magenta = "\u001b[45m" +on_Cyan = "\u001b[46m" +on_LightGray = "\u001b[47m" + + +on_Gray = "\u001b[40;1m" +on_LightRed = "\u001b[41;1m" +on_LightGreen = "\u001b[42;1m" +on_LightYellow = "\u001b[43;1m" +on_LightBlue = "\u001b[44;1m" +on_LightMagenta = "\u001b[45;1m" +on_LightCyan = "\u001b[46;1m" +on_White = "\u001b[47;1m" + +def clear(txt): + txt = re.sub("\033\[[0-9][0-9]?m", "", txt) + txt = re.sub("\\u001b\[[0-9][0-9]?m", "", txt) + txt = re.sub("\\u001b\[[0-9][0-9]?;1m", "", txt) + return txt \ No newline at end of file diff --git a/LRFutils/log.py b/LRFutils/logs.py similarity index 71% rename from LRFutils/log.py rename to LRFutils/logs.py index 6a2ffc8..a0a4ca2 100644 --- a/LRFutils/log.py +++ b/LRFutils/logs.py @@ -4,7 +4,7 @@ from datetime import datetime import os import platform -from LRFutils.color import Color +from LRFutils import color as C import sys import traceback @@ -15,25 +15,25 @@ def now(human=False, color=False): time = str(datetime.now()) if human: if color: - return f"{Color.Blue}{time[8:10]}/{time[5:7]}/{time[0:4]}{Color.NC} at {Color.Purple}{time[11:13]}:{time[14:16]}:{time[17:19]}{Color.NC}" + return f"{C.Blue}{time[8:10]}/{time[5:7]}/{time[0:4]}{C.NC} at {C.Purple}{time[11:13]}:{time[14:16]}:{time[17:19]}{C.NC}" else: return f"{time[8:10]}/{time[5:7]}/{time[0:4]} at {time[11:13]}:{time[14:16]}:{time[17:19]}" else: return time.replace(" ", "_").replace(":", ".") startTime = now() -filename = f"logs/{startTime}.log" +filename = f"logs/{startTime}.logs" if not os.path.isdir("logs"): os.makedirs(f"logs/") # Getting the current environment -with open(filename, "a") as logFile: - logFile.write(f"ENVIRONMENT: {platform.uname()}\n\n") +with open(filename, "a") as logsFile: + logsFile.write(f"ENVIRONMENT: {platform.uname()}\n\n") # Print message in log file def logSave(message): currentTime = now(human = True, color=False) - with open(filename, "a", encoding="utf-8") as logFile: - logFile.write(f"{currentTime} | {message}\n") + with open(filename, "a", encoding="utf-8") as logsFile: + logsFile.write(f"{currentTime} | {message}\n") # Print message in terminal def logPrint(message): @@ -43,27 +43,27 @@ def logPrint(message): # Info-styled messages def info(message): logSave(f"[INFO] {message}") - message = Color.Green + "[INFO] " + Color.NC + message + message = C.Green + "[INFO] " + C.NC + message logPrint(message) # Warning-styled messages def warn(message): message = f"[WARNING] {message}" logSave(message) - message = Color.Yellow + message + Color.NC + message = C.Yellow + message + C.NC logPrint(message) # Error-styled messages def error(message, etype = None, value = None, tb=None): message = f"[ERROR] {message}" logSave(message) - message = Color.on_Red + message + Color.NC + message = C.on_Red + message + C.NC if etype is None or value is None or tb is None: tb = traceback.format_exc() else: tb = ''.join(traceback.format_exception(etype, value, tb)) logSave(f"Full traceback below.\n\n{tb}") - logPrint(message + f"\n -> Look at {Color.Green}{filename}{Color.NC} for more information.\n") + logPrint(message + f"\n -> Look at {C.Green}{filename}{C.NC} for more information.\n") # Catch unexpected crashes def myexcepthook(etype, value, tb): diff --git a/LRFutils/progress.py b/LRFutils/progress.py index 136f210..2915620 100644 --- a/LRFutils/progress.py +++ b/LRFutils/progress.py @@ -1,74 +1,119 @@ -from .color import Color +from . import color from time import time import datetime class Bar(): - def __init__(self, max = 1, width = 80, prefix = "", eta = True, decimals = 0, duration = True): + + + + # ________________________________________________________________________________ + # Create a progress bar + + def __init__(self, max:float|int = 1, width:int = 80, prefix:str = "", eta:bool = True, decimals:int = 0, show_duration:bool = True, average_ETA:int = 10): self.max = max - self.width = width if type(width) == int else 80 + self.width = width if isinstance(width,int) else 80 self.prefix = prefix self.eta = eta self.decimals = decimals - self.lastProgress = 0 - self.lastUpdate = None + self.previous_progress = [0] + self.previous_update = [] self.lastETA = "-" self.start_at = time() - self.duration = duration + self.duration = show_duration + self.average_ETA = average_ETA + + + # ________________________________________________________________________________ + # Compute the ETA def update_eta(self, progress): - if self.lastUpdate is not None and time()-self.lastUpdate < 1: return self.lastETA - progression = progress - self.lastProgress - left = (self.max-progress) + # Get index of the i-th revious update to average the ETA on i updates + if len(self.previous_progress) <= self.average_ETA: + i = 0 + else: + i = -self.average_ETA + + # Compute progression since the i-th previous update + progression = progress - self.previous_progress[i] + todo = self.max - progress - if progression == 0 or self.lastUpdate is None: - self.lastUpdate = time() - self.lastProgress = progress + # If there is no progression or the bar was just created, it update the data but return the same ETA + if progression == 0 or self.previous_update == []: + self.previous_update.append(time()) + self.previous_progress.append(progress) self.lastETA = "-" return self.lastETA - seconds = left/progression * (time() - self.lastUpdate) - self.lastUpdate = time() - self.lastProgress = progress - if seconds < 0: self.lastETA = "-" - else: self.lastETA = str(datetime.timedelta(seconds=seconds)).split(".")[0] + # If the bar was updated less than one second before, + # we don't update it again to not slow the program + if time()-self.previous_update[-1] < 1: + return self.lastETA + + # Compute the ETA in seconds + try: + seconds = todo / progression * (time() - self.previous_update[i]) + except: + print(len(self.previous_update), i) + + # Update bar data + self.previous_update.append(time()) + self.previous_progress.append(progress) + + # If the ETA is negative, then we show an undefined ETA + if seconds < 0: + self.lastETA = "-" + # Else we return the number of seconds + else: + self.lastETA = str(datetime.timedelta(seconds=seconds)).split(".")[0] + return self.lastETA + + + # ________________________________________________________________________________ + # Update the progress bar + def __call__(self, progress: float, prefix=None, stop=False): if prefix is None: prefix = self.prefix else: prefix = str(prefix) progress_normed = progress / self.max if progress == self.max : stop = True - color = Color.Yellow if stop and progress_normed != 1 else Color.LightGreen + color_bar = color.Yellow if stop and progress_normed != 1 else color.LightGreen if stop: end = "\n" else: end = "\r" if type(progress) == float: progress = round(progress, self.decimals) - percent = f" {color}{round(progress_normed*100,self.decimals) if self.decimals > 0 else int(progress_normed*100)}%" - frac = f" {Color.LightRed}{progress}/{self.max}" if self.max is not None else '' - eta = f" {Color.NC}eta {Color.Blue}{self.update_eta(progress)}" if not stop else '' - duration = f" {Color.Purple}{str(datetime.timedelta(seconds=time() - self.start_at)).split('.')[0]}" if self.duration else '' + percent = f" {color_bar}{round(progress_normed*100,self.decimals) if self.decimals > 0 else int(progress_normed*100)}%" + frac = f" {color.LightRed}{progress}/{self.max}" if self.max is not None else '' + eta = f" {color.NC}eta {color.Blue}{self.update_eta(progress)}" if not stop else '' + duration = f" {color.Purple}{str(datetime.timedelta(seconds=time() - self.start_at)).split('.')[0]}" if self.duration else '' - prefix = '' if prefix == '' else Color.NC + prefix + ' ' + prefix = '' if prefix == '' else color.NC + prefix + ' ' suffix = f"{percent}{frac}{duration}{eta}" - barwidth = self.width - len(Color.clear(suffix)) - len(Color.clear(prefix)) + barwidth = self.width - len(color.clear(suffix)) - len(color.clear(prefix)) barwidth = max(barwidth,10) currentBar = int(round(min(progress_normed*barwidth,barwidth))) minBar = int(min(progress_normed*barwidth,barwidth)) - if progress_normed == 0: bar = Color.White + '━' * barwidth - elif progress_normed == 1: bar = Color.LightGreen + '━' * barwidth - elif currentBar == minBar: bar = color + '━' * currentBar + Color.White + '╺' + Color.White + '━' * (barwidth - currentBar - 1) - else: bar = color + '━' * (currentBar - 1) + color + '╸' + Color.White + '━' * (barwidth - currentBar) + if progress_normed == 0: bar = color.White + '━' * barwidth + elif progress_normed == 1: bar = color.LightGreen + '━' * barwidth + elif currentBar == minBar: bar = color_bar + '━' * currentBar + color.White + '╺' + color.White + '━' * (barwidth - currentBar - 1) + else: bar = color_bar + '━' * (currentBar - 1) + color_bar + '╸' + color.White + '━' * (barwidth - currentBar) - msg = f"{prefix}{bar}{suffix}{Color.NC}" + msg = f"{prefix}{bar}{suffix}{color.NC}" print(msg, end=end) + + + # ________________________________________________________________________________ + # Stop the progress bar + def stop(self): - self(self.lastProgress, stop=True) - self.lastProgress = 0 + self(self.previous_progress[-1], stop=True) + self.previous_progress = [0] self.lastUpdate = None \ No newline at end of file diff --git a/Leirof.egg-info/PKG-INFO b/Leirof.egg-info/PKG-INFO new file mode 100644 index 0000000..381a692 --- /dev/null +++ b/Leirof.egg-info/PKG-INFO @@ -0,0 +1,15 @@ +Metadata-Version: 2.1 +Name: Leirof +Version: 0.0.11 +Summary: Just a custom library to share with some colleagues. Use it at your own risks. +Home-page: https://github.com/LeiRoF/LRFutils +License: MIT +Project-URL: Bug Tracker, https://github.com/LeiRoF/LRFutils/issues +Classifier: [ +Classifier: "Programming Language :: Python :: 3", +Classifier: "License :: OSI Approved :: MIT License", +Classifier: "Operating System :: OS Independent", +Classifier: 'Intended Audience :: Developers' +Classifier: ] +Requires-Python: >=3.10 +License-File: LICENSE diff --git a/Leirof.egg-info/SOURCES.txt b/Leirof.egg-info/SOURCES.txt new file mode 100644 index 0000000..e69de29 diff --git a/Leirof.egg-info/dependency_links.txt b/Leirof.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Leirof.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/Leirof.egg-info/requires.txt b/Leirof.egg-info/requires.txt new file mode 100644 index 0000000..b735103 --- /dev/null +++ b/Leirof.egg-info/requires.txt @@ -0,0 +1,2 @@ +gitpython +regex diff --git a/Leirof.egg-info/top_level.txt b/Leirof.egg-info/top_level.txt new file mode 100644 index 0000000..3e8a11a --- /dev/null +++ b/Leirof.egg-info/top_level.txt @@ -0,0 +1 @@ +LRFutils diff --git a/build/lib/LRFutils/__init__.py b/build/lib/LRFutils/__init__.py new file mode 100644 index 0000000..b7cd16b --- /dev/null +++ b/build/lib/LRFutils/__init__.py @@ -0,0 +1,5 @@ +from .archive import * +from .color import * +from .term import * +from .progress import * +from .logs import * \ No newline at end of file diff --git a/build/lib/LRFutils/archive.py b/build/lib/LRFutils/archive.py new file mode 100644 index 0000000..e9a15c9 --- /dev/null +++ b/build/lib/LRFutils/archive.py @@ -0,0 +1,47 @@ +import datetime +import os +import git + +number = None + +def next_number(path): + global number + max_num = 0 + for file in os.listdir(path): + if "_" in file: file = file.split("_")[0] + try: + if int(file) > max_num: max_num = int(file) + except: pass + number = max_num + 1 + return number + +def new(name = None): + global number + + timestamp = str(datetime.datetime.now()).split(" ") + + try: + repo = git.Repo(search_parent_directories=True) + sha = "_" + repo.head.object.hexsha[:7] + except: sha = "" + + path = "./archives/" + timestamp[0] + sha + + if not os.path.isdir(path): os.makedirs(path) + + if path is not None: next_number(path) + else: number = 1 + + if name is not None: name = "_" + name + + if not os.path.isdir(f"{path}/{number}{name}"): os.makedirs(f"{path}/{number}{name}") + + + return f"{path}/{number}{name}" + +def description(**kwargs): + desc = "" + for key,value in kwargs.items(): + if type(value) in [int, str, float, bool] : desc += f",{key}={value}" + else: print(f"⚠️ Your archive description contain a non-supported type: {type(value)}") + return desc[1:] diff --git a/build/lib/LRFutils/color.py b/build/lib/LRFutils/color.py new file mode 100644 index 0000000..daf7ce8 --- /dev/null +++ b/build/lib/LRFutils/color.py @@ -0,0 +1,53 @@ +import re + +NC = '\033[0m' # No Color, reset all + +Bold = '\033[1m' +Underlined = '\033[4m' +Blink = '\033[5m' +Inverted = '\033[7m' +Hidden = '\033[8m' + +Black = '\033[30m' +Red = '\033[31m' +Green = '\033[32m' +Yellow = '\033[33m' +Blue = '\033[34m' +Purple = '\033[35m' +Cyan = '\033[36m' +LightGray = '\033[37m' + +Gray = "\u001b[30;1m" +LightRed = "\u001b[31;1m" +LightGreen = "\u001b[32;1m" +LightYellow = "\u001b[33;1m" +LightBlue = "\u001b[34;1m" +LightMagenta = "\u001b[35;1m" +LightCyan = "\u001b[36;1m" +White = "\u001b[37;1m" + + +on_Black = "\u001b[40m" +on_Red = "\u001b[41m" +on_Green = "\u001b[42m" +on_Yellow = "\u001b[43m" +on_Blue = "\u001b[44m" +on_Magenta = "\u001b[45m" +on_Cyan = "\u001b[46m" +on_LightGray = "\u001b[47m" + + +on_Gray = "\u001b[40;1m" +on_LightRed = "\u001b[41;1m" +on_LightGreen = "\u001b[42;1m" +on_LightYellow = "\u001b[43;1m" +on_LightBlue = "\u001b[44;1m" +on_LightMagenta = "\u001b[45;1m" +on_LightCyan = "\u001b[46;1m" +on_White = "\u001b[47;1m" + +def clear(txt): + txt = re.sub("\033\[[0-9][0-9]?m", "", txt) + txt = re.sub("\\u001b\[[0-9][0-9]?m", "", txt) + txt = re.sub("\\u001b\[[0-9][0-9]?;1m", "", txt) + return txt \ No newline at end of file diff --git a/build/lib/LRFutils/logs.py b/build/lib/LRFutils/logs.py new file mode 100644 index 0000000..a0a4ca2 --- /dev/null +++ b/build/lib/LRFutils/logs.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# coding=utf-8 + +from datetime import datetime +import os +import platform +from LRFutils import color as C +import sys +import traceback + +hide_traceback = False + +# Get current time as string +def now(human=False, color=False): + time = str(datetime.now()) + if human: + if color: + return f"{C.Blue}{time[8:10]}/{time[5:7]}/{time[0:4]}{C.NC} at {C.Purple}{time[11:13]}:{time[14:16]}:{time[17:19]}{C.NC}" + else: + return f"{time[8:10]}/{time[5:7]}/{time[0:4]} at {time[11:13]}:{time[14:16]}:{time[17:19]}" + else: + return time.replace(" ", "_").replace(":", ".") + +startTime = now() +filename = f"logs/{startTime}.logs" +if not os.path.isdir("logs"): os.makedirs(f"logs/") + +# Getting the current environment +with open(filename, "a") as logsFile: + logsFile.write(f"ENVIRONMENT: {platform.uname()}\n\n") + +# Print message in log file +def logSave(message): + currentTime = now(human = True, color=False) + with open(filename, "a", encoding="utf-8") as logsFile: + logsFile.write(f"{currentTime} | {message}\n") + +# Print message in terminal +def logPrint(message): + currentTime = now(human = True, color=True) + print(f'{currentTime} | {message}') + +# Info-styled messages +def info(message): + logSave(f"[INFO] {message}") + message = C.Green + "[INFO] " + C.NC + message + logPrint(message) + +# Warning-styled messages +def warn(message): + message = f"[WARNING] {message}" + logSave(message) + message = C.Yellow + message + C.NC + logPrint(message) + +# Error-styled messages +def error(message, etype = None, value = None, tb=None): + message = f"[ERROR] {message}" + logSave(message) + message = C.on_Red + message + C.NC + + if etype is None or value is None or tb is None: tb = traceback.format_exc() + else: tb = ''.join(traceback.format_exception(etype, value, tb)) + logSave(f"Full traceback below.\n\n{tb}") + + logPrint(message + f"\n -> Look at {C.Green}{filename}{C.NC} for more information.\n") + +# Catch unexpected crashes +def myexcepthook(etype, value, tb): + global hide_traceback + error(f"🤕 Uh, there is an unexpected error somewhere: {value} ({type})", etype=etype, value=value, tb=tb) + if not hide_traceback: sys.__excepthook__(etype, value, tb) + +sys.excepthook = myexcepthook \ No newline at end of file diff --git a/build/lib/LRFutils/progress.py b/build/lib/LRFutils/progress.py new file mode 100644 index 0000000..2915620 --- /dev/null +++ b/build/lib/LRFutils/progress.py @@ -0,0 +1,119 @@ +from . import color +from time import time +import datetime + +class Bar(): + + + + # ________________________________________________________________________________ + # Create a progress bar + + def __init__(self, max:float|int = 1, width:int = 80, prefix:str = "", eta:bool = True, decimals:int = 0, show_duration:bool = True, average_ETA:int = 10): + self.max = max + self.width = width if isinstance(width,int) else 80 + self.prefix = prefix + self.eta = eta + self.decimals = decimals + self.previous_progress = [0] + self.previous_update = [] + self.lastETA = "-" + self.start_at = time() + self.duration = show_duration + self.average_ETA = average_ETA + + + # ________________________________________________________________________________ + # Compute the ETA + + def update_eta(self, progress): + + # Get index of the i-th revious update to average the ETA on i updates + if len(self.previous_progress) <= self.average_ETA: + i = 0 + else: + i = -self.average_ETA + + # Compute progression since the i-th previous update + progression = progress - self.previous_progress[i] + todo = self.max - progress + + # If there is no progression or the bar was just created, it update the data but return the same ETA + if progression == 0 or self.previous_update == []: + self.previous_update.append(time()) + self.previous_progress.append(progress) + self.lastETA = "-" + return self.lastETA + + # If the bar was updated less than one second before, + # we don't update it again to not slow the program + if time()-self.previous_update[-1] < 1: + return self.lastETA + + # Compute the ETA in seconds + try: + seconds = todo / progression * (time() - self.previous_update[i]) + except: + print(len(self.previous_update), i) + + # Update bar data + self.previous_update.append(time()) + self.previous_progress.append(progress) + + # If the ETA is negative, then we show an undefined ETA + if seconds < 0: + self.lastETA = "-" + # Else we return the number of seconds + else: + self.lastETA = str(datetime.timedelta(seconds=seconds)).split(".")[0] + + return self.lastETA + + + + # ________________________________________________________________________________ + # Update the progress bar + + def __call__(self, progress: float, prefix=None, stop=False): + if prefix is None: prefix = self.prefix + else: prefix = str(prefix) + + progress_normed = progress / self.max + if progress == self.max : stop = True + color_bar = color.Yellow if stop and progress_normed != 1 else color.LightGreen + + if stop: end = "\n" + else: end = "\r" + + if type(progress) == float: progress = round(progress, self.decimals) + percent = f" {color_bar}{round(progress_normed*100,self.decimals) if self.decimals > 0 else int(progress_normed*100)}%" + frac = f" {color.LightRed}{progress}/{self.max}" if self.max is not None else '' + eta = f" {color.NC}eta {color.Blue}{self.update_eta(progress)}" if not stop else '' + duration = f" {color.Purple}{str(datetime.timedelta(seconds=time() - self.start_at)).split('.')[0]}" if self.duration else '' + + prefix = '' if prefix == '' else color.NC + prefix + ' ' + suffix = f"{percent}{frac}{duration}{eta}" + + barwidth = self.width - len(color.clear(suffix)) - len(color.clear(prefix)) + barwidth = max(barwidth,10) + + currentBar = int(round(min(progress_normed*barwidth,barwidth))) + minBar = int(min(progress_normed*barwidth,barwidth)) + + if progress_normed == 0: bar = color.White + '━' * barwidth + elif progress_normed == 1: bar = color.LightGreen + '━' * barwidth + elif currentBar == minBar: bar = color_bar + '━' * currentBar + color.White + '╺' + color.White + '━' * (barwidth - currentBar - 1) + else: bar = color_bar + '━' * (currentBar - 1) + color_bar + '╸' + color.White + '━' * (barwidth - currentBar) + + msg = f"{prefix}{bar}{suffix}{color.NC}" + print(msg, end=end) + + + + # ________________________________________________________________________________ + # Stop the progress bar + + def stop(self): + self(self.previous_progress[-1], stop=True) + self.previous_progress = [0] + self.lastUpdate = None \ No newline at end of file diff --git a/build/lib/LRFutils/term.py b/build/lib/LRFutils/term.py new file mode 100644 index 0000000..9230caa --- /dev/null +++ b/build/lib/LRFutils/term.py @@ -0,0 +1,9 @@ +import os + +try: + term_size = os.get_terminal_size() + term_size = term_size.columns +except: term_size = 80 + +def hline(motif): + return motif * int(term_size / len(motif)) \ No newline at end of file diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..2109e6f --- /dev/null +++ b/changelog.md @@ -0,0 +1,22 @@ +# 0.0.11 + +> **Warning** +> +> This update include breaking changes 💥 + +## 📢 Announcements +- This module is now available on Pypi! +https://pypi.org/project/LRFutils/0.0.11/ + - You can then install it using `pip install LRFutils` + +## ➕ Additions +- Added `average_ETA` parameter on progress bar to prevent variating ETA. By default, this parameter is set to 10 + +## 🔧 Tweaks +- 💥 `LRFutils.progress.Bar()`'s `duration` parameter was renamed in `show_duration` to be more explicit. +- 💥 `LRFutils.log` module was renamed `LRFutils.logs` in order to have a conveniant import line (`from LRFutils import logs`) while avoiding conflict with mathematical log function. +- 💥 `LRFutils.color.Color` class, was removed. All the attribute are now directly in the module `LRFutils.color` (which allow to import the module on the same line than other ones `from LRFutils import color, logs, archive [...]`) + +# 0.0.10 + +> 🔎 Changelog doesn't go that far... \ No newline at end of file diff --git a/dist/LRFutils-0.0.11.tar.gz b/dist/LRFutils-0.0.11.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..05dd24fcc7d81d20cb8ebd1ffbfebecbf954076d GIT binary patch literal 5634 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 clTJG6q?1lM>7lVgLXD literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py index 50e4ee2..3412bd7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,7 +28,8 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'myst_parser' + 'myst_parser', + 'nbsphinx' ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/getting_started.md b/docs/getting_started.md index 09dff8e..446dab3 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -6,7 +6,7 @@ This project require python 3.10 or upper 1. Install the package ``` -pip install git+https://github.com/LeiRoF/LRFutils +pip install LRFutils ``` 2. That's it! There is no second step! diff --git a/docs/index.rst b/docs/index.rst index 73c44c5..0f8e8b5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,5 +22,6 @@ I don't guaranty any kind of performance, stability, etc. use it at your own ris archive color + logs progress term \ No newline at end of file diff --git a/docs/logs.ipynb b/docs/logs.ipynb new file mode 100644 index 0000000..6094182 --- /dev/null +++ b/docs/logs.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 📜 Logs" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m22/10/2022\u001b[0m at \u001b[35m09:41:20\u001b[0m | \u001b[32m[INFO] \u001b[0mHello world!\n", + "\u001b[34m22/10/2022\u001b[0m at \u001b[35m09:41:20\u001b[0m | \u001b[33m[WARNING] Hello world!\u001b[0m\n", + "\u001b[34m22/10/2022\u001b[0m at \u001b[35m09:41:20\u001b[0m | \u001b[41m[ERROR] Hello world!\u001b[0m\n", + " -> Look at \u001b[32mlogs/2022-10-22_09.41.20.923615.logs\u001b[0m for more information.\n", + "\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'notDefinedVariable' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32mc:\\Users\\vince\\Documents\\Dev\\Perso\\LRFutils\\docs\\logs.ipynb Cell 2\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 4\u001b[0m logs\u001b[39m.\u001b[39mwarn(\u001b[39m\"\u001b[39m\u001b[39mHello world!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 6\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m----> 7\u001b[0m \u001b[39mif\u001b[39;00m notDefinedVariable \u001b[39m==\u001b[39m \u001b[39mTrue\u001b[39;00m:\n\u001b[0;32m 8\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m\"\u001b[39m\u001b[39mEuh, this is not supposed to work\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 9\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mNameError\u001b[39;00m:\n", + "\u001b[1;31mNameError\u001b[0m: name 'notDefinedVariable' is not defined" + ] + } + ], + "source": [ + "from LRFutils import logs\n", + "\n", + "logs.info(\"Hello world!\")\n", + "logs.warn(\"Hello world!\")\n", + "\n", + "try:\n", + " if notDefinedVariable == True:\n", + " print(\"Euh, this is not supposed to work\")\n", + "except NameError:\n", + " logs.error(\"Hello world!\")\n", + " raise" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.8 64-bit (microsoft store)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e0d398e7c3cc3d2b8386dfea47f5eae3378d5d39db7e2c8ef87e93246db0bfd2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/progress.ipynb b/docs/progress.ipynb new file mode 100644 index 0000000..3ddc730 --- /dev/null +++ b/docs/progress.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ⌛ Progress\n", + "\n", + "This module allow to create a progress bar when you are performing a long task.\n", + "\n", + "## Example" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0mDemo progress bar \u001b[33m━━━━━━━━━━━━━━━━━━━━━━━━\u001b[37;1m╺\u001b[37;1m━━━━━━━━━━━━━━━━ \u001b[33m58% \u001b[31;1m587/1000 \u001b[35m0:00:06\u001b[0m\n" + ] + } + ], + "source": [ + "from LRFutils import progress\n", + "import time\n", + "\n", + "N = 1000\n", + "# creation (with all parameters)\n", + "myBar = progress.Bar(max = N, width = 80, prefix = \"Demo progress bar\", eta = True, decimals = 0, show_duration = True, average_ETA = 10)\n", + "\n", + "for i in range(N):\n", + " # update\n", + " myBar(i+1)\n", + " time.sleep(0.01)\n", + " if i == int(2*N/3):\n", + " myBar.stop()\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + "## Class attributes\n", + "\n", + "Nothing here...\n", + "\n", + "---\n", + "\n", + "## Class methods\n", + "\n", + "### Builder\n", + "\n", + "Create a progress bar object\n", + "\n", + "```python\n", + "progress.Bar(max = 1, width = 80, prefix = \"\", eta = True, decimals = 0, duration = True, average_ETA = 10)\n", + "```\n", + "**Parameters:**\n", + "- `max : float | int` maximum value of the bar. By default, this value is 1, so you have to update the bar using a ratio.\n", + "- `widht : int` bar's total lenght (80 characters by default)\n", + "- `prefix : str` short message displayed before the bar\n", + "- `eta : boolean` display or not the estimation of remaining time\n", + "- `decimals : int` number of decimals showed for the percentage\n", + "- `duration : boolean` display or not the spent time\n", + "- `average_ETA : int` average the computation of the estimation of time arrival on several progress update in order to prevent fluctuations.\n", + "\n", + "**Return types:**\n", + "- `Bar` progress bar object\n", + "\n", + "---\n", + "\n", + "## Object attributes\n", + "\n", + "- `max : float` maximum value of the bar. By default, this value is 1, so you have to update the bar using a ratio.\n", + "- `widht : int` bar's total lenght (80 characters by default)\n", + "- `prefix : str` short message displayed before the bar\n", + "- `eta : boolean` display or not the estimation of remaining time\n", + "- `decimals : int` number of decimals showed for the percentage\n", + "- `duration : boolean` display or not the spent time\n", + "- `lastProgress : float` last recorded `progress` value\n", + "- `lastUpdate : float` date (in second) of the last update\n", + "- `start_at : float` date (in second) of the creation of the bar\n", + "- `lastETA : float | str` last estimation of remaining time (in second). If there is no previous one, lastETA store `\"-\"`\n", + "\n", + "---\n", + "\n", + "## Object methods\n", + "\n", + "### Updater\n", + "Update the bar (print it in the terminal)\n", + "```python\n", + "myBar(progress: float, prefix=None, stop=False)\n", + "```\n", + "\n", + "**Parameters:**\n", + "- `progress : float` the progression of the computation. Tha bar will be filed according to the ratio `progress / max`\n", + "- `prefix : str` short message displayed before the bar\n", + "\n", + "> Note: if the `progress` reach the `max` value, the bar will automatically stop. A running progress bar ends with a '\\r' character in order to be overwritten by the next update. When the bar is stopped, the printed line ends with '\\n' so you can continue to print other stuff. If you update the bar after the bar stoped, it will display a new bar.\n", + "\n", + "**Return types:** None\n", + "\n", + "### Force stop\n", + "\n", + "Update and stop the bar by putting it in an incomplet mode.\n", + "\n", + "```python\n", + "stop()\n", + "```\n", + "\n", + "> Once a bar is stopped, the line cannot be overwritten, so it cannot be updated anymore. If you update the bar, it will display a new bar.\n", + "\n", + "**Parameters:** None\n", + "\n", + "**Return types:** None\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.8 64-bit (microsoft store)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e0d398e7c3cc3d2b8386dfea47f5eae3378d5d39db7e2c8ef87e93246db0bfd2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/progress.md b/docs/progress.md deleted file mode 100644 index de4a614..0000000 --- a/docs/progress.md +++ /dev/null @@ -1,95 +0,0 @@ -# ⌛ Progress - -This module allow to create a progress bar when you are performing a long task. - -## Example -```python -from LRFutils import progress -from time import time - -N = 1000 -# creation -myBar = progress.bar(max = N, width = 80, prefix = "Demo progress bar", eta = True, decimals = 0, duration = True) - -for i in range(N) - # update - myBar(i) - time.sleep(0.01) -``` - ---- - -## Class attributes - -Nothing here... - ---- - -## Class methods - -### Builder - -Create a progress bar object - -```python -progress.Bar(max = 1, width = 80, prefix = "", eta = True, decimals = 0, duration = True) -``` -**Parameters:** -- `max : float` maximum value of the bar. By default, this value is 1, so you have to update the bar using a ratio. -- `widht : int` bar's total lenght (80 characters by default) -- `prefix : str` short message displayed before the bar -- `eta : boolean` display or not the estimation of remaining time -- `decimals : int` number of decimals showed for the percentage -- `duration : boolean` display or not the spent time - -**Return types:** -- `Bar` progress bar object - ---- - -## Object attributes - -- `max : float` maximum value of the bar. By default, this value is 1, so you have to update the bar using a ratio. -- `widht : int` bar's total lenght (80 characters by default) -- `prefix : str` short message displayed before the bar -- `eta : boolean` display or not the estimation of remaining time -- `decimals : int` number of decimals showed for the percentage -- `duration : boolean` display or not the spent time -- `lastProgress : float` last recorded `progress` value -- `lastUpdate : float` date (in second) of the last update -- `start_at : float` date (in second) of the creation of the bar -- `lastETA : float | str` last estimation of remaining time (in second). If there is no previous one, lastETA store `"-"` - ---- - -## Object methods - -### Updater -Update the bar (print it in the terminal) -```python -myBar(progress: float, prefix=None, stop=False) -``` - -**Parameters:** -- `progress : float` the progression of the computation. Tha bar will be filed according to the ratio `progress / max` -- `prefix : str` short message displayed before the bar - -> Note: if the `progress` reach the `max` value, the bar will automatically stop. A running progress bar ends with a '\r' character in order to be overwritten by the next update. When the bar is stopped, the printed line ends with '\n' so you can continue to print other stuff. If you update the bar after the bar stoped, it will display a new bar. - -**Return types:** None - -### Force stop - -Update and stop the bar by putting it in an incomplet mode. - -```python -stop() -``` - -> Once a bar is stopped, the line cannot be overwritten, so it cannot be updated anymore. If you update the bar, it will display a new bar. - -**Parameters:** None - -**Return types:** None - - diff --git a/docs/requirements.txt b/docs/requirements.txt index 7531791..7ce91eb 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ myst-parser -sphinx-book-theme \ No newline at end of file +sphinx-book-theme +nbsphinx \ No newline at end of file diff --git a/examples.ipynb b/examples.ipynb index d8c8abb..b31a052 100644 --- a/examples.ipynb +++ b/examples.ipynb @@ -1,5 +1,14 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + "# Progress bar" + ] + }, { "cell_type": "code", "execution_count": 1, @@ -9,9 +18,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32;1m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[32;1m100% \u001b[31;1m1000/1000 \u001b[35m0:00:17\u001b[0m[0meta \u001b[34m0:00:00\u001b[0m\n", - "\u001b[0mThe best bar \u001b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[33m╸\u001b[37;1m━━━━━━━━━━━━━━━━ \u001b[33m64% \u001b[31;1m643/1000 \u001b[35m0:00:12\u001b[0m[34m0:00:06\u001b[0m\n", - "\u001b[0mWaw, another incredible bar \u001b[32;1m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[32;1m100% \u001b[31;1m1000/1000 \u001b[35m0:00:17\u001b[0m[0meta \u001b[34m0:00:00\u001b[0m\n" + "\u001b[32;1m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[32;1m100% \u001b[31;1m1000/1000 \u001b[35m0:00:10\u001b[0m[0meta \u001b[34m0:00:00\u001b[0m\n", + "\u001b[0mThe best bar \u001b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[33m╸\u001b[37;1m━━━━━━━━━━━━━━━━━━━ \u001b[33m58% \u001b[31;1m586/1000 \u001b[35m0:00:06\u001b[0m[34m0:00:04\u001b[0m\n", + "\u001b[0mWaw, another incredible bar \u001b[32;1m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[32;1m100% \u001b[31;1m1000/1000 \u001b[35m0:00:10\u001b[0m[0meta \u001b[34m0:00:00\u001b[0m\n" ] } ], @@ -31,7 +40,7 @@ "\n", "for i in range(N):\n", " a(i+1, prefix=i if i Look at \u001b[32mlogs/2022-09-03_10.12.04.435769.log\u001b[0m for more information.\n", - "\n" - ] - }, { "ename": "NameError", - "evalue": "name 'notDefinedError' is not defined", + "evalue": "name 'log' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32mc:\\Users\\vince\\Documents\\Dev\\Perso\\LRFutils\\examples.ipynb Cell 2\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 4\u001b[0m log\u001b[39m.\u001b[39mwarn(\u001b[39m\"\u001b[39m\u001b[39mHello world!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 5\u001b[0m log\u001b[39m.\u001b[39merror(\u001b[39m\"\u001b[39m\u001b[39mHello world!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[1;32m----> 7\u001b[0m \u001b[39mif\u001b[39;00m notDefinedError \u001b[39m==\u001b[39m \u001b[39mTrue\u001b[39;00m:\n\u001b[0;32m 8\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m\"\u001b[39m\u001b[39mEuh, this is not supposed to work\u001b[39m\u001b[39m\"\u001b[39m)\n", - "\u001b[1;31mNameError\u001b[0m: name 'notDefinedError' is not defined" + "\u001b[1;32mc:\\Users\\vince\\Documents\\Dev\\Perso\\LRFutils\\examples.ipynb Cell 4\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mLRFutils\u001b[39;00m \u001b[39mimport\u001b[39;00m logs\n\u001b[1;32m----> 3\u001b[0m log\u001b[39m.\u001b[39minfo(\u001b[39m\"\u001b[39m\u001b[39mHello world!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 4\u001b[0m log\u001b[39m.\u001b[39mwarn(\u001b[39m\"\u001b[39m\u001b[39mHello world!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 6\u001b[0m \u001b[39mtry\u001b[39;00m:\n", + "\u001b[1;31mNameError\u001b[0m: name 'log' is not defined" ] } ], "source": [ - "from LRFutils import log\n", + "from LRFutils import logs\n", + "\n", + "logs.info(\"Hello world!\")\n", + "logs.warn(\"Hello world!\")\n", + "\n", + "try:\n", + " if notDefinedVariable == True:\n", + " print(\"Euh, this is not supposed to work\")\n", + "except NameError:\n", + " logs.error(\"Hello world!\")\n", + " raise\n", "\n", - "log.info(\"Hello world!\")\n", - "log.warn(\"Hello world!\")\n", - "log.error(\"Hello world!\")" + "\n" ] } ], @@ -96,7 +111,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.10.8" }, "orig_nbformat": 4, "vscode": { diff --git a/setup.py b/setup.py index d5457de..f4964b9 100644 --- a/setup.py +++ b/setup.py @@ -6,14 +6,14 @@ setup( name="LRFutils", - version = "0.0.10", + version = "0.0.11", description = 'Just a custom library to share with some colleagues. Use it at your own risks.', author = 'Leirof', author_email = 'vince.lrf@gmail.com', url = 'https://github.com/LeiRoF/Utils', packages=['LRFutils'], install_requires=requirements, - python_requires='>=3.9.0', + python_requires='>=3.10.0', classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", diff --git a/test.py b/test.py deleted file mode 100644 index c8b8e45..0000000 --- a/test.py +++ /dev/null @@ -1,2 +0,0 @@ -if notDefinedError == True: - print("Euh, this is not supposed to work") \ No newline at end of file diff --git a/upload_on_pip.py b/upload_on_pip.py new file mode 100644 index 0000000..efbc9bb --- /dev/null +++ b/upload_on_pip.py @@ -0,0 +1,5 @@ +import os + +os.system("python3 -m build -s") +os.system("python3 -m pip install --upgrade twine") +os.system("python3 -m twine upload dist/*") \ No newline at end of file