diff --git a/.gitignore b/.gitignore index c560be3..72b5e14 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ py101_2nd_code.wpu chapter22_type_hints/.mypy_cache/ *.pyc +*.zip +*.db +*.pdf +*.mypy_cache \ No newline at end of file diff --git a/appendix_b_git/arithmetic.py b/appendix_b_git/arithmetic.py new file mode 100644 index 0000000..f49c8db --- /dev/null +++ b/appendix_b_git/arithmetic.py @@ -0,0 +1,13 @@ +# arithmetic.py + +def add(x, y): + return x + y + +def divide(x, y): + return x / y + +def multiply(x, y): + return x * y + +def subtract(x, y): + return x - y diff --git a/chapter27_decorators/classmethod_example.py b/chapter27_decorators/classmethod_example.py new file mode 100644 index 0000000..e35b726 --- /dev/null +++ b/chapter27_decorators/classmethod_example.py @@ -0,0 +1,27 @@ +class Time: + """an example 24-hour time class""" + + def __init__(self, hour, minute): + self.hour = hour + self.minute = minute + + def __repr__(self): + return "Time(%d, %d)" % (self.hour, self.minute) + + @classmethod + def from_float(cls, moment): + """2.5 == 2 hours, 30 minutes, 0 seconds, 0 microseconds""" + hours = int(moment) + if hours: + moment = moment % hours + minutes = int(moment * 60) + return cls(hours, minutes) + + def to_float(self): + """return self as a floating point number""" + return self.hour + self.minute / 60 + +Time(7, 30) +Time.from_float(5.75) +t = Time(10, 15) +t.to_float() \ No newline at end of file diff --git a/chapter27_decorators/decorator_syntax_with_arguments.py b/chapter27_decorators/decorator_syntax_with_arguments.py index ee861f2..bfd6ea8 100644 --- a/chapter27_decorators/decorator_syntax_with_arguments.py +++ b/chapter27_decorators/decorator_syntax_with_arguments.py @@ -7,8 +7,11 @@ def func_info(arg1, arg2): def the_real_decorator(function): def wrapper(*args, **kwargs): - print('Function {} args: {} kwargs: {}'.format( - function.__name__, str(args), str(kwargs))) + print('Function {} args: {} kwargs: {}' + .format( + function.__name__, + str(args), + str(kwargs))) return function(*args, **kwargs) return wrapper diff --git a/chapter32_argparse/file_parser.py b/chapter32_argparse/file_parser.py index 5dc6f85..9b3db74 100644 --- a/chapter32_argparse/file_parser.py +++ b/chapter32_argparse/file_parser.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter32_argparse/file_parser_aliases.py b/chapter32_argparse/file_parser_aliases.py index 97e7fa7..d56f8b9 100644 --- a/chapter32_argparse/file_parser_aliases.py +++ b/chapter32_argparse/file_parser_aliases.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter32_argparse/file_parser_aliases2.py b/chapter32_argparse/file_parser_aliases2.py index 43b80a6..e64d642 100644 --- a/chapter32_argparse/file_parser_aliases2.py +++ b/chapter32_argparse/file_parser_aliases2.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter32_argparse/file_parser_exclusive.py b/chapter32_argparse/file_parser_exclusive.py index 4f03b89..7eb3b82 100644 --- a/chapter32_argparse/file_parser_exclusive.py +++ b/chapter32_argparse/file_parser_exclusive.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter32_argparse/file_parser_no_help.py b/chapter32_argparse/file_parser_no_help.py index 9c89971..b69614e 100644 --- a/chapter32_argparse/file_parser_no_help.py +++ b/chapter32_argparse/file_parser_no_help.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter32_argparse/file_parser_with_description.py b/chapter32_argparse/file_parser_with_description.py index f0c1b81..c755a64 100644 --- a/chapter32_argparse/file_parser_with_description.py +++ b/chapter32_argparse/file_parser_with_description.py @@ -2,7 +2,7 @@ import argparse -def file_parser(input_file, output_file = ''): +def file_parser(input_file, output_file=''): print(f'Processing {input_file}') print('Finished processing') if output_file: diff --git a/chapter35_scrape_website/downloading_files.py b/chapter35_scrape_website/downloading_files.py index b80f20d..ee766f7 100644 --- a/chapter35_scrape_website/downloading_files.py +++ b/chapter35_scrape_website/downloading_files.py @@ -4,8 +4,9 @@ def download_file(url): urllib.request.urlretrieve(url, "code.zip") def alternate_download(url): - f = urllib.request.urlopen(url) - data = f.read() + with urllib.request.urlopen(url) as response: + data = response.read() + with open("code2.zip", "wb") as code: code.write(data) diff --git a/chapter36_csv/books.csv b/chapter36_csv/books.csv new file mode 100644 index 0000000..9833652 --- /dev/null +++ b/chapter36_csv/books.csv @@ -0,0 +1,4 @@ +book_title,author,publisher,pub_date,isbn +Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 +wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 +Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081 \ No newline at end of file diff --git a/chapter36_csv/csv_dict_reader.py b/chapter36_csv/csv_dict_reader.py new file mode 100644 index 0000000..0e0acc4 --- /dev/null +++ b/chapter36_csv/csv_dict_reader.py @@ -0,0 +1,12 @@ +# csv_dict_reader.py + +import csv + +def process_csv_dict_reader(file_obj): + reader = csv.DictReader(file_obj) + for line in reader: + print(f'{line["book_title"]} by {line["author"]}') + +if __name__ == '__main__': + with open('books.csv', newline='') as csvfile: + process_csv_dict_reader(csvfile) \ No newline at end of file diff --git a/chapter36_csv/csv_dict_writer.py b/chapter36_csv/csv_dict_writer.py new file mode 100644 index 0000000..964144b --- /dev/null +++ b/chapter36_csv/csv_dict_writer.py @@ -0,0 +1,28 @@ +# csv_dict_writer.py + +import csv + +def csv_dict_writer(path, headers, data): + with open(path, 'w', newline='') as csvfile: + writer = csv.DictWriter(csvfile, delimiter=',', + fieldnames=headers) + writer.writeheader() + for record in data: + writer.writerow(record) + +if __name__ == '__main__': + data = '''book_title,author,publisher,pub_date,isbn + Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 + wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 + Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081''' + records = [] + for line in data.splitlines(): + records.append(line.strip().split(',')) + headers = records.pop(0) + + list_of_dicts = [] + for row in records: + my_dict = dict(zip(headers, row)) + list_of_dicts.append(my_dict) + + csv_dict_writer('output_dict.csv', headers, list_of_dicts) \ No newline at end of file diff --git a/chapter36_csv/csv_reader.py b/chapter36_csv/csv_reader.py new file mode 100644 index 0000000..ccdc251 --- /dev/null +++ b/chapter36_csv/csv_reader.py @@ -0,0 +1,12 @@ +# csv_reader.py + +import csv + +def process_csv(path): + with open(path, newline='') as csvfile: + reader = csv.reader(csvfile) + for row in reader: + print(row) + +if __name__ == '__main__': + process_csv('books.csv') \ No newline at end of file diff --git a/chapter36_csv/csv_reader_no_header.py b/chapter36_csv/csv_reader_no_header.py new file mode 100644 index 0000000..5030e66 --- /dev/null +++ b/chapter36_csv/csv_reader_no_header.py @@ -0,0 +1,14 @@ +# csv_reader_no_header.py + +import csv + +def process_csv(path): + with open(path, newline='') as csvfile: + reader = csv.reader(csvfile) + # Skip the header + next(reader, None) + for row in reader: + print(row) + +if __name__ == '__main__': + process_csv('books.csv') \ No newline at end of file diff --git a/chapter36_csv/csv_writer.py b/chapter36_csv/csv_writer.py new file mode 100644 index 0000000..0fa594b --- /dev/null +++ b/chapter36_csv/csv_writer.py @@ -0,0 +1,19 @@ +# csv_writer.py + +import csv + +def csv_writer(path, data): + with open(path, 'w', newline='') as csvfile: + writer = csv.writer(csvfile, delimiter=',') + for row in data: + writer.writerow(row) + +if __name__ == '__main__': + data = '''book_title,author,publisher,pub_date,isbn + Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 + wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 + Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081''' + records = [] + for line in data.splitlines(): + records.append(line.strip().split(',')) + csv_writer('output.csv', records) \ No newline at end of file diff --git a/chapter36_csv/csv_writer_rows.py b/chapter36_csv/csv_writer_rows.py new file mode 100644 index 0000000..0143498 --- /dev/null +++ b/chapter36_csv/csv_writer_rows.py @@ -0,0 +1,18 @@ +# csv_writer_rows.py + +import csv + +def csv_writer(path, data): + with open(path, 'w', newline='') as csvfile: + writer = csv.writer(csvfile, delimiter=',') + writer.writerows(data) + +if __name__ == '__main__': + data = '''book_title,author,publisher,pub_date,isbn + Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 + wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 + Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081''' + records = [] + for line in data.splitlines(): + records.append(line.strip().split(',')) + csv_writer('output2.csv', records) \ No newline at end of file diff --git a/chapter36_csv/output.csv b/chapter36_csv/output.csv new file mode 100644 index 0000000..6d9c4de --- /dev/null +++ b/chapter36_csv/output.csv @@ -0,0 +1,4 @@ +book_title,author,publisher,pub_date,isbn +Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 +wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 +Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081 diff --git a/chapter36_csv/output_dict.csv b/chapter36_csv/output_dict.csv new file mode 100644 index 0000000..6d9c4de --- /dev/null +++ b/chapter36_csv/output_dict.csv @@ -0,0 +1,4 @@ +book_title,author,publisher,pub_date,isbn +Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 +wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 +Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081 diff --git a/chapter37_sqlite/add_data.py b/chapter37_sqlite/add_data.py new file mode 100644 index 0000000..77c6a82 --- /dev/null +++ b/chapter37_sqlite/add_data.py @@ -0,0 +1,25 @@ +# add_data.py + +import sqlite3 + +conn = sqlite3.connect("books.db") +cursor = conn.cursor() + +# insert a record into the database +cursor.execute("""INSERT INTO books + VALUES ('Python 101', 'Mike Driscoll', '9/01/2020', + 'Mouse Vs Python', 'epub')""" + ) + +# save data to database +conn.commit() + +# insert multiple records using the more secure "?" method +books = [('Python Interviews', 'Mike Driscoll', + '2/1/2018', 'Packt Publishing', 'softcover'), + ('Automate the Boring Stuff with Python', + 'Al Sweigart', '', 'No Starch Press', 'PDF'), + ('The Well-Grounded Python Developer', + 'Doug Farrell', '2020', 'Manning', 'Kindle')] +cursor.executemany("INSERT INTO books VALUES (?,?,?,?,?)", books) +conn.commit() \ No newline at end of file diff --git a/chapter37_sqlite/create_database.py b/chapter37_sqlite/create_database.py new file mode 100644 index 0000000..54ab740 --- /dev/null +++ b/chapter37_sqlite/create_database.py @@ -0,0 +1,13 @@ +# create_database.py + +import sqlite3 + +conn = sqlite3.connect("books.db") + +cursor = conn.cursor() + +# create a table +cursor.execute("""CREATE TABLE books + (title text, author text, release_date text, + publisher text, book_type text) + """) \ No newline at end of file diff --git a/chapter37_sqlite/delete_record.py b/chapter37_sqlite/delete_record.py new file mode 100644 index 0000000..43c0726 --- /dev/null +++ b/chapter37_sqlite/delete_record.py @@ -0,0 +1,17 @@ +# delete_record.py + +import sqlite3 + +def delete_author(author): + conn = sqlite3.connect("books.db") + cursor = conn.cursor() + + sql = f""" + DELETE FROM books + WHERE author = '{author}' + """ + cursor.execute(sql) + conn.commit() + +if __name__ == '__main__': + delete_author(author='Al Sweigart') \ No newline at end of file diff --git a/chapter37_sqlite/queries.py b/chapter37_sqlite/queries.py new file mode 100644 index 0000000..7cb106f --- /dev/null +++ b/chapter37_sqlite/queries.py @@ -0,0 +1,29 @@ +# queries.py + +import sqlite3 + +def get_cursor(): + conn = sqlite3.connect("books.db") + return conn.cursor() + +def select_all_records_by_author(cursor, author): + sql = "SELECT * FROM books WHERE author=?" + cursor.execute(sql, [author]) + print(cursor.fetchall()) # or use fetchone() + print("\nHere is a listing of the rows in the table\n") + for row in cursor.execute("SELECT rowid, * FROM books ORDER BY author"): + print(row) + +def select_using_like(cursor, text): + print("\nLIKE query results:\n") + sql = f""" + SELECT * FROM books + WHERE title LIKE '{text}%'""" + cursor.execute(sql) + print(cursor.fetchall()) + +if __name__ == '__main__': + cursor = get_cursor() + select_all_records_by_author(cursor, + author='Mike Driscoll') + select_using_like(cursor, text='Python') \ No newline at end of file diff --git a/chapter37_sqlite/update_record.py b/chapter37_sqlite/update_record.py new file mode 100644 index 0000000..46ae430 --- /dev/null +++ b/chapter37_sqlite/update_record.py @@ -0,0 +1,19 @@ +# update_record.py + +import sqlite3 + + +def update_author(old_name, new_name): + conn = sqlite3.connect("books.db") + cursor = conn.cursor() + sql = f""" + UPDATE books + SET author = '{new_name}' + WHERE author = '{old_name}' + """ + cursor.execute(sql) + conn.commit() + +if __name__ == '__main__': + update_author(old_name='Mike Driscoll', + new_name='Michael Driscoll') \ No newline at end of file diff --git a/chapter38_excel/books.xlsx b/chapter38_excel/books.xlsx new file mode 100644 index 0000000..f57e615 Binary files /dev/null and b/chapter38_excel/books.xlsx differ diff --git a/chapter38_excel/creating_sheets.py b/chapter38_excel/creating_sheets.py new file mode 100644 index 0000000..d8bdb38 --- /dev/null +++ b/chapter38_excel/creating_sheets.py @@ -0,0 +1,18 @@ +# creating_sheets.py + +import openpyxl + +def create_worksheets(path): + workbook = openpyxl.Workbook() + print(workbook.sheetnames) + # Add a new worksheet + workbook.create_sheet() + print(workbook.sheetnames) + # Insert a worksheet + workbook.create_sheet(index=1, + title='Second sheet') + print(workbook.sheetnames) + workbook.save(path) + +if __name__ == '__main__': + create_worksheets('sheets.xlsx') \ No newline at end of file diff --git a/chapter38_excel/delete_demo.py b/chapter38_excel/delete_demo.py new file mode 100644 index 0000000..58098a3 --- /dev/null +++ b/chapter38_excel/delete_demo.py @@ -0,0 +1,21 @@ +# delete_demo.py + +from openpyxl import Workbook + +def deleting_cols_rows(path): + workbook = Workbook() + sheet = workbook.active + sheet['A1'] = 'Hello' + sheet['B1'] = 'from' + sheet['C1'] = 'OpenPyXL' + sheet['A2'] = 'row 2' + sheet['A3'] = 'row 3' + sheet['A4'] = 'row 4' + # Delete column A + sheet.delete_cols(idx=1) + # delete 2 rows starting on the second row + sheet.delete_rows(idx=2, amount=2) + workbook.save(path) + +if __name__ == '__main__': + deleting_cols_rows('deleting.xlsx') \ No newline at end of file diff --git a/chapter38_excel/delete_sheets.py b/chapter38_excel/delete_sheets.py new file mode 100644 index 0000000..026234e --- /dev/null +++ b/chapter38_excel/delete_sheets.py @@ -0,0 +1,17 @@ +# delete_sheets.py + +import openpyxl + +def create_worksheets(path): + workbook = openpyxl.Workbook() + workbook.create_sheet() + # Insert a worksheet + workbook.create_sheet(index=1, + title='Second sheet') + print(workbook.sheetnames) + del workbook['Second sheet'] + print(workbook.sheetnames) + workbook.save(path) + +if __name__ == '__main__': + create_worksheets('del_sheets.xlsx') \ No newline at end of file diff --git a/chapter38_excel/insert_demo.py b/chapter38_excel/insert_demo.py new file mode 100644 index 0000000..8046b29 --- /dev/null +++ b/chapter38_excel/insert_demo.py @@ -0,0 +1,18 @@ +# insert_demo.py + +from openpyxl import Workbook + +def inserting_cols_rows(path): + workbook = Workbook() + sheet = workbook.active + sheet['A1'] = 'Hello' + sheet['A2'] = 'from' + sheet['A3'] = 'OpenPyXL' + # insert a column before A + sheet.insert_cols(idx=1) + # insert 2 rows starting on the second row + sheet.insert_rows(idx=2, amount=2) + workbook.save(path) + +if __name__ == '__main__': + inserting_cols_rows('inserting.xlsx') \ No newline at end of file diff --git a/chapter38_excel/iterating_over_cell_values.py b/chapter38_excel/iterating_over_cell_values.py new file mode 100644 index 0000000..3f64c5e --- /dev/null +++ b/chapter38_excel/iterating_over_cell_values.py @@ -0,0 +1,14 @@ +# iterating_over_cell_values.py + +from openpyxl import load_workbook + +def iterating_over_values(path): + workbook = load_workbook(filename=path) + sheet = workbook.active + for value in sheet.iter_rows(min_row=1, max_row=3, + min_col=1, max_col=3, + values_only=True): + print(value) + +if __name__ == '__main__': + iterating_over_values('books.xlsx') \ No newline at end of file diff --git a/chapter38_excel/iterating_over_cells.py b/chapter38_excel/iterating_over_cells.py new file mode 100644 index 0000000..0cdd545 --- /dev/null +++ b/chapter38_excel/iterating_over_cells.py @@ -0,0 +1,12 @@ +# iterating_over_cells.py + +from openpyxl import load_workbook + +def iterating_range(path): + workbook = load_workbook(filename=path) + sheet = workbook.active + for cell in sheet['A']: + print(cell) + +if __name__ == '__main__': + iterating_range('books.xlsx') \ No newline at end of file diff --git a/chapter38_excel/open_workbook.py b/chapter38_excel/open_workbook.py new file mode 100644 index 0000000..8e889d7 --- /dev/null +++ b/chapter38_excel/open_workbook.py @@ -0,0 +1,13 @@ +# open_workbook.py + +from openpyxl import load_workbook + +def open_workbook(path): + workbook = load_workbook(filename=path) + print(f'Worksheet names: {workbook.sheetnames}') + sheet = workbook.active + print(sheet) + print(f'The title of the Worksheet is: {sheet.title}') + +if __name__ == '__main__': + open_workbook('books.xlsx') \ No newline at end of file diff --git a/chapter38_excel/remove_sheets.py b/chapter38_excel/remove_sheets.py new file mode 100644 index 0000000..9dbeb4f --- /dev/null +++ b/chapter38_excel/remove_sheets.py @@ -0,0 +1,17 @@ +# remove_sheets.py + +import openpyxl + +def create_worksheets(path): + workbook = openpyxl.Workbook() + sheet1 = workbook.create_sheet() + # Insert a worksheet + workbook.create_sheet(index=1, + title='Second sheet') + print(workbook.sheetnames) + workbook.remove(workbook['Second sheet']) + print(workbook.sheetnames) + workbook.save(path) + +if __name__ == '__main__': + create_worksheets('remove_sheets.xlsx') \ No newline at end of file diff --git a/chapter38_excel/workbook_cells.py b/chapter38_excel/workbook_cells.py new file mode 100644 index 0000000..82d6668 --- /dev/null +++ b/chapter38_excel/workbook_cells.py @@ -0,0 +1,24 @@ +# workbook_cells.py + +from openpyxl import load_workbook + +def get_cell_info(path): + workbook = load_workbook(filename=path) + sheet = workbook.active + print(sheet) + print(f'The title of the Worksheet is: {sheet.title}') + print(f'The value of {sheet["A2"].value=}') + print(f'The value of {sheet["A3"].value=}') + cell = sheet['B3'] + print(f'{cell.value=}') + +def get_info_by_coord(path): + workbook = load_workbook(filename=path) + sheet = workbook.active + cell = sheet['A2'] + print(f'Row {cell.row}, Col {cell.column} = {cell.value}') + print(f'{cell.value=} is at {cell.coordinate=}') + +if __name__ == '__main__': + get_cell_info('books.xlsx') + get_info_by_coord('books.xlsx') \ No newline at end of file diff --git a/chapter38_excel/writing_hello.py b/chapter38_excel/writing_hello.py new file mode 100644 index 0000000..09be8ec --- /dev/null +++ b/chapter38_excel/writing_hello.py @@ -0,0 +1,14 @@ +# writing_hello.py + +from openpyxl import Workbook + +def create_workbook(path): + workbook = Workbook() + sheet = workbook.active + sheet['A1'] = 'Hello' + sheet['A2'] = 'from' + sheet['A3'] = 'OpenPyXL' + workbook.save(path) + +if __name__ == '__main__': + create_workbook('hello.xlsx') \ No newline at end of file diff --git a/chapter39_reportlab/canvas_form.py b/chapter39_reportlab/canvas_form.py new file mode 100644 index 0000000..f7cc75e --- /dev/null +++ b/chapter39_reportlab/canvas_form.py @@ -0,0 +1,23 @@ +# canvas_form.py + +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen import canvas + +def form(path): + my_canvas = canvas.Canvas(path, pagesize=letter) + my_canvas.setLineWidth(.3) + my_canvas.setFont('Helvetica', 12) + my_canvas.drawString(30, 750, 'OFFICIAL COMMUNIQUE') + my_canvas.drawString(30, 735, 'OF ACME INDUSTRIES') + my_canvas.drawString(500, 750, "12/12/2010") + my_canvas.line(480, 747, 580, 747) + my_canvas.drawString(275, 725, 'AMOUNT OWED:') + my_canvas.drawString(500, 725, "$1,000.00") + my_canvas.line(378, 723, 580, 723) + my_canvas.drawString(30, 703, 'RECEIVED BY:') + my_canvas.line(120, 700, 580, 700) + my_canvas.drawString(120, 703, "JOHN DOE") + my_canvas.save() + +if __name__ == '__main__': + form('canvas_form.pdf') \ No newline at end of file diff --git a/chapter39_reportlab/drawing_polygons.py b/chapter39_reportlab/drawing_polygons.py new file mode 100644 index 0000000..8c838e7 --- /dev/null +++ b/chapter39_reportlab/drawing_polygons.py @@ -0,0 +1,16 @@ +# drawing_polygons.py + +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen import canvas + +def draw_shapes(): + my_canvas = canvas.Canvas("drawing_polygons.pdf") + my_canvas.setStrokeColorRGB(0.2, 0.5, 0.3) + my_canvas.rect(10, 740, 100, 80, stroke=1, fill=0) + my_canvas.ellipse(10, 680, 100, 630, stroke=1, fill=1) + my_canvas.wedge(10, 600, 100, 550, 45, 90, stroke=1, fill=0) + my_canvas.circle(300, 600, 50) + my_canvas.save() + +if __name__ == '__main__': + draw_shapes() \ No newline at end of file diff --git a/chapter39_reportlab/hello_platypus.py b/chapter39_reportlab/hello_platypus.py new file mode 100644 index 0000000..7e29ee4 --- /dev/null +++ b/chapter39_reportlab/hello_platypus.py @@ -0,0 +1,25 @@ +# hello_platypus.py + +from reportlab.lib.pagesizes import letter +from reportlab.platypus import SimpleDocTemplate, Paragraph +from reportlab.lib.styles import getSampleStyleSheet + +def hello(): + doc = SimpleDocTemplate("hello_platypus.pdf", + pagesize=letter, + rightMargin=72, + leftMargin=72, + topMargin=72, + bottomMargin=18) + styles = getSampleStyleSheet() + + flowables = [] + + text = "Hello, I'm a Paragraph" + para = Paragraph(text, style=styles["Normal"]) + flowables.append(para) + + doc.build(flowables) + +if __name__ == '__main__': + hello() \ No newline at end of file diff --git a/chapter39_reportlab/hello_reportlab.py b/chapter39_reportlab/hello_reportlab.py new file mode 100644 index 0000000..f1d75f9 --- /dev/null +++ b/chapter39_reportlab/hello_reportlab.py @@ -0,0 +1,7 @@ +# hello_reportlab.py + +from reportlab.pdfgen import canvas + +my_canvas = canvas.Canvas("hello.pdf") +my_canvas.drawString(100, 750, "Welcome to Reportlab!") +my_canvas.save() \ No newline at end of file diff --git a/chapter39_reportlab/image_on_canvas.py b/chapter39_reportlab/image_on_canvas.py new file mode 100644 index 0000000..8be2a08 --- /dev/null +++ b/chapter39_reportlab/image_on_canvas.py @@ -0,0 +1,16 @@ +# image_on_canvas.py + +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen import canvas + + +def add_image(image_path): + my_canvas = canvas.Canvas("canvas_image.pdf", + pagesize=letter) + my_canvas.drawImage(image_path, 30, 600, + width=100, height=100) + my_canvas.save() + +if __name__ == '__main__': + image_path = 'snakehead.jpg' + add_image(image_path) \ No newline at end of file diff --git a/chapter39_reportlab/platypus_multipage.py b/chapter39_reportlab/platypus_multipage.py new file mode 100644 index 0000000..9a0fe76 --- /dev/null +++ b/chapter39_reportlab/platypus_multipage.py @@ -0,0 +1,26 @@ +# platypus_multipage.py + +from reportlab.lib.pagesizes import letter +from reportlab.lib.styles import getSampleStyleSheet +from reportlab.lib.units import inch +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer + + +def create_document(): + doc = SimpleDocTemplate("platypus_multipage.pdf", + pagesize=letter) + styles = getSampleStyleSheet() + flowables = [] + spacer = Spacer(1, 0.25*inch) + + # Create a lot of content to make a multipage PDF + for i in range(50): + text = 'Paragraph #{}'.format(i) + para = Paragraph(text, styles["Normal"]) + flowables.append(para) + flowables.append(spacer) + + doc.build(flowables) + +if __name__ == '__main__': + create_document() \ No newline at end of file diff --git a/chapter39_reportlab/simple_table.py b/chapter39_reportlab/simple_table.py new file mode 100644 index 0000000..19c201d --- /dev/null +++ b/chapter39_reportlab/simple_table.py @@ -0,0 +1,21 @@ +# simple_table.py + +from reportlab.lib.pagesizes import letter +from reportlab.platypus import SimpleDocTemplate, Table + +def simple_table(): + doc = SimpleDocTemplate("simple_table.pdf", pagesize=letter) + flowables = [] + + data = [['col_{}'.format(x) for x in range(1, 6)], + [str(x) for x in range(1, 6)], + ['a', 'b', 'c', 'd', 'e'] + ] + + tbl = Table(data) + flowables.append(tbl) + + doc.build(flowables) + +if __name__ == '__main__': + simple_table() \ No newline at end of file diff --git a/chapter39_reportlab/simple_table_with_style.py b/chapter39_reportlab/simple_table_with_style.py new file mode 100644 index 0000000..db47c7e --- /dev/null +++ b/chapter39_reportlab/simple_table_with_style.py @@ -0,0 +1,29 @@ +# simple_table_with_style.py + +from reportlab.lib import colors +from reportlab.lib.pagesizes import letter +from reportlab.platypus import SimpleDocTemplate, Table, TableStyle + +def simple_table_with_style(): + doc = SimpleDocTemplate("simple_table_with_style.pdf", + pagesize=letter) + flowables = [] + + data = [['col_{}'.format(x) for x in range(1, 6)], + [str(x) for x in range(1, 6)], + ['a', 'b', 'c', 'd', 'e'] + ] + + tblstyle = TableStyle( + [('BACKGROUND', (0, 0), (-1, 0), colors.red), + ('TEXTCOLOR', (0, 1), (-1, 1), colors.blue) + ]) + + tbl = Table(data) + tbl.setStyle(tblstyle) + flowables.append(tbl) + + doc.build(flowables) + +if __name__ == '__main__': + simple_table_with_style() \ No newline at end of file diff --git a/chapter39_reportlab/snakehead.jpg b/chapter39_reportlab/snakehead.jpg new file mode 100644 index 0000000..db89582 Binary files /dev/null and b/chapter39_reportlab/snakehead.jpg differ diff --git a/chapter40_graphs/bar_chart.py b/chapter40_graphs/bar_chart.py new file mode 100644 index 0000000..11808f3 --- /dev/null +++ b/chapter40_graphs/bar_chart.py @@ -0,0 +1,14 @@ +# bar_chart.py + +import matplotlib.pyplot as plt + +def bar_chart(numbers, labels, pos): + plt.bar(pos, numbers, color='blue') + plt.xticks(ticks=pos, labels=labels) + plt.show() + +if __name__ == '__main__': + numbers = [2, 1, 4, 6] + labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] + pos = list(range(4)) + bar_chart(numbers, labels, pos) \ No newline at end of file diff --git a/chapter40_graphs/bar_chart.title.py b/chapter40_graphs/bar_chart.title.py new file mode 100644 index 0000000..a68a7b9 --- /dev/null +++ b/chapter40_graphs/bar_chart.title.py @@ -0,0 +1,18 @@ +# bar_chart_title.py + +import matplotlib.pyplot as plt + +def bar_chart(numbers, labels, pos): + plt.bar(pos, [4, 5, 6, 3], color='green') + plt.bar(pos, numbers, color='blue') + plt.xticks(ticks=pos, labels=labels) + plt.title('Gas Used in Various Vehicles') + plt.xlabel('Vehicle Types') + plt.ylabel('Number of Vehicles') + plt.show() + +if __name__ == '__main__': + numbers = [2, 1, 4, 6] + labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] + pos = list(range(4)) + bar_chart(numbers, labels, pos) \ No newline at end of file diff --git a/chapter40_graphs/bar_chart_labels.py b/chapter40_graphs/bar_chart_labels.py new file mode 100644 index 0000000..2625f0f --- /dev/null +++ b/chapter40_graphs/bar_chart_labels.py @@ -0,0 +1,16 @@ +# bar_chart_labels.py + +import matplotlib.pyplot as plt + +def bar_chart(numbers, labels, pos): + plt.bar(pos, numbers, color='blue') + plt.xticks(ticks=pos, labels=labels) + plt.xlabel('Vehicle Types') + plt.ylabel('Number of Vehicles') + plt.show() + +if __name__ == '__main__': + numbers = [2, 1, 4, 6] + labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] + pos = list(range(4)) + bar_chart(numbers, labels, pos) \ No newline at end of file diff --git a/chapter40_graphs/bar_chart_legend.py b/chapter40_graphs/bar_chart_legend.py new file mode 100644 index 0000000..049be31 --- /dev/null +++ b/chapter40_graphs/bar_chart_legend.py @@ -0,0 +1,20 @@ +# bar_chart_legend.py + +import matplotlib.pyplot as plt + +def bar_chart(numbers, labels, pos): + plt.bar(pos, [4, 5, 6, 3], color='green') + plt.bar(pos, numbers, color='blue') + plt.xticks(ticks=pos, labels=labels) + plt.xlabel('Vehicle Types') + plt.ylabel('Number of Vehicles') + plt.title('Gas Used in Various Vehicles') + plt.legend(['First Label', 'Second Label'], + loc='upper left') + plt.show() + +if __name__ == '__main__': + numbers = [2, 1, 4, 6] + labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] + pos = list(range(4)) + bar_chart(numbers, labels, pos) \ No newline at end of file diff --git a/chapter40_graphs/bar_charth.py b/chapter40_graphs/bar_charth.py new file mode 100644 index 0000000..cdd2763 --- /dev/null +++ b/chapter40_graphs/bar_charth.py @@ -0,0 +1,14 @@ +# bar_charth.py + +import matplotlib.pyplot as plt + +def bar_charth(numbers, labels, pos): + plt.barh(pos, numbers, color='blue') + plt.yticks(ticks=pos, labels=labels) + plt.show() + +if __name__ == '__main__': + numbers = [2, 1, 4, 6] + labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] + pos = list(range(4)) + bar_charth(numbers, labels, pos) \ No newline at end of file diff --git a/chapter40_graphs/line_plot.py b/chapter40_graphs/line_plot.py new file mode 100644 index 0000000..03b7dd5 --- /dev/null +++ b/chapter40_graphs/line_plot.py @@ -0,0 +1,12 @@ +# line_plot.py + +import matplotlib.pyplot as plt + +def line_plot(numbers): + plt.plot(numbers) + plt.ylabel('Random numbers') + plt.show() + +if __name__ == '__main__': + numbers = [2, 4, 1, 6] + line_plot(numbers) \ No newline at end of file diff --git a/chapter40_graphs/multiple_figures.py b/chapter40_graphs/multiple_figures.py new file mode 100644 index 0000000..ea4bf17 --- /dev/null +++ b/chapter40_graphs/multiple_figures.py @@ -0,0 +1,16 @@ +# multiple_figures.py + +import matplotlib.pyplot as plt + +def line_plot(numbers, numbers2): + first_plot = plt.figure(1) + plt.plot(numbers) + + second_plot = plt.figure(2) + plt.plot(numbers2) + plt.show() + +if __name__ == '__main__': + numbers = [2, 4, 1, 6] + more_numbers = [5, 1, 10, 3] + line_plot(numbers, more_numbers) \ No newline at end of file diff --git a/chapter40_graphs/multiple_plots.py b/chapter40_graphs/multiple_plots.py new file mode 100644 index 0000000..1b9b9af --- /dev/null +++ b/chapter40_graphs/multiple_plots.py @@ -0,0 +1,18 @@ +# multiple_plots.py + +import matplotlib.pyplot as plt +import numpy as np + +def multiple_plots(): + # Some example data to display + x = np.linspace(0, 2 * np.pi, 400) + y = np.sin(x ** 2) + + fig, axs = plt.subplots(2) + fig.suptitle('Vertically stacked subplots') + axs[0].plot(x, y) + axs[1].plot(x, -y) + plt.show() + +if __name__ == '__main__': + multiple_plots() \ No newline at end of file diff --git a/chapter40_graphs/multiple_plots2.py b/chapter40_graphs/multiple_plots2.py new file mode 100644 index 0000000..f0487cf --- /dev/null +++ b/chapter40_graphs/multiple_plots2.py @@ -0,0 +1,15 @@ +# multiple_plots2.py + +import matplotlib.pyplot as plt + +def multiple_plots(): + numbers = [2, 4, 1, 6] + more_numbers = [5, 1, 10, 3] + fig, axs = plt.subplots(2) + fig.suptitle('Vertically stacked subplots') + axs[0].plot(numbers) + axs[1].plot(more_numbers) + plt.show() + +if __name__ == '__main__': + multiple_plots() \ No newline at end of file diff --git a/chapter40_graphs/pie_chart_fancy.py b/chapter40_graphs/pie_chart_fancy.py new file mode 100644 index 0000000..fef5f86 --- /dev/null +++ b/chapter40_graphs/pie_chart_fancy.py @@ -0,0 +1,19 @@ +# pie_chart.py + +import matplotlib.pyplot as plt + +def pie_chart(): + numbers = [40, 35, 15, 10] + labels = ['Python', 'Ruby', 'C++', 'PHP'] + # Explode the first slice (Python) + explode = (0.1, 0, 0, 0) + + fig1, ax1 = plt.subplots() + ax1.pie(numbers, explode=explode, labels=labels, + shadow=True, startangle=90, + autopct='%1.1f%%') + ax1.axis('equal') + plt.show() + +if __name__ == '__main__': + pie_chart() \ No newline at end of file diff --git a/chapter40_graphs/pie_chart_plain.py b/chapter40_graphs/pie_chart_plain.py new file mode 100644 index 0000000..d28980c --- /dev/null +++ b/chapter40_graphs/pie_chart_plain.py @@ -0,0 +1,14 @@ +# pie_chart_plain.py + +import matplotlib.pyplot as plt + +def pie_chart(): + numbers = [40, 35, 15, 10] + labels = ['Python', 'Ruby', 'C++', 'PHP'] + + fig1, ax1 = plt.subplots() + ax1.pie(numbers, labels=labels) + plt.show() + +if __name__ == '__main__': + pie_chart() \ No newline at end of file diff --git a/chapter41_images/blur.py b/chapter41_images/blur.py new file mode 100644 index 0000000..4dff2cf --- /dev/null +++ b/chapter41_images/blur.py @@ -0,0 +1,13 @@ +# blur.py + +from PIL import Image +from PIL import ImageFilter + + +def blur(path, modified_photo): + image = Image.open(path) + blurred_image = image.filter(ImageFilter.BLUR) + blurred_image.save(modified_photo) + +if __name__ == '__main__': + blur('butterfly.jpg', 'butterfly_blurred.jpg') \ No newline at end of file diff --git a/chapter41_images/border.py b/chapter41_images/border.py new file mode 100644 index 0000000..675d3ff --- /dev/null +++ b/chapter41_images/border.py @@ -0,0 +1,20 @@ +# border.py + +from PIL import Image, ImageOps + + +def add_border(input_image, output_image, border): + img = Image.open(input_image) + + if isinstance(border, int) or isinstance(border, tuple): + bimg = ImageOps.expand(img, border=border) + else: + raise RuntimeError('Border is not an integer or tuple!') + + bimg.save(output_image) + +if __name__ == '__main__': + in_img = 'butterfly_grey.jpg' + + add_border(in_img, output_image='butterfly_border.jpg', + border=100) diff --git a/chapter41_images/border2.py b/chapter41_images/border2.py new file mode 100644 index 0000000..671cbd1 --- /dev/null +++ b/chapter41_images/border2.py @@ -0,0 +1,20 @@ +# border2.py + +from PIL import Image, ImageOps + + +def add_border(input_image, output_image, border): + img = Image.open(input_image) + + if isinstance(border, int) or isinstance(border, tuple): + bimg = ImageOps.expand(img, border=border) + else: + raise RuntimeError('Border is not an integer or tuple!') + + bimg.save(output_image) + +if __name__ == '__main__': + in_img = 'butterfly_grey.jpg' + + add_border(in_img, output_image='butterfly_border2.jpg', + border=(10, 50)) diff --git a/chapter41_images/butterfly.jpg b/chapter41_images/butterfly.jpg new file mode 100644 index 0000000..9750c31 Binary files /dev/null and b/chapter41_images/butterfly.jpg differ diff --git a/chapter41_images/butterfly_grey.jpg b/chapter41_images/butterfly_grey.jpg new file mode 100644 index 0000000..f416524 Binary files /dev/null and b/chapter41_images/butterfly_grey.jpg differ diff --git a/chapter41_images/colored_border.py b/chapter41_images/colored_border.py new file mode 100644 index 0000000..2c2d37a --- /dev/null +++ b/chapter41_images/colored_border.py @@ -0,0 +1,25 @@ +# colored_border.py + +from PIL import Image, ImageOps + +def add_border(input_image, output_image, border, color=0): + img = Image.open(input_image) + + if isinstance(border, int) or isinstance( + border, tuple): + bimg = ImageOps.expand(img, + border=border, + fill=color) + else: + msg = 'Border is not an integer or tuple!' + raise RuntimeError(msg) + + bimg.save(output_image) + +if __name__ == '__main__': + in_img = 'butterfly_grey.jpg' + + add_border(in_img, + output_image='butterfly_border_red.jpg', + border=100, + color='indianred') \ No newline at end of file diff --git a/chapter41_images/cropping.py b/chapter41_images/cropping.py new file mode 100644 index 0000000..7eb5883 --- /dev/null +++ b/chapter41_images/cropping.py @@ -0,0 +1,12 @@ +# cropping.py + +from PIL import Image + + +def crop_image(path, cropped_path): + image = Image.open(path) + cropped = image.crop((40, 590, 979, 1500)) + cropped.save(cropped_path) + +if __name__ == '__main__': + crop_image('ducks.jpg', 'ducks_cropped.jpg') \ No newline at end of file diff --git a/chapter41_images/ducks.jpg b/chapter41_images/ducks.jpg new file mode 100644 index 0000000..86837a1 Binary files /dev/null and b/chapter41_images/ducks.jpg differ diff --git a/chapter41_images/get_histogram.py b/chapter41_images/get_histogram.py new file mode 100644 index 0000000..32964ab --- /dev/null +++ b/chapter41_images/get_histogram.py @@ -0,0 +1,16 @@ +# get_histrogram.py + +import matplotlib.pyplot as plt + +from PIL import Image + + +def get_image_histrogram(path): + image = Image.open(path) + histogram = image.histogram() + plt.hist(histogram, bins=len(histogram)) + plt.xlabel('Histogram') + plt.show() + +if __name__ == '__main__': + get_image_histrogram('butterfly.jpg') \ No newline at end of file diff --git a/chapter41_images/get_image_info.py b/chapter41_images/get_image_info.py new file mode 100644 index 0000000..1b6736f --- /dev/null +++ b/chapter41_images/get_image_info.py @@ -0,0 +1,12 @@ +# get_image_info.py + +from PIL import Image + +def get_image_info(path): + image = Image.open(path) + print(f'This image is {image.width} x {image.height}') + exif = image._getexif() + print(exif) + +if __name__ == '__main__': + get_image_info('ducks.jpg') \ No newline at end of file diff --git a/chapter41_images/jellyfish.jpg b/chapter41_images/jellyfish.jpg new file mode 100644 index 0000000..3cee85e Binary files /dev/null and b/chapter41_images/jellyfish.jpg differ diff --git a/chapter41_images/lizard.jpg b/chapter41_images/lizard.jpg new file mode 100644 index 0000000..535baf8 Binary files /dev/null and b/chapter41_images/lizard.jpg differ diff --git a/chapter41_images/open_image.py b/chapter41_images/open_image.py new file mode 100644 index 0000000..3459f7c --- /dev/null +++ b/chapter41_images/open_image.py @@ -0,0 +1,6 @@ +# open_image.py + +from PIL import Image + +image = Image.open('jellyfish.jpg') +image.show() \ No newline at end of file diff --git a/chapter41_images/resize_image.py b/chapter41_images/resize_image.py new file mode 100644 index 0000000..bec9953 --- /dev/null +++ b/chapter41_images/resize_image.py @@ -0,0 +1,23 @@ +# resize_image.py + +from PIL import Image + +def resize_image(input_image_path, + output_image_path, + size): + original_image = Image.open(input_image_path) + width, height = original_image.size + print(f'The original image size is {width} wide x {height} ' + f'high') + + resized_image = original_image.resize(size) + width, height = resized_image.size + print(f'The resized image size is {width} wide x {height} ' + f'high') + resized_image.show() + resized_image.save(output_image_path) + +if __name__ == '__main__': + resize_image(input_image_path='lizard.jpg', + output_image_path='lizard_small.jpg', + size=(800, 400)) \ No newline at end of file diff --git a/chapter41_images/scale_image.py b/chapter41_images/scale_image.py new file mode 100644 index 0000000..aa2febc --- /dev/null +++ b/chapter41_images/scale_image.py @@ -0,0 +1,37 @@ +# scale_image.py + +from PIL import Image + +def scale_image(input_image_path, + output_image_path, + width=None, + height=None + ): + original_image = Image.open(input_image_path) + w, h = original_image.size + print(f'The original image size is {w} wide x {h} ' + 'high') + + if width and height: + max_size = (width, height) + elif width: + max_size = (width, h) + elif height: + max_size = (w, height) + else: + # No width or height specified + raise ValueError('Width or height required!') + + original_image.thumbnail(max_size, Image.ANTIALIAS) + original_image.save(output_image_path) + + scaled_image = Image.open(output_image_path) + width, height = scaled_image.size + print(f'The scaled image size is {width} wide x {height} ' + 'high') + + +if __name__ == '__main__': + scale_image(input_image_path='lizard.jpg', + output_image_path='lizard_scaled.jpg', + width=800) \ No newline at end of file diff --git a/chapter41_images/sharpen.py b/chapter41_images/sharpen.py new file mode 100644 index 0000000..494b0fa --- /dev/null +++ b/chapter41_images/sharpen.py @@ -0,0 +1,13 @@ +# sharpen.py + +from PIL import Image +from PIL import ImageFilter + + +def sharpen(path, modified_photo): + image = Image.open(path) + sharpened_image = image.filter(ImageFilter.SHARPEN) + sharpened_image.save(modified_photo) + +if __name__ == '__main__': + sharpen('butterfly.jpg', 'butterfly_sharper.jpg') \ No newline at end of file diff --git a/chapter42_gui/button_events.py b/chapter42_gui/button_events.py new file mode 100644 index 0000000..b282fab --- /dev/null +++ b/chapter42_gui/button_events.py @@ -0,0 +1,41 @@ +# button_events.py + +import wx + + +class MyPanel(wx.Panel): + + def __init__(self, parent): + super().__init__(parent) + + button = wx.Button(self, label='Press Me') + button.Bind(wx.EVT_BUTTON, self.on_button1) + button2 = wx.Button(self, label='Second button') + button2.Bind(wx.EVT_BUTTON, self.on_button2) + + main_sizer = wx.BoxSizer(wx.HORIZONTAL) + main_sizer.Add(button, proportion=1, + flag=wx.ALL | wx.CENTER | wx.EXPAND, + border=5) + main_sizer.Add(button2, 0, wx.ALL, 5) + self.SetSizer(main_sizer) + + def on_button1(self, event): + print('You clicked the first button') + + def on_button2(self, event): + print('You clicked the second button') + + +class MyFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Hello World') + panel = MyPanel(self) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MyFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter42_gui/hello_with_panel.py b/chapter42_gui/hello_with_panel.py new file mode 100644 index 0000000..f6bb3e8 --- /dev/null +++ b/chapter42_gui/hello_with_panel.py @@ -0,0 +1,23 @@ +# hello_with_panel.py + +import wx + + +class MyPanel(wx.Panel): + + def __init__(self, parent): + super().__init__(parent) + button = wx.Button(self, label='Press Me') + +class MyFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Hello World') + panel = MyPanel(self) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MyFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter42_gui/hello_wx.py b/chapter42_gui/hello_wx.py new file mode 100644 index 0000000..7dfe858 --- /dev/null +++ b/chapter42_gui/hello_wx.py @@ -0,0 +1,8 @@ +# hello_wx.py + +import wx + +app = wx.App(False) +frame = wx.Frame(parent=None, title='Hello World') +frame.Show() +app.MainLoop() diff --git a/chapter42_gui/hello_wx_class.py b/chapter42_gui/hello_wx_class.py new file mode 100644 index 0000000..7a23617 --- /dev/null +++ b/chapter42_gui/hello_wx_class.py @@ -0,0 +1,15 @@ +# hello_wx_class.py + +import wx + +class MyFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Hello World') + self.Show() + +if __name__ == '__main__': + app = wx.App(False) + frame = MyFrame() + frame.Show() + app.MainLoop() diff --git a/chapter42_gui/image_viewer.py b/chapter42_gui/image_viewer.py new file mode 100644 index 0000000..38dd872 --- /dev/null +++ b/chapter42_gui/image_viewer.py @@ -0,0 +1,34 @@ +# image_viewer.py + +import wx + +class ImagePanel(wx.Panel): + + def __init__(self, parent, image_size): + super().__init__(parent) + + img = wx.Image(*image_size) + self.image_ctrl = wx.StaticBitmap(self, + bitmap=wx.Bitmap(img)) + browse_btn = wx.Button(self, label='Browse') + + main_sizer = wx.BoxSizer(wx.VERTICAL) + main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5) + main_sizer.Add(browse_btn) + self.SetSizer(main_sizer) + main_sizer.Fit(parent) + self.Layout() + + +class MainFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Image Viewer') + panel = ImagePanel(self, image_size=(240,240)) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MainFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter42_gui/image_viewer_working.py b/chapter42_gui/image_viewer_working.py new file mode 100644 index 0000000..3abd01f --- /dev/null +++ b/chapter42_gui/image_viewer_working.py @@ -0,0 +1,78 @@ +# image_viewer_working.py + +import wx + +class ImagePanel(wx.Panel): + + def __init__(self, parent, image_size): + super().__init__(parent) + self.max_size = 240 + + img = wx.Image(*image_size) + self.image_ctrl = wx.StaticBitmap(self, + bitmap=wx.Bitmap(img)) + + browse_btn = wx.Button(self, label='Browse') + browse_btn.Bind(wx.EVT_BUTTON, self.on_browse) + + self.photo_txt = wx.TextCtrl(self, size=(200, -1)) + + main_sizer = wx.BoxSizer(wx.VERTICAL) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + + main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5) + hsizer.Add(browse_btn, 0, wx.ALL, 5) + hsizer.Add(self.photo_txt, 0, wx.ALL, 5) + main_sizer.Add(hsizer, 0, wx.ALL, 5) + + self.SetSizer(main_sizer) + main_sizer.Fit(parent) + self.Layout() + + def on_browse(self, event): + """ + Browse for an image file + @param event: The event object + """ + wildcard = "JPEG files (*.jpg)|*.jpg" + with wx.FileDialog(None, "Choose a file", + wildcard=wildcard, + style=wx.ID_OPEN) as dialog: + if dialog.ShowModal() == wx.ID_OK: + self.photo_txt.SetValue(dialog.GetPaths()[0]) + self.load_image() + + def load_image(self): + """ + Load the image and display it to the user + """ + filepath = self.photo_txt.GetValue() + img = wx.Image(filepath, wx.BITMAP_TYPE_ANY) + + # scale the image, preserving the aspect ratio + W = img.GetWidth() + H = img.GetHeight() + if W > H: + NewW = self.max_size + NewH = self.max_size * H / W + else: + NewH = self.max_size + NewW = self.max_size * W / H + img = img.Scale(NewW,NewH) + + self.image_ctrl.SetBitmap(wx.Bitmap(img)) + self.Refresh() + + +class MainFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Image Viewer') + panel = ImagePanel(self, image_size=(240,240)) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MainFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter42_gui/sizer_with_two_widgets.py b/chapter42_gui/sizer_with_two_widgets.py new file mode 100644 index 0000000..f69c706 --- /dev/null +++ b/chapter42_gui/sizer_with_two_widgets.py @@ -0,0 +1,33 @@ +# sizer_with_two_widgets.py + +import wx + + +class MyPanel(wx.Panel): + + def __init__(self, parent): + super().__init__(parent) + + button = wx.Button(self, label='Press Me') + button2 = wx.Button(self, label='Second button') + + main_sizer = wx.BoxSizer(wx.HORIZONTAL) + main_sizer.Add(button, proportion=1, + flag=wx.ALL | wx.CENTER | wx.EXPAND, + border=5) + main_sizer.Add(button2, 0, wx.ALL, 5) + self.SetSizer(main_sizer) + + +class MyFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Hello World') + panel = MyPanel(self) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MyFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter42_gui/stacked_buttons.py b/chapter42_gui/stacked_buttons.py new file mode 100644 index 0000000..f8ce7de --- /dev/null +++ b/chapter42_gui/stacked_buttons.py @@ -0,0 +1,25 @@ +# stacked_buttons.py + +import wx + + +class MyPanel(wx.Panel): + + def __init__(self, parent): + super().__init__(parent) + button = wx.Button(self, label='Press Me') + button2 = wx.Button(self, label='Press Me too') + button3 = wx.Button(self, label='Another button') + +class MyFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Hello World') + panel = MyPanel(self) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MyFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter43_packages/arithmetic/__init__.py b/chapter43_packages/arithmetic/__init__.py new file mode 100644 index 0000000..be3c5fc --- /dev/null +++ b/chapter43_packages/arithmetic/__init__.py @@ -0,0 +1,2 @@ +# __init__.py +from . import add \ No newline at end of file diff --git a/chapter43_packages/arithmetic/add.py b/chapter43_packages/arithmetic/add.py new file mode 100644 index 0000000..07fb1d6 --- /dev/null +++ b/chapter43_packages/arithmetic/add.py @@ -0,0 +1,4 @@ +# add.py + +def add(x, y): + return x + y \ No newline at end of file diff --git a/chapter43_packages/arithmetic/divide.py b/chapter43_packages/arithmetic/divide.py new file mode 100644 index 0000000..1f6707b --- /dev/null +++ b/chapter43_packages/arithmetic/divide.py @@ -0,0 +1,4 @@ +# divide.py + +def divide(x, y): + return x / y \ No newline at end of file diff --git a/chapter43_packages/arithmetic/multiply.py b/chapter43_packages/arithmetic/multiply.py new file mode 100644 index 0000000..0a4dcbc --- /dev/null +++ b/chapter43_packages/arithmetic/multiply.py @@ -0,0 +1,4 @@ +# multiply.py + +def multiply(x, y): + return x * y \ No newline at end of file diff --git a/chapter43_packages/arithmetic/subtract.py b/chapter43_packages/arithmetic/subtract.py new file mode 100644 index 0000000..f9340ac --- /dev/null +++ b/chapter43_packages/arithmetic/subtract.py @@ -0,0 +1,4 @@ +# subtract.py + +def subtract(x, y): + return x - y \ No newline at end of file diff --git a/chapter43_packages/module/arithmetic.py b/chapter43_packages/module/arithmetic.py new file mode 100644 index 0000000..f49c8db --- /dev/null +++ b/chapter43_packages/module/arithmetic.py @@ -0,0 +1,13 @@ +# arithmetic.py + +def add(x, y): + return x + y + +def divide(x, y): + return x / y + +def multiply(x, y): + return x * y + +def subtract(x, y): + return x - y diff --git a/chapter43_packages/module/test_arithmetic.py b/chapter43_packages/module/test_arithmetic.py new file mode 100644 index 0000000..f259dcf --- /dev/null +++ b/chapter43_packages/module/test_arithmetic.py @@ -0,0 +1,22 @@ +# test_arithmetic.py + +import arithmetic +import unittest + +class TestArithmetic(unittest.TestCase): + + def test_addition(self): + self.assertEqual(arithmetic.add(1, 2), 3) + + def test_subtraction(self): + self.assertEqual(arithmetic.subtract(2, 1), 1) + + def test_multiplication(self): + self.assertEqual(arithmetic.multiply(5, 5), 25) + + def test_division(self): + self.assertEqual(arithmetic.divide(8, 2), 4) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/chapter43_packages/my_package/LICENSE b/chapter43_packages/my_package/LICENSE new file mode 100644 index 0000000..153d416 --- /dev/null +++ b/chapter43_packages/my_package/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/chapter43_packages/my_package/README.md b/chapter43_packages/my_package/README.md new file mode 100644 index 0000000..e69de29 diff --git a/chapter43_packages/my_package/arithmetic/__init__.py b/chapter43_packages/my_package/arithmetic/__init__.py new file mode 100644 index 0000000..be3c5fc --- /dev/null +++ b/chapter43_packages/my_package/arithmetic/__init__.py @@ -0,0 +1,2 @@ +# __init__.py +from . import add \ No newline at end of file diff --git a/chapter43_packages/my_package/arithmetic/add.py b/chapter43_packages/my_package/arithmetic/add.py new file mode 100644 index 0000000..07fb1d6 --- /dev/null +++ b/chapter43_packages/my_package/arithmetic/add.py @@ -0,0 +1,4 @@ +# add.py + +def add(x, y): + return x + y \ No newline at end of file diff --git a/chapter43_packages/my_package/arithmetic/divide.py b/chapter43_packages/my_package/arithmetic/divide.py new file mode 100644 index 0000000..1f6707b --- /dev/null +++ b/chapter43_packages/my_package/arithmetic/divide.py @@ -0,0 +1,4 @@ +# divide.py + +def divide(x, y): + return x / y \ No newline at end of file diff --git a/chapter43_packages/my_package/arithmetic/multiply.py b/chapter43_packages/my_package/arithmetic/multiply.py new file mode 100644 index 0000000..0a4dcbc --- /dev/null +++ b/chapter43_packages/my_package/arithmetic/multiply.py @@ -0,0 +1,4 @@ +# multiply.py + +def multiply(x, y): + return x * y \ No newline at end of file diff --git a/chapter43_packages/my_package/arithmetic/subtract.py b/chapter43_packages/my_package/arithmetic/subtract.py new file mode 100644 index 0000000..f9340ac --- /dev/null +++ b/chapter43_packages/my_package/arithmetic/subtract.py @@ -0,0 +1,4 @@ +# subtract.py + +def subtract(x, y): + return x - y \ No newline at end of file diff --git a/chapter43_packages/my_package/setup.py b/chapter43_packages/my_package/setup.py new file mode 100644 index 0000000..4684c74 --- /dev/null +++ b/chapter43_packages/my_package/setup.py @@ -0,0 +1,22 @@ +import setuptools + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="arithmetic-YOUR-USERNAME-HERE", # Replace with your own username + version="0.0.1", + author="Mike Driscoll", + author_email="driscoll@example.com", + description="A simple arithmetic package", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/driscollis/arithmetic", + packages=setuptools.find_packages(), + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + python_requires='>=3.6', +) \ No newline at end of file diff --git a/chapter44_pyinstaller/image_viewer.py b/chapter44_pyinstaller/image_viewer.py new file mode 100644 index 0000000..8e4dec4 --- /dev/null +++ b/chapter44_pyinstaller/image_viewer.py @@ -0,0 +1,78 @@ +# image_viewer_working.py + +import wx + +class ImagePanel(wx.Panel): + + def __init__(self, parent, image_size): + super().__init__(parent) + self.max_size = 240 + + img = wx.Image(*image_size) + self.image_ctrl = wx.StaticBitmap(self, + bitmap=wx.Bitmap(img)) + + browse_btn = wx.Button(self, label='Browse') + browse_btn.Bind(wx.EVT_BUTTON, self.on_browse) + + self.photo_txt = wx.TextCtrl(self, size=(200, -1)) + + main_sizer = wx.BoxSizer(wx.VERTICAL) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + + main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5) + hsizer.Add(browse_btn, 0, wx.ALL, 5) + hsizer.Add(self.photo_txt, 0, wx.ALL, 5) + main_sizer.Add(hsizer, 0, wx.ALL, 5) + + self.SetSizer(main_sizer) + main_sizer.Fit(parent) + self.Layout() + + def on_browse(self, event): + """ + Browse for an image file + @param event: The event object + """ + wildcard = "JPEG files (*.jpg)|*.jpg" + with wx.FileDialog(None, "Choose a file", + wildcard=wildcard, + style=wx.ID_OPEN) as dialog: + if dialog.ShowModal() == wx.ID_OK: + self.photo_txt.SetValue(dialog.GetPath()) + self.load_image() + + def load_image(self): + """ + Load the image and display it to the user + """ + filepath = self.photo_txt.GetValue() + img = wx.Image(filepath, wx.BITMAP_TYPE_ANY) + + # scale the image, preserving the aspect ratio + W = img.GetWidth() + H = img.GetHeight() + if W > H: + NewW = self.max_size + NewH = self.max_size * H / W + else: + NewH = self.max_size + NewW = self.max_size * W / H + img = img.Scale(NewW,NewH) + + self.image_ctrl.SetBitmap(wx.Bitmap(img)) + self.Refresh() + + +class MainFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Image Viewer') + panel = ImagePanel(self, image_size=(240,240)) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MainFrame() + app.MainLoop() \ No newline at end of file diff --git a/chapter44_pyinstaller/pysearch.py b/chapter44_pyinstaller/pysearch.py new file mode 100644 index 0000000..9a2e0cc --- /dev/null +++ b/chapter44_pyinstaller/pysearch.py @@ -0,0 +1,49 @@ +# pysearch.py + +import argparse +import pathlib + + +def search_folder(path, extension, file_size=None): + """ + Search folder for files + """ + folder = pathlib.Path(path) + files = list(folder.rglob(f'*.{extension}')) + + if not files: + print(f'No files found with {extension=}') + return + + if file_size is not None: + files = [f for f in files + if f.stat().st_size > file_size] + + print(f'{len(files)} *.{extension} files found:') + for file_path in files: + print(file_path) + + +def main(): + parser = argparse.ArgumentParser( + 'PySearch', + description='PySearch - The Python Powered File Searcher') + parser.add_argument('-p', '--path', + help='The path to search for files', + required=True, + dest='path') + parser.add_argument('-e', '--ext', + help='The extension to search for', + required=True, + dest='extension') + parser.add_argument('-s', '--size', + help='The file size to filter on in bytes', + type=int, + dest='size', + default=None) + + args = parser.parse_args() + search_folder(args.path, args.extension, args.size) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/chapter46_mac/image_viewer.py b/chapter46_mac/image_viewer.py new file mode 100644 index 0000000..8e4dec4 --- /dev/null +++ b/chapter46_mac/image_viewer.py @@ -0,0 +1,78 @@ +# image_viewer_working.py + +import wx + +class ImagePanel(wx.Panel): + + def __init__(self, parent, image_size): + super().__init__(parent) + self.max_size = 240 + + img = wx.Image(*image_size) + self.image_ctrl = wx.StaticBitmap(self, + bitmap=wx.Bitmap(img)) + + browse_btn = wx.Button(self, label='Browse') + browse_btn.Bind(wx.EVT_BUTTON, self.on_browse) + + self.photo_txt = wx.TextCtrl(self, size=(200, -1)) + + main_sizer = wx.BoxSizer(wx.VERTICAL) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + + main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5) + hsizer.Add(browse_btn, 0, wx.ALL, 5) + hsizer.Add(self.photo_txt, 0, wx.ALL, 5) + main_sizer.Add(hsizer, 0, wx.ALL, 5) + + self.SetSizer(main_sizer) + main_sizer.Fit(parent) + self.Layout() + + def on_browse(self, event): + """ + Browse for an image file + @param event: The event object + """ + wildcard = "JPEG files (*.jpg)|*.jpg" + with wx.FileDialog(None, "Choose a file", + wildcard=wildcard, + style=wx.ID_OPEN) as dialog: + if dialog.ShowModal() == wx.ID_OK: + self.photo_txt.SetValue(dialog.GetPath()) + self.load_image() + + def load_image(self): + """ + Load the image and display it to the user + """ + filepath = self.photo_txt.GetValue() + img = wx.Image(filepath, wx.BITMAP_TYPE_ANY) + + # scale the image, preserving the aspect ratio + W = img.GetWidth() + H = img.GetHeight() + if W > H: + NewW = self.max_size + NewH = self.max_size * H / W + else: + NewH = self.max_size + NewW = self.max_size * W / H + img = img.Scale(NewW,NewH) + + self.image_ctrl.SetBitmap(wx.Bitmap(img)) + self.Refresh() + + +class MainFrame(wx.Frame): + + def __init__(self): + super().__init__(None, title='Image Viewer') + panel = ImagePanel(self, image_size=(240,240)) + self.Show() + + +if __name__ == '__main__': + app = wx.App(redirect=False) + frame = MainFrame() + app.MainLoop() \ No newline at end of file