diff --git a/document-python-code-with-chatgpt/README.md b/document-python-code-with-chatgpt/README.md new file mode 100644 index 0000000000..905694ee9b --- /dev/null +++ b/document-python-code-with-chatgpt/README.md @@ -0,0 +1,3 @@ +# Document Your Python Code and Projects With ChatGPT + +This folder provides the code examples for the Real Python tutorial [Document Your Python Code and Projects With ChatGPT](https://realpython.com/document-python-code-with-chatgpt/). diff --git a/document-python-code-with-chatgpt/circle.py b/document-python-code-with-chatgpt/circle.py new file mode 100644 index 0000000000..d9940822e2 --- /dev/null +++ b/document-python-code-with-chatgpt/circle.py @@ -0,0 +1,56 @@ +"""Prompt +Write NumPy-style docstrings for the following class and its methods: + +class Circle: + def __init__(self, radius): + self.radius = radius + + def calculate_area(self): + return round(math.pi * self.radius ** 2, 2) +""" + +import math + + +# Output: +class Circle: + """ + A Circle class to perform some circle-related operations. + + Parameters + ---------- + radius : float + The radius of the circle. + + Attributes + ---------- + radius : float + The radius of the circle. + + Methods + ------- + calculate_area(): + Calculates the area of the circle. + """ + + def __init__(self, radius): + """ + Constructs all the necessary attributes for the circle object. + + Parameters + ---------- + radius : float + The radius of the circle. + """ + self.radius = radius + + def calculate_area(self): + """ + Calculate the area of the circle. + + Returns + ------- + float + The area of the circle rounded to 2 decimal places. + """ + return round(math.pi * self.radius**2, 2) diff --git a/document-python-code-with-chatgpt/code_explanation.py b/document-python-code-with-chatgpt/code_explanation.py new file mode 100644 index 0000000000..279269ff15 --- /dev/null +++ b/document-python-code-with-chatgpt/code_explanation.py @@ -0,0 +1,9 @@ +"""Prompt +Explain how the following function works: + +def find_extremes(iterable): + data = tuple(iterable) + if len(data) == 0: + raise ValueError("input iterable must not be empty") + return min(data), max(data) +""" diff --git a/document-python-code-with-chatgpt/docstring_1.py b/document-python-code-with-chatgpt/docstring_1.py new file mode 100644 index 0000000000..110858255a --- /dev/null +++ b/document-python-code-with-chatgpt/docstring_1.py @@ -0,0 +1,12 @@ +""""Prompt +Write a single-line docstring for the following function: + +def add(a, b): + return a + b +""" + + +# Output: +def add(a, b): + """Return the sum of a and b.""" + return a + b diff --git a/document-python-code-with-chatgpt/docstring_2.py b/document-python-code-with-chatgpt/docstring_2.py new file mode 100644 index 0000000000..b576d82858 --- /dev/null +++ b/document-python-code-with-chatgpt/docstring_2.py @@ -0,0 +1,71 @@ +"""Propmt +Write a Google-style docstring for the following function: + +def add(a, b): + return a + b +""" + + +# Output: +def add(a, b): + """Sum two numbers. + + Args: + a (int or float): The first number. + b (int or float): The second number. + + Returns: + int or float: The sum of the two numbers. + """ + return a + b + + +"""Prompt +Write a Numpy-style docstring for the following function: + +def add(a, b): + return a + b +""" + + +# Output: +def add_(a, b): + """ + Sum two numbers. + + Parameters + ---------- + a : int or float + The first number to be added. + b : int or float + The second number to be added. + + Returns + ------- + int or float + The sum of a and b. + """ + return a + b + + +"""Prompt +Write a Sphinx-style docstring for the following function: + +def add(a, b): + return a + b +""" + + +# Output: +def add__(a, b): + """ + Calculate the sum of two numbers. + + :param a: The first number. + :type a: int or float + :param b: The second number. + :type b: int or float + :return: The sum of the two numbers. + :rtype: int or float + """ + return a + b diff --git a/document-python-code-with-chatgpt/doctest_tests.py b/document-python-code-with-chatgpt/doctest_tests.py new file mode 100644 index 0000000000..4430d9a6bf --- /dev/null +++ b/document-python-code-with-chatgpt/doctest_tests.py @@ -0,0 +1,39 @@ +"""Prompt +Write a NumPy-style docstring for the following function. +Add a section with usage examples as doctest tests: + +def add(a, b): + return a + b +""" + + +# Output: +def add(a, b): + """ + Add two numbers together. + + This function takes two numbers (either integers or floats) + as arguments and returns their sum. + + Parameters + ---------- + a : int or float + The first number to add. + b : int or float + The second number to add. + + Returns + ------- + int or float + The sum of the two input numbers. + + Examples + -------- + >>> add(1, 2) + 3 + >>> add(5.5, 2.5) + 8.0 + >>> add(100, -50) + 50 + """ + return a + b diff --git a/document-python-code-with-chatgpt/interval.py b/document-python-code-with-chatgpt/interval.py new file mode 100644 index 0000000000..168114869f --- /dev/null +++ b/document-python-code-with-chatgpt/interval.py @@ -0,0 +1,30 @@ +"""Prompt +Write a Google-style docstring for a function with the following signature: + +def in_interval(number, start, end): +""" + + +# Output: +def in_interval(number, start, end): + """ + Checks if a given number is within a specified interval. + + This function takes three arguments: a number, and the start + and end points of an interval. + It checks whether the given number falls within the specified + interval or not. + + Args: + number (int or float): The number to check. + start (int or float): The starting point of the interval. + end (int or float): The ending point of the interval. + + Returns: + bool: True if the given number falls within the interval, + False otherwise. + + Raises: + ValueError: If the start is larger than the end, or if + the number, start, or end are not numbers. + """ diff --git a/document-python-code-with-chatgpt/prime.py b/document-python-code-with-chatgpt/prime.py new file mode 100644 index 0000000000..b7e9f21e1c --- /dev/null +++ b/document-python-code-with-chatgpt/prime.py @@ -0,0 +1,27 @@ +"""Prompt +Write a Google-style docstring for a function that takes an +integer as an argument and determines whether it’s a prime +number. +""" + + +# Output: +def is_prime_number(n): + """ + Determines if an input integer is a prime number. + + This function takes an integer as an argument and checks + whether it is a prime number. A prime number is a + positive natural number greater than 1 that has no positive + integer divisors other than 1 and itself. + + Args: + n (int): The integer to check. + + Returns: + bool: True if the input integer is a prime number, + False otherwise. + + Raises: + ValueError: If n is less than or equal to 1. + """ diff --git a/document-python-code-with-chatgpt/usage_examples.py b/document-python-code-with-chatgpt/usage_examples.py new file mode 100644 index 0000000000..3db413ab8c --- /dev/null +++ b/document-python-code-with-chatgpt/usage_examples.py @@ -0,0 +1,9 @@ +"""Prompt +Write three usage examples for the following function. +Add explanations to each example: + +def is_divisible(a, b): + if not a % b: + return True + return False +""" diff --git a/python-type-hints-multiple-types/01_type_hints_for_one_piece_of_data.py b/python-type-hints-multiple-types/01_type_hints_for_one_piece_of_data.py new file mode 100644 index 0000000000..8da0a92531 --- /dev/null +++ b/python-type-hints-multiple-types/01_type_hints_for_one_piece_of_data.py @@ -0,0 +1,16 @@ +def parse_email(email_address: str) -> str | None: + if "@" in email_address: + username, domain = email_address.split("@") + return username + return None + + +# %% Python 3.9 and earlier + +# from typing import Union +# +# def parse_email(email_address: str) -> Union[str, None]: +# if "@" in email_address: +# username, domain = email_address.split("@") +# return username +# return None diff --git a/python-type-hints-multiple-types/02_type_hints_for_multiple_pieces_of_data.py b/python-type-hints-multiple-types/02_type_hints_for_multiple_pieces_of_data.py new file mode 100644 index 0000000000..c0bfc13a70 --- /dev/null +++ b/python-type-hints-multiple-types/02_type_hints_for_multiple_pieces_of_data.py @@ -0,0 +1,16 @@ +def parse_email(email_address: str) -> tuple[str, str] | None: + if "@" in email_address: + username, domain = email_address.split("@") + return username, domain + return None + + +# %% Python 3.9 and earlier + +# from typing import Tuple, Union +# +# def parse_email(email_address: str) -> Union[Tuple[str, str], None]: +# if "@" in email_address: +# username, domain = email_address.split("@") +# return username, domain +# return None diff --git a/python-type-hints-multiple-types/03_type_hints_for_callback.py b/python-type-hints-multiple-types/03_type_hints_for_callback.py new file mode 100644 index 0000000000..d65ee6df33 --- /dev/null +++ b/python-type-hints-multiple-types/03_type_hints_for_callback.py @@ -0,0 +1,19 @@ +from collections.abc import Callable +from typing import ParamSpec, TypeVar + +P = ParamSpec("P") +T = TypeVar("T") + + +def apply_func(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + return func(*args, **kwargs) + + +def parse_email(email_address: str) -> tuple[str, str]: + if "@" in email_address: + username, domain = email_address.split("@") + return username, domain + return "", "" + + +apply_func(parse_email, "claudia@realpython.com") diff --git a/python-type-hints-multiple-types/04_type_hints_for_factory_function.py b/python-type-hints-multiple-types/04_type_hints_for_factory_function.py new file mode 100644 index 0000000000..c2b8afc52c --- /dev/null +++ b/python-type-hints-multiple-types/04_type_hints_for_factory_function.py @@ -0,0 +1,31 @@ +import functools +import time +from collections.abc import Callable +from typing import ParamSpec, TypeVar + +P = ParamSpec("P") +T = TypeVar("T") + + +def timeit(function: Callable[P, T]) -> Callable[P, T]: + @functools.wraps(function) + def wrapper(*args: P.args, **kwargs: P.kwargs): + start = time.perf_counter() + result = function(*args, **kwargs) + end = time.perf_counter() + print(f"{function.__name__}() finished in {end - start:.10f}s") + return result + + return wrapper + + +@timeit +def parse_email(email_address: str) -> tuple[str, str]: + if "@" in email_address: + username, domain = email_address.split("@") + return username, domain + return "", "" + + +username, domain = parse_email("claudia@realpython.com") +print(username, domain) diff --git a/python-type-hints-multiple-types/05_type_hints_for_generator.py b/python-type-hints-multiple-types/05_type_hints_for_generator.py new file mode 100644 index 0000000000..fab68bd2ef --- /dev/null +++ b/python-type-hints-multiple-types/05_type_hints_for_generator.py @@ -0,0 +1,37 @@ +from collections.abc import Generator, Iterator + + +def parse_email() -> Generator[tuple[str, str], str, str]: + sent = yield "", "" + while sent != "": + if "@" in sent: + username, domain = sent.split("@") + sent = yield username, domain + else: + sent = yield "ERROR", "invalid email" + return "Done" + + +generator = parse_email() +next(generator) +generator.send("claudia@realpython.com") +generator.send("realpython") +try: + generator.send("") +except StopIteration as ex: + print(ex.value) + + +def parse_emails(emails: list[str]) -> Iterator[tuple[str, str]]: + for email in emails: + if "@" in email: + username, domain = email.split("@") + yield username, domain + + +# from collections.abc import Iterable +# def parse_emails(emails: Iterable[str]) -> Iterable[tuple[str, str]]: +# for email in emails: +# if "@" in email: +# username, domain = email.split("@") +# yield username, domain diff --git a/python-type-hints-multiple-types/06_type_aliases.py b/python-type-hints-multiple-types/06_type_aliases.py new file mode 100644 index 0000000000..880fdd8cbb --- /dev/null +++ b/python-type-hints-multiple-types/06_type_aliases.py @@ -0,0 +1,11 @@ +from typing import TypeAlias + + +EmailComponents: TypeAlias = tuple[str, str] | None + + +def parse_email(email_address: str) -> EmailComponents: + if "@" in email_address: + username, domain = email_address.split("@") + return username, domain + return None diff --git a/python-type-hints-multiple-types/07_static_type_checking.py b/python-type-hints-multiple-types/07_static_type_checking.py new file mode 100644 index 0000000000..9204b2f70d --- /dev/null +++ b/python-type-hints-multiple-types/07_static_type_checking.py @@ -0,0 +1,5 @@ +def parse_email(email_address: str) -> tuple[str, str] | None: + if "@" in email_address: + username, domain = email_address.split("@") + return username, domain + return None diff --git a/python-type-hints-multiple-types/README.md b/python-type-hints-multiple-types/README.md new file mode 100644 index 0000000000..2b3cdc3a6e --- /dev/null +++ b/python-type-hints-multiple-types/README.md @@ -0,0 +1,17 @@ +# How to Use Type Hints for Multiple Return Types in Python + +This folder contains sample code for the [How to Use Type Hints for Multiple Return Types in Python](https://realpython.com/python-type-hints-multiple-types/) tutorial on Real Python. + +## Installation + +Some of the code requires the following third-party library: + +- [`mypy`](https://pypi.org/project/mypy/) + +To install it into a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/), type the following commands: + +```shell +$ python3 -m venv venv/ +$ source venv/bin/activate +(venv) $ python -m pip install -r requirements.txt +``` diff --git a/python-type-hints-multiple-types/requirements.txt b/python-type-hints-multiple-types/requirements.txt new file mode 100644 index 0000000000..01bdb66600 --- /dev/null +++ b/python-type-hints-multiple-types/requirements.txt @@ -0,0 +1,3 @@ +mypy==1.5.1 +mypy-extensions==1.0.0 +typing_extensions==4.8.0