diff --git a/bcrypt_test.py b/bcrypt_test.py new file mode 100755 index 0000000..09e58ad --- /dev/null +++ b/bcrypt_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""bcrypt_test.py +This module provides utilities for user authentication, including functions to +store hashed passwords, create new users, and authenticate existing users using +bcrypt for password hashing and a CSV file to store user data. +""" +import bcrypt +import csv + + +def store_password(password): + hashed_password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()) + return hashed_password + + +def check_password(password, hashed_password): + return bcrypt.checkpw(password.encode("utf-8"), hashed_password) + + +def create_user(username, password): + hashed_password = store_password(password).decode("utf-8") + + with open("passwords_db.csv", "a", newline="") as file: + writer = csv.writer(file) + writer.writerow([username, hashed_password]) + + +def authenticate_user(username, password): + try: + with open("passwords_db.csv", "r") as file: + reader = csv.reader(file) + for row in reader: + if row and row[0] == username: + hashed_password = row[1].encode("utf-8") + return check_password(password, hashed_password) + return False + except FileNotFoundError: + return False + + +if __name__ == "__main__": + create_user("user1", "mysecurepassword") + + if authenticate_user("user1", "mysecurepassword"): + print("Authentication successful") + else: + print("Authentication failed") diff --git a/email_example.py b/email_example.py old mode 100644 new mode 100755 index 4179651..f7e9890 --- a/email_example.py +++ b/email_example.py @@ -1,23 +1,22 @@ -# Import smtplib for the actual sending function +""" +This module sends an email with the contents of a specified text file as the +body. The "smtplib" and "email.message" modules are used to construct and send +the email. +""" + import smtplib -# Import the email modules we'll need from email.message import EmailMessage textfile = "textfile" -# Open the plain text file whose name is in textfile for reading. with open(textfile) as fp: - # Create a text/plain message msg = EmailMessage() msg.set_content(fp.read()) -# me == the sender's email address -# you == the recipient's email address msg["Subject"] = f"The contents of {textfile}" -msg["From"] = "roland@rtj.dev" -msg["To"] = "roland@rtj.dev" +msg["From"] = "roland" +msg["To"] = "roland" -# Send the message via our own SMTP server. s = smtplib.SMTP("localhost") s.send_message(msg) s.quit() diff --git a/freq.py b/freq.py old mode 100644 new mode 100755 diff --git a/patch_example.py b/patch_example.py old mode 100644 new mode 100755 index de03c11..589bfd6 --- a/patch_example.py +++ b/patch_example.py @@ -3,7 +3,7 @@ import unittest from io import StringIO from unittest.mock import patch -import print_things # import the module containing the function with print statements +import print_things class TestPrintFunction(unittest.TestCase): diff --git a/print_things.py b/print_things.py old mode 100644 new mode 100755 diff --git a/pyqttt.py b/pyqttt.py old mode 100644 new mode 100755 index b3e1262..e9f07c5 --- a/pyqttt.py +++ b/pyqttt.py @@ -1,3 +1,14 @@ +#!/usr/bin/env python3 +""" +This module contains a Python script utilizing the PyQt5 library to create a +basic graphical user interface (GUI) application. The application showcases a +tabbed window with two tabs, each containing a grid of numbers. The first tab +displays numbers from 1 to 100, and the second tab displays numbers from 101 to +200, arranged in a grid format. + +Dependencies: + PyQt5 +""" import sys from PyQt5.QtWidgets import ( QApplication, @@ -13,50 +24,40 @@ class TabbedWindow(QMainWindow): def __init__(self): super().__init__() - # Set the main window title and size self.setWindowTitle("Tabbed Window") self.resize(300, 300) - # Create a tab widget self.tab_widget = QTabWidget() self.setCentralWidget(self.tab_widget) - # Create the first tab self.tab1 = QWidget() self.tab_widget.addTab(self.tab1, "1-100") - # Create a grid layout for the first tab layout1 = QGridLayout() layout1.setHorizontalSpacing(10) layout1.setVerticalSpacing(10) - # Add the numbers 1-100 to the layout for i in range(1, 101): column = (i - 1) % 10 row = (i - 1) // 10 label = QLabel(str(i)) layout1.addWidget(label, row, column) - # Set the layout for the first tab self.tab1.setLayout(layout1) - # Create the second tab self.tab2 = QWidget() self.tab_widget.addTab(self.tab2, "101-200") - # Create a grid layout for the second tab layout2 = QGridLayout() layout2.setHorizontalSpacing(10) layout2.setVerticalSpacing(10) - # Add the numbers 101-200 to the layout for i in range(101, 201): column = (i - 101) % 10 row = (i - 101) // 10 label = QLabel(str(i)) layout2.addWidget(label, row, column) - # Set the layout for the second tab self.tab2.setLayout(layout2) diff --git a/rand_char.py b/rand_char.py index 7c3d6d1..77624b4 100755 --- a/rand_char.py +++ b/rand_char.py @@ -2,13 +2,13 @@ """ Generate and Print Random Unicode Characters -This module generates a string of random Unicode characters, specifically avoiding the -surrogate pair range (0xD800 to 0xDFFF). The generated string has a default length of -5000 characters. +This module generates a string of random Unicode characters, specifically +avoiding the surrogate pair range (0xD800 to 0xDFFF). The generated string has +a default length of 5000 characters. Usage: - Run the script with an argument to specify the length of the string to be generated: - `python script_name.py 5000` + Run the script with an argument to specify the length of the string to be + generated: `python script_name.py 5000` """ import random from argparse import ArgumentParser @@ -21,7 +21,11 @@ def generate_string(length): [ chr( random.choice( - [i for i in range(0x0, 0xD7FF + 1) if i < 0xD800 or i > 0xDFFF] + [ + i + for i in range(0x0, 0xD7FF + 1) + if i < 0xD800 or i > 0xDFFF + ] ) ) for _ in range(length) @@ -30,7 +34,7 @@ def generate_string(length): except UnicodeEncodeError as e: print(f"Error encoding character: {e}") - return(characters) + return characters if __name__ == "__main__": @@ -45,4 +49,4 @@ if __name__ == "__main__": ) args = parser.parse_args() - print(generate_string(args.length)) \ No newline at end of file + print(generate_string(args.length)) diff --git a/readline/creatures.py b/readline/creatures.py old mode 100644 new mode 100755 index eecac57..361f1b0 --- a/readline/creatures.py +++ b/readline/creatures.py @@ -1,12 +1,21 @@ +#!/usr/bin/env +""" +This module implements a simple console application to manage a list of creatures. +It provides functionalities to add a creature to the list, lookup creatures with +autocomplete support (press tab to auto-complete creature names), and quit the +application. +""" import readline creatures = [] + def add_creature(): creature = input("Enter a creature name: ") creatures.append(creature) print(f"{creature} added to the list of creatures.") + def lookup_creature(): def completer(text, state): options = [c for c in creatures if c.startswith(text)] @@ -14,46 +23,51 @@ def lookup_creature(): return options[state] else: return None - + readline.set_completer(completer) readline.parse_and_bind("tab: complete") - + print("List of creatures:") for creature in creatures: print(f"- {creature}") - + while True: - creature = input("Enter the name of a creature or press enter to return to the main menu: ") + creature = input( + "Enter the name of a creature or press enter to return to the main menu: " + ) if not creature: break elif creature in creatures: print(f"{creature} found!") else: print(f"{creature} not found.") - + readline.set_completer(None) readline.parse_and_bind("tab: ") + def quit(): print("Goodbye!") exit() -menu = { - "1": add_creature, - "2": lookup_creature, - "3": quit -} -while True: - print("Menu:") - print("[1] Add Creature") - print("[2] Lookup Creature") - print("[3] Quit") - - choice = input("Enter your choice: ") - action = menu.get(choice) - if action: - action() - else: - print(f"{choice} is not a valid option.") +menu = {"1": add_creature, "2": lookup_creature, "3": quit} + +def main(): + while True: + print("Menu:") + print("[1] Add Creature") + print("[2] Lookup Creature") + print("[3] Quit") + + choice = input("Enter your choice: ") + action = menu.get(choice) + if action: + action() + else: + print(f"{choice} is not a valid option.") + + +if __name__ == "__main__": + main() diff --git a/readline/mtg.py b/readline/mtg.py old mode 100644 new mode 100755 index 0beb551..0c67d69 --- a/readline/mtg.py +++ b/readline/mtg.py @@ -1,15 +1,25 @@ +#!/usr/bin/env python3 +""" +This module defines a command-line interface (CLI) application which allows +users to interact with a predefined list of completion options, specifically, +card names from the "Alara Reborn" set. + +It leverages the `cmd` module to build the CLI and has tab-completion +functionality for adding items from the predefined list of card names. +""" import cmd completions = [ - 'Mage Slayer (Alara Reborn)', - 'Magefire Wings (Alara Reborn)', - 'Sages of the Anima (Alara Reborn)', - 'Sanctum Plowbeast (Alara Reborn)', - 'Sangrite Backlash (Alara Reborn)', - 'Sanity Gnawers (Alara Reborn)', - 'Sen Triplets (Alara Reborn)' + "Mage Slayer (Alara Reborn)", + "Magefire Wings (Alara Reborn)", + "Sages of the Anima (Alara Reborn)", + "Sanctum Plowbeast (Alara Reborn)", + "Sangrite Backlash (Alara Reborn)", + "Sanity Gnawers (Alara Reborn)", + "Sen Triplets (Alara Reborn)", ] + class mycmd(cmd.Cmd): def __init__(self): cmd.Cmd.__init__(self) @@ -21,9 +31,10 @@ class mycmd(cmd.Cmd): pass def complete_add(self, text, line, begidx, endidx): - mline = line.partition(' ')[2] + mline = line.partition(" ")[2] offs = len(mline) - len(text) return [s[offs:] for s in completions if s.startswith(mline)] -if __name__ == '__main__': + +if __name__ == "__main__": mycmd().cmdloop() diff --git a/readline/readline_auto_complete.py b/readline/readline_auto_complete.py deleted file mode 100644 index 6e68a68..0000000 --- a/readline/readline_auto_complete.py +++ /dev/null @@ -1,92 +0,0 @@ -import cmd -import os -import readline -import sys - -# Set up history file -histfile = os.path.join(os.path.expanduser('~'), '.history') -try: - readline.read_history_file(histfile) -except FileNotFoundError: - open(histfile, 'wb').close() - -# Define add and subtract functions -def add(x, y): - return x + y - -def subtract(x, y): - return x - y - -# Define command processor -class MyCmd(cmd.Cmd): - prompt = '> ' - intro = 'Type help for commands' - - def do_exit(self, arg): - """Exit the program""" - return True - - def do_add(self, arg): - """Add two numbers: add """ - try: - num1, num2 = map(float, arg.split()) - except ValueError: - print('Invalid input') - return - print(add(num1, num2)) - - def complete_add(self, text, line, begidx, endidx): - if not text: - completions = ['', ''] - elif '' in line: - completions = [''] - else: - completions = [''] - return [c for c in completions if c.startswith(text)] - - def do_subtract(self, arg): - """Subtract two numbers: subtract """ - try: - num1, num2 = map(float, arg.split()) - except ValueError: - print('Invalid input') - return - print(subtract(num1, num2)) - - def complete_subtract(self, text, line, begidx, endidx): - if not text: - completions = ['', ''] - elif '' in line: - completions = [''] - else: - completions = [''] - return [c for c in completions if c.startswith(text)] - - def do_clear(self, arg): - """Clear the screen""" - if sys.platform.startswith('win'): - os.system('cls') - else: - os.system('clear') - - def default(self, line): - print('Invalid command') - - def emptyline(self): - pass - -# Run command processor -console = MyCmd() -readline.set_completer_delims(' \t\n;') -readline.parse_and_bind('tab: complete') -while True: - try: - line = input(console.prompt) - except EOFError: - break - console.onecmd(line) - -# Save history file -with open(histfile, 'w') as f: - readline.write_history_file(histfile) - diff --git a/readline/readline_calc.py b/readline/readline_calc.py deleted file mode 100644 index 13c089f..0000000 --- a/readline/readline_calc.py +++ /dev/null @@ -1,54 +0,0 @@ -import readline - -# Set up history file -histfile = '.history' -try: - readline.read_history_file(histfile) -except FileNotFoundError: - open(histfile, 'wb').close() - -# Define add and subtract functions -def add(x, y): - return x + y - -def subtract(x, y): - return x - y - -# Loop for user input -while True: - # Read user input - try: - line = input('> ') - except EOFError: - break - - # Check for exit command - if line == 'exit': - break - - # Parse user input - try: - args = line.split() - if len(args) != 3: - raise ValueError - num1 = float(args[0]) - num2 = float(args[2]) - op = args[1] - if op not in ['+', '-']: - raise ValueError - except ValueError: - print('Invalid input') - continue - - # Perform operation - if op == '+': - result = add(num1, num2) - else: - result = subtract(num1, num2) - - # Print result and add command to history - print(result) - readline.add_history(line) - -# Save history file -readline.write_history_file(histfile) diff --git a/readline/readline_cmd.py b/readline/readline_cmd.py deleted file mode 100644 index a65c130..0000000 --- a/readline/readline_cmd.py +++ /dev/null @@ -1,66 +0,0 @@ -import cmd -import os -import readline - -# Set up history file -histfile = os.path.join(os.path.expanduser('~'), '.history') -try: - readline.read_history_file(histfile) -except FileNotFoundError: - open(histfile, 'wb').close() - -# Define add and subtract functions -def add(x, y): - return x + y - -def subtract(x, y): - return x - y - -# Define command processor -class MyCmd(cmd.Cmd): - prompt = '> ' - intro = 'Type help for commands' - - def do_exit(self, arg): - """Exit the program""" - return True - - def do_add(self, arg): - """Add two numbers: add """ - try: - num1, num2 = map(float, arg.split()) - except ValueError: - print('Invalid input') - return - print(add(num1, num2)) - - def do_subtract(self, arg): - """Subtract two numbers: subtract """ - try: - num1, num2 = map(float, arg.split()) - except ValueError: - print('Invalid input') - return - print(subtract(num1, num2)) - - def default(self, line): - print('Invalid command') - - def emptyline(self): - pass - -# Run command processor -console = MyCmd() -readline.set_completer_delims(' \t\n;') -readline.parse_and_bind('tab: complete') -while True: - try: - line = input(console.prompt) - except EOFError: - break - console.onecmd(line) - -# Save history file -with open(histfile, 'w') as f: - readline.write_history_file(histfile) - diff --git a/readline/readline_test.py b/readline/readline_test.py deleted file mode 100644 index 159e6ea..0000000 --- a/readline/readline_test.py +++ /dev/null @@ -1,39 +0,0 @@ -import atexit -import code -import os -import readline - -class HistoryConsole(code.InteractiveConsole): - def __init__(self, locals=None, filename="", - histfile=os.path.expanduser("~/.console-history")): - code.InteractiveConsole.__init__(self, locals, filename) - self.init_history(histfile) - - def init_history(self, histfile): - readline.parse_and_bind("tab: complete") - if hasattr(readline, "read_history_file"): - try: - readline.read_history_file(histfile) - except FileNotFoundError: - pass - atexit.register(self.save_history, histfile) - - def save_history(self, histfile): - readline.set_history_length(1000) - readline.write_history_file(histfile) - - -# Run console -console = HistoryConsole() -while True: - try: - line = input('> ') - except EOFError: - break - - # Check for exit command - if line == 'exit': - break - - # Process user input - console.push(line) diff --git a/set_get_attr_example.py b/set_get_attr_example.py old mode 100644 new mode 100755 index 59a4da4..ed9939a --- a/set_get_attr_example.py +++ b/set_get_attr_example.py @@ -1,3 +1,37 @@ +""" +set_get_attr_example.py +----------------------- + +This module contains a class named `Number` which implements special attribute +access methods to demonstrate custom attribute setting and getting behaviors +in a Python class. + +Here is a summary of its functionality and methods: + +- `__init__(self, number)`: Initializes a new instance with a `number` parameter. +- `power(self)`: Squares the current value of the `_number` attribute. It utilizes + `self.number` to access the `_number` attribute, which works correctly due to + the overridden `__getattribute__` method. +- `another_func(self)`: Prints a message when invoked. +- `__str__(self)`: Returns a string representation of the `_number` attribute. + +The class also overrides special methods (`__setattr__`, `__getattribute__`, +`__getattr__`) to define custom behaviors for setting, getting, and accessing +non-existent attributes, respectively. + +Usage: + If run as the main program, an instance of `Number` is created with an initial + value of 5. The script then performs various operations to demonstrate the + custom attribute access behaviors. + +Note: + The `__getattribute__` method in the `Number` class is implemented such that if + an attribute other than the ones listed in the `options` list is accessed, the + `_number` attribute value is returned. This is demonstrated in the script where + `number.num` and `number.number` (which are non-existing attributes) are accessed, + but the `_number` value is printed instead of raising an AttributeError. +""" + class Number: def __init__(self, number): self._number = number @@ -31,3 +65,11 @@ class Number: def __getattr__(self, name): return self._number + +if __name__ == "__main__": + number = Number(5) + print(number.num) + print(number.number) + number.power() + print(number.num) + number.another_func() diff --git a/test.py b/test.py deleted file mode 100644 index 6c7f266..0000000 --- a/test.py +++ /dev/null @@ -1,15 +0,0 @@ -import unittest - - -class Yest(unittest.TestCase): - def test_int(self): - n1 = 5 - self.assertIsInstance(n1, int, "n1 should be an int") - int("124124") - a = 5 - self.assertIsInstance(a, int) - - assert isinstance(n1, int) - - -unittest.main() diff --git a/thread_pool.py b/thread_pool.py new file mode 100755 index 0000000..1952dcf --- /dev/null +++ b/thread_pool.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +""" +This module demonstrates the use of asyncio to handle asynchronous and blocking +functions in Python. The module contains three functions: a blocking function +that simulates a long-running process with `time.sleep`, an asynchronous +function that demonstrates asyncio's sleep, and a main function that runs +both the blocking and async functions concurrently using a ThreadPoolExecutor +for the blocking function. +""" + +import asyncio +from concurrent.futures import ThreadPoolExecutor +import time + + +def blocking_function(): + time.sleep(2) + return "Blocking function completed!" + + +async def async_function(): + print("Async function started!") + await asyncio.sleep(1) + print("Async function completed!") + + +async def main(): + loop = asyncio.get_event_loop() + executor = ThreadPoolExecutor() + + async_task = asyncio.create_task(async_function()) + + result = await loop.run_in_executor(executor, blocking_function) + print(result) + + await async_task + + +if __name__ == "__main__": + asyncio.run(main())