Skip to content

Commit

Permalink
Merge pull request #27 from JordanWelsman/0.5-bugfixes
Browse files Browse the repository at this point in the history
Merging now.
  • Loading branch information
JordanWelsman authored May 27, 2023
2 parents 8e98087 + 005f248 commit 2d5dc5e
Show file tree
Hide file tree
Showing 10 changed files with 555 additions and 6 deletions.
2 changes: 1 addition & 1 deletion jutl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Dunder attributes
__version__ = "0.5.2"
__version__ = "0.5.3"
__author__ = "Jordan Welsman"
__license__ = "MIT"
__copyright__ = "Copyright 2023 Jordan Welsman"
10 changes: 10 additions & 0 deletions jutl/cryptography/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Import utils.py so module
# functions are usable at
# 'from jutl import cryptography' level.
from .caesarcipher import *
from .rot13cipher import *
from .substitutioncipher import *

# Only show functions specified in
# submodule files to the outside world.
__all__ = caesarcipher.__all__, rot13cipher.__all__, substitutioncipher.__all__
4 changes: 4 additions & 0 deletions jutl/cryptography/caesarcipher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Module imports

# External class visibility
__all__ = []
4 changes: 4 additions & 0 deletions jutl/cryptography/rot13cipher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Module imports

# External class visibility
__all__ = []
63 changes: 63 additions & 0 deletions jutl/cryptography/substitutioncipher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Module imports

# External class visibility
__all__ = ['SubstitutionCipher']


class SubstitutionCipher():
"""
Class which acts as the
base Cipher implementation.
"""
def __init__(self, rotation: int = 0):
"Initialization method."
self.rotation = self._check_rotation(rotation)

def __repr__(self) -> str:
"""
Tells the interpreter how
to represent this class.
"""
if self.rotation != 0:
print("s")


def _check_rotation(self, rotation: int) -> int:
"""
Checks if rotation is valid.
"""
allowed_range = range(0, 27)

if rotation in allowed_range:
return rotation
else:
return 0


def set_rotation(self, rotation: int = 0):
"""
Sets the rotation
after initialization.
"""
self.rotation = self._check_rotation(rotation)


def _encrypt(self, message: str):
"""
Encrypts the passed message
using the defined rotation.
"""
__alpha_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
__alpha_lower = "abcdefghijklmnopqrstuvwxyz"
encrypted_message: str = ""

for letter in message:
if letter in __alpha_upper:
encrypted_message += __alpha_upper[(__alpha_upper.find(letter) + self.rotation) % 26]
elif letter in __alpha_lower:
encrypted_message += __alpha_lower[(__alpha_lower.find(letter) + self.rotation) % 26]
else:
encrypted_message += letter

return encrypted_message

3 changes: 2 additions & 1 deletion jutl/timers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Import submodule files so
# classes and functions are usable at
# 'from jutl.timers import _' level.
from .reporter import *
from .stopwatch import *
from .timer import *

# Only show functions specified in
# submodule files to the outside world.
__all__ = stopwatch.__all__, timer.__all__
__all__ = reporter.__all__, stopwatch.__all__, timer.__all__
196 changes: 196 additions & 0 deletions jutl/timers/reporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Module imports
from jutl.formatting import apply
from time import time

# External class visibility
__all__ = ['Reporter']


class Reporter():
"""
Class which acts as a timer to
record loop times for comparison.
"""
def __init__(self, name: str = None, declare_times: bool = False):
"Initialization method."
self.name: str = name
self._start_time: float
self._stop_time: float
self.total_time: float = None
self._loops: list[float] = []
self.loop_times: list[float] = []
self._declare_times = declare_times

def __repr__(self) -> str:
"""
Tells the interpreter how
to represent this class.
"""
if self.name is None:
if self.total_time is None:
return "Reporter()"
else:
return f"Reporter({round(self.total_time, 2)}s)"
else:
if self.total_time is None:
return f"Reporter({self.name})"
else:
return f"Reporter({self.name}, {round(self.total_time, 2)}s)"

def __call__(self, color: str = None):
"""
Tells the interpreter what to
do when an object of this
class is called directly.
"""
if self.loop_times:
for n, time in enumerate(self.loop_times):
if color:
print(apply(text=f"Loop {n+1}: {round(time, 2)}s", text_color=color))
else:
print(f"Loop {n+1}: {round(time, 2)}s")
else:
print("There are no loop times.")

def __len__(self) -> int:
"""
Tells the interpreter what to
consider this class' length.
"""
return len(self._loops)

def __iter__(self) -> iter:
"""
Tells the interpreter what to
iterate over thwn iterator methods
are called on this class.
"""
return iter(self.loop_times)

def __eq__(self, other) -> bool:
"""
Tells the interpreter how this class
handles equal operators.
"""
return self.total_time == other.total_time

def __ne__(self, other) -> bool:
"""
Tells the interpreter how this class
handles not equal operators.
"""
return self.total_time != other.total_time

def __gt__(self, other) -> bool:
"""
Tells the interpreter how this class
handles greater than operators.
"""
return self.total_time > other.total_time

def __ge__(self, other) -> bool:
"""
Tells the interpreter how this class
handles greater or equal operators.
"""
return self.total_time >= other.total_time

def __lt__(self, other) -> bool:
"""
Tells the interpreter how this class
handles less than operators.
"""
return self.total_time < other.total_time

def __le__(self, other) -> bool:
"""
Tells the interpreter how this class
handles less than or equal operators.
"""
return self.total_time <= other.total_time

def __add__(self, other) -> float:
"""
Tells the interpreter how to sum these objects.
"""
return self.total_time + other.total_time

def __sub__(self, other) -> float:
"""
Tells the interpreter how to subtract these objects.
"""
return self.total_time - other.total_time

def __mul__(self, multiplier) -> float:
"""
Tells the interpreter how to subtract these objects.
"""
return self.total_time * multiplier

def __truediv__(self, other) -> float:
"""
Tells the interpreter how to subtract these objects.
"""
return self.total_time / other.total_time


def start(self, message: str = None, color : str = None):
"""
Starts the reporter and
optionall prints a message.
"""
self._start_time = time()
if message:
print(apply(text=message, text_color=color) if color else print(message))


def loop(self, loop_time: float = None, message: str = None, color: str = None):
"""
Adds the current time to the loop
time list, records the time since
the start or time of the last recorded
loop, and optionally prints a message.
"""
if loop_time:
self._loops.append(loop_time)
else:
self._loops.append(time())
if not self.loop_times:
self.loop_times.append(self._calculate_time(self._start_time, self._loops[-1]))
else:
self.loop_times.append(self._calculate_time(self._loops[-2], self._loops[-1]))
if message:
print(apply(text=message, text_color=color) if color else print(message))

def stop(self, message: str = None, color: str = None):
"""
Stops the reporter, calculates
the total time passed, and
optionally prints a message.
"""
self._stop_time = time()
self.total_time = self._calculate_time(self._start_time, self._stop_time)
self.loop(self._stop_time) # add final loop time and calculate loop difference
if message:
print(apply(text=message, text_color=color) if color else print(text=message))


def _calculate_time(self, time1: float, time2: float) -> float:
"""
Returns the difference in time where t2>t1.
"""
return time2 - time1


def reset(self, message: str = None, color: str = None):
"""
Resets all reporter attributes
and optionally prints a message.
"""
self._start_time = None
self._stop_time = None
self.total_time = None
self._loops.clear()
self.loop_times.clear()
if message:
print(apply(text=message, text_color=color) if color else print(text=message))
6 changes: 3 additions & 3 deletions jutl/timers/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ def __repr__(self) -> str:
else:
return f"Timer({self.name}, {round(self.total_time, 2)}s)"

def __call__(self, color: str = None):
def __call__(self, precision: int = 2, color: str = None):
"""
Tells the interpreter what to
do when an object of this
class is called directly.
"""
if self.total_time:
if color:
print(apply(text=f"{self.name} total time: {round(self.total_time, 2)}s", text_color=color))
print(apply(text=f"{self.name} total time: {round(self.total_time, precision)}s", text_color=color))
else:
print(f"{self.name} total time: {round(self.total_time, 2)}s")
print(f"{self.name} total time: {round(self.total_time, precision)}s")
else:
print("There is no recorded time.")

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Arguments
git_name = "jutils"
pypi_name = "jutl"
version = "0.5.2" # update __init__.py
version = "0.5.3" # update __init__.py
python_version = ">=3.10"

# Long description from README.md
Expand Down
Loading

0 comments on commit 2d5dc5e

Please sign in to comment.