├── 0x00-python_variable_annotations ├── 0-add.py ├── 0-main.py ├── 1-concat.py ├── 100-safe_first_element.py ├── 101-safely_get_value.py ├── 102-type_checking.py ├── 2-floor.py ├── 3-to_str.py ├── 4-define_variables.py ├── 5-sum_list.py ├── 6-sum_mixed_list.py ├── 7-to_kv.py ├── 8-make_multiplier.py ├── 9-element_length.py ├── README.md └── __pycache__ │ └── 0-add.cpython-38.pyc ├── 0x01-python_async_function ├── 0-basic_async_syntax.py ├── 0-main.py ├── 1-concurrent_coroutines.py ├── 1-main.py ├── 2-main.py ├── 2-measure_runtime.py ├── 3-main.py ├── 3-tasks.py ├── 4-main.py ├── 4-tasks.py ├── README.md └── __pycache__ │ ├── 0-basic_async_syntax.cpython-38.pyc │ ├── 1-concurrent_coroutines.cpython-38.pyc │ ├── 2-measure_runtime.cpython-38.pyc │ ├── 3-tasks.cpython-38.pyc │ └── 4-tasks.cpython-38.pyc ├── 0x02-python_async_comprehension ├── 0-async_generator.py ├── 0-main.py ├── 1-async_comprehension.py ├── 1-main.py ├── 2-main.py ├── 2-measure_runtime.py ├── README.md └── __pycache__ │ ├── 0-async_generator.cpython-38.pyc │ ├── 1-async_comprehension.cpython-38.pyc │ └── 2-measure_runtime.cpython-38.pyc ├── 0x03-Unittests_and_integration_tests ├── README.md ├── client.py ├── fixtures.py ├── test_client.py ├── test_utils.py └── utils.py └── README.md /0x00-python_variable_annotations/0-add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | Basic annotations for variables. 5 | ''' 6 | 7 | 8 | def add(a: float, b: float) -> float: 9 | ''' 10 | Returns sum of two floats. 11 | ''' 12 | return a + b 13 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/0-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | add = __import__('0-add').add 3 | 4 | print(add(1.11, 2.22) == 1.11 + 2.22) 5 | print(add.__annotations__) 6 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/1-concat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ Basic annotations concat """ 4 | 5 | 6 | def concat(str1: str, str2: str) -> str: 7 | """ Returns sum of two strings """ 8 | return str1 + str2 9 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/100-safe_first_element.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Duck typing - first element of a sequence """ 3 | from typing import Any, Union, Sequence, Iterable, List, Tuple 4 | 5 | 6 | # The types of the elements of the input are not know 7 | def safe_first_element(lst: Sequence[Any]) -> Union[Any, None]: 8 | """ Safe first element """ 9 | if lst: 10 | return lst[0] 11 | else: 12 | return None 13 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/101-safely_get_value.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ More involved type annotations """ 3 | from typing import Mapping, Any, Sequence, Union, TypeVar 4 | 5 | 6 | T = TypeVar('T') 7 | 8 | 9 | def safely_get_value(dct: Mapping, key: Any, 10 | default: Union[T, None] = None 11 | ) -> Union[Any, T]: 12 | """ Safely get value """ 13 | if key in dct: 14 | return dct[key] 15 | else: 16 | return default 17 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/102-type_checking.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Type Checking """ 3 | from typing import Tuple, List 4 | 5 | 6 | def zoom_array(lst: Tuple, factor: int = 2) -> List: 7 | """ Zoom Array """ 8 | zoomed_in: List = [ 9 | item for item in lst 10 | for i in range(factor) 11 | ] 12 | return zoomed_in 13 | 14 | 15 | array = (12, 72, 91) 16 | 17 | zoom_2x = zoom_array(array) 18 | 19 | zoom_3x = zoom_array(array, 3) 20 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/2-floor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Basic annotations concat """ 3 | 4 | import math 5 | 6 | 7 | def floor(n: float) -> int: 8 | """ Returns the floor of the float """ 9 | return math.floor(n) 10 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/3-to_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Basic annotations - to string """ 3 | 4 | 5 | def to_str(n: float) -> str: 6 | """ Returns the string representation of the float. """ 7 | return str(n) 8 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/4-define_variables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Define variables """ 3 | 4 | a: int = 1 5 | pi: float = 3.14 6 | i_understand_annotations: bool = True 7 | school: str = "Holberton" 8 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/5-sum_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Complex types - list of floats """ 3 | from typing import Callable, Iterator, Union, Optional, List 4 | 5 | 6 | def sum_list(input_list: List[float]) -> float: 7 | """ 8 | Takes a list input_list of floats as argument 9 | returns their sum as a float. 10 | """ 11 | 12 | return sum(input_list) 13 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/6-sum_mixed_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ mixed list """ 4 | from typing import Union, List 5 | 6 | 7 | def sum_mixed_list(mxd_lst: List[Union[int, float]]) -> float: 8 | """ returns sum as a float. """ 9 | return float(sum(mxd_lst)) 10 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/7-to_kv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Complex types - string and int/float to tuple""" 3 | from typing import Callable, Iterator, Union, Optional, List, Tuple 4 | 5 | 6 | def to_kv(k: str, v: Union[int, float]) -> Tuple[str, float]: 7 | """ 8 | takes a string k and an int OR float v as arguments 9 | returns a tuple. 10 | """ 11 | 12 | return (k, v**2) 13 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/8-make_multiplier.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Complex types - functions""" 3 | from typing import Callable, Iterator, Union, Optional, List, Tuple 4 | 5 | 6 | def make_multiplier(multiplier: float) -> Callable[[float], float]: 7 | """ 8 | takes a float multiplier as argument, 9 | returns a function that multiplies a float by multiplier. 10 | """ 11 | def f(n: float) -> float: 12 | """ multiplies a float by multiplier """ 13 | return float(n * multiplier) 14 | 15 | return f 16 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/9-element_length.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Let's duck type an iterable object""" 3 | from typing import Mapping, MutableMapping, Sequence, Iterable, List, Tuple 4 | 5 | 6 | def element_length(lst: Iterable[Sequence]) -> List[Tuple[Sequence, int]]: 7 | """ Element length """ 8 | return [(i, len(i)) for i in lst] 9 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/README.md: -------------------------------------------------------------------------------- 1 | # Python Variable Annotations Project 2 | 3 | ## Learning Objectives 4 | 5 | By the end of this project, you will gain knowledge and skills in the following areas: 6 | 7 | - Understanding type annotations in Python 3. 8 | - Using type annotations to specify function signatures and variable types. 9 | - Exploring the concept of duck typing in Python. 10 | - Validating your code for type correctness using Mypy. 11 | 12 | ## Requirements 13 | 14 | ### General 15 | 16 | - **Editors**: You are allowed to use vi, vim, or emacs for coding. 17 | - **Python Version**: All code will be interpreted/compiled using Python 3 (version 3.7). 18 | - **File Endings**: Ensure that all your files end with a newline character. 19 | - **Shebang Line**: The first line of all your Python files should be exactly `#!/usr/bin/env python3`. 20 | - **README.md**: A mandatory README.md file must be present at the root of your project folder. 21 | - **Code Style**: Your code should adhere to the pycodestyle style (version 2.5). 22 | - **Executable Files**: All your Python files must be executable. 23 | - **File Length**: The length of your files will be tested using `wc`. 24 | - **Documentation**: 25 | - All your modules should have documentation. You can check this using `python3 -c 'print(__import__("my_module").__doc__)'`. 26 | - All your classes should have documentation. You can check this using `python3 -c 'print(__import__("my_module").MyClass.__doc__)'`. 27 | - All your functions, both inside and outside a class, should have documentation. You can check this using `python3 -c 'print(__import__("my_module").my_function.__doc__)'` and `python3 -c 'print(__import__("my_module").MyClass.my_function.__doc__)'`. 28 | 29 | ### Documentation Guidelines 30 | 31 | - A documentation is not just a single word; it should be a complete sentence that explains the purpose of the module, class, or method. The length of your documentation will be verified. 32 | 33 | ## Project Overview 34 | 35 | This project is designed to help you improve your Python programming skills with a focus on variable annotations and type hinting. You will learn how to specify data types for variables, function parameters, and return values using type annotations. Additionally, you will explore the concept of duck typing and how to use the Mypy tool to validate your code for type correctness. 36 | 37 | ## Getting Started 38 | 39 | To get started with this project, follow these step 40 | -------------------------------------------------------------------------------- /0x00-python_variable_annotations/__pycache__/0-add.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x00-python_variable_annotations/__pycache__/0-add.cpython-38.pyc -------------------------------------------------------------------------------- /0x01-python_async_function/0-basic_async_syntax.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ''' 3 | The basics of async. 4 | ''' 5 | 6 | import asyncio 7 | import random 8 | 9 | 10 | async def wait_random(max_delay: int = 10) -> float: 11 | """ 12 | waits for a random delay between 0 and max_delay (included and float value) 13 | seconds and eventually returns it. 14 | """ 15 | delay = random.uniform(0, max_delay) 16 | await asyncio.sleep(delay) 17 | return delay 18 | -------------------------------------------------------------------------------- /0x01-python_async_function/0-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | wait_random = __import__('0-basic_async_syntax').wait_random 6 | 7 | print(asyncio.run(wait_random())) 8 | print(asyncio.run(wait_random(5))) 9 | print(asyncio.run(wait_random(15))) 10 | -------------------------------------------------------------------------------- /0x01-python_async_function/1-concurrent_coroutines.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ The basics of async """ 3 | 4 | import asyncio 5 | from typing import List 6 | 7 | wait_random = __import__('0-basic_async_syntax').wait_random 8 | 9 | 10 | async def wait_n(n: int, max_delay: int) -> List[float]: 11 | """ 12 | spawn wait_random n times with the specified max_delay. 13 | """ 14 | tasks = [asyncio.create_task(wait_random(max_delay)) for _ in range(n)] 15 | return [await task for task in asyncio.as_completed(tasks)] 16 | -------------------------------------------------------------------------------- /0x01-python_async_function/1-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ''' 3 | Test file for printing the correct output of the wait_n coroutine 4 | ''' 5 | import asyncio 6 | 7 | wait_n = __import__('1-concurrent_coroutines').wait_n 8 | 9 | print(asyncio.run(wait_n(5, 5))) 10 | print(asyncio.run(wait_n(10, 7))) 11 | print(asyncio.run(wait_n(10, 0))) 12 | -------------------------------------------------------------------------------- /0x01-python_async_function/2-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | measure_time = __import__('2-measure_runtime').measure_time 4 | 5 | n = 5 6 | max_delay = 9 7 | 8 | print(measure_time(n, max_delay)) 9 | -------------------------------------------------------------------------------- /0x01-python_async_function/2-measure_runtime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ The basics of async """ 3 | 4 | from asyncio import run 5 | from time import time 6 | 7 | wait_n = __import__('1-concurrent_coroutines').wait_n 8 | 9 | 10 | def measure_time(n: int, max_delay: int) -> float: 11 | """ Measure the runtime """ 12 | start = time() 13 | 14 | run(wait_n(n, max_delay)) 15 | 16 | end = time() 17 | 18 | return (end - start) / n 19 | -------------------------------------------------------------------------------- /0x01-python_async_function/3-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | task_wait_random = __import__('3-tasks').task_wait_random 6 | 7 | 8 | async def test(max_delay: int) -> float: 9 | task = task_wait_random(max_delay) 10 | await task 11 | print(task.__class__) 12 | 13 | asyncio.run(test(5)) 14 | -------------------------------------------------------------------------------- /0x01-python_async_function/3-tasks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Async basics """ 3 | 4 | from asyncio import Task, create_task 5 | 6 | wait_random = __import__('0-basic_async_syntax').wait_random 7 | 8 | 9 | def task_wait_random(max_delay: int) -> Task: 10 | """ Tasks """ 11 | task = create_task(wait_random(max_delay)) 12 | return task 13 | -------------------------------------------------------------------------------- /0x01-python_async_function/4-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | task_wait_n = __import__('4-tasks').task_wait_n 6 | 7 | n = 5 8 | max_delay = 6 9 | print(asyncio.run(task_wait_n(n, max_delay))) 10 | -------------------------------------------------------------------------------- /0x01-python_async_function/4-tasks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ The basics of async """ 3 | 4 | import asyncio 5 | from typing import List 6 | 7 | task_wait_random = __import__('3-tasks').task_wait_random 8 | 9 | 10 | async def task_wait_n(n: int, max_delay: int) -> List[float]: 11 | """ 12 | spawn task_wait_random n times with the specified max_delay. 13 | """ 14 | tasks = [task_wait_random(max_delay) for _ in range(n)] 15 | return [await task for task in asyncio.as_completed(tasks)] 16 | -------------------------------------------------------------------------------- /0x01-python_async_function/README.md: -------------------------------------------------------------------------------- 1 | # Asynchronous Python (asyncio) Project 2 | 3 | ## Learning Objectives 4 | 5 | This project focuses on asynchronous programming in Python using the asyncio library. By the end of this project, you will be able to: 6 | 7 | 1. Understand and use the `async` and `await` syntax in Python for asynchronous operations. 8 | 2. Execute an async program with asyncio. 9 | 3. Run concurrent coroutines to improve program efficiency. 10 | 4. Create asyncio tasks to manage asynchronous operations effectively. 11 | 5. Utilize the Python `random` module within asynchronous code. 12 | 13 | ## Requirements 14 | 15 | ### General 16 | 17 | - **Python Version**: Python 3.7 18 | - **Operating System**: Ubuntu 18.04 LTS 19 | 20 | ### Code Style and Documentation 21 | 22 | - All code files follow the `pycodestyle` (version 2.5.x) coding style guide. 23 | - Code files have a newline at the end. 24 | - The first line of code files starts with `#!/usr/bin/env python3`. 25 | - Functions and coroutines are appropriately type-annotated. 26 | - Modules have documentation using `python3 -c 'print(__import__("my_module").__doc__)'`. 27 | - Functions have documentation using `python3 -c 'print(__import__("my_module").my_function.__doc__)'`. The documentation consists of clear and meaningful sentences describing the purpose of the function. 28 | 29 | ### Project Structure 30 | project-root/ 31 | │ 32 | ├── your_code_file.py 33 | ├── another_code_file.py 34 | │ 35 | └── README.md 36 | 37 | ### Usage 38 | 39 | Include instructions on how to run and use your code here. 40 | 41 | ### Example 42 | 43 | Provide an example or code snippet demonstrating the usage of your async code and asyncio tasks. 44 | 45 | ```python 46 | import asyncio 47 | 48 | async def main(): 49 | # Your async code here 50 | pass 51 | 52 | if __name__ == "__main__": 53 | asyncio.run(main()) 54 | 55 | -------------------------------------------------------------------------------- /0x01-python_async_function/__pycache__/0-basic_async_syntax.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x01-python_async_function/__pycache__/0-basic_async_syntax.cpython-38.pyc -------------------------------------------------------------------------------- /0x01-python_async_function/__pycache__/1-concurrent_coroutines.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x01-python_async_function/__pycache__/1-concurrent_coroutines.cpython-38.pyc -------------------------------------------------------------------------------- /0x01-python_async_function/__pycache__/2-measure_runtime.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x01-python_async_function/__pycache__/2-measure_runtime.cpython-38.pyc -------------------------------------------------------------------------------- /0x01-python_async_function/__pycache__/3-tasks.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x01-python_async_function/__pycache__/3-tasks.cpython-38.pyc -------------------------------------------------------------------------------- /0x01-python_async_function/__pycache__/4-tasks.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x01-python_async_function/__pycache__/4-tasks.cpython-38.pyc -------------------------------------------------------------------------------- /0x02-python_async_comprehension/0-async_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ a python module to loop 10 times """ 3 | import random 4 | import asyncio 5 | from typing import Generator 6 | 7 | 8 | async def async_generator() -> Generator[float, None, None]: 9 | """ 10 | async_generator - function to loop 10 times 11 | Arguments: 12 | no arguments 13 | Returns: 14 | nothing 15 | """ 16 | for i in range(10): 17 | await asyncio.sleep(1) 18 | yield random.uniform(0, 10) 19 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/0-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | async_generator = __import__('0-async_generator').async_generator 6 | 7 | async def print_yielded_values(): 8 | result = [] 9 | async for i in async_generator(): 10 | result.append(i) 11 | print(result) 12 | 13 | asyncio.run(print_yielded_values()) 14 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/1-async_comprehension.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ a python module to returns 10 random numbers using async comprehension""" 3 | from typing import List 4 | async_generator = __import__('0-async_generator').async_generator 5 | 6 | 7 | async def async_comprehension() -> List[float]: 8 | """ 9 | async_comprehension- function to return 10 random numbers 10 | Arguments: 11 | no arguments 12 | Returns: 13 | 10 random numbers 14 | """ 15 | rslt = [i async for i in async_generator()] 16 | return rslt 17 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/1-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | async_comprehension = __import__('1-async_comprehension').async_comprehension 6 | 7 | 8 | async def main(): 9 | print(await async_comprehension()) 10 | 11 | asyncio.run(main()) 12 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/2-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | 5 | 6 | measure_runtime = __import__('2-measure_runtime').measure_runtime 7 | 8 | 9 | async def main(): 10 | return await(measure_runtime()) 11 | 12 | print( 13 | asyncio.run(main()) 14 | ) 15 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/2-measure_runtime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """a python module to measure the execution time""" 3 | import time 4 | import asyncio 5 | async_comprehension = __import__('1-async_comprehension').async_comprehension 6 | 7 | 8 | async def measure_runtime() -> float: 9 | """ 10 | measure_runtime - function execute async_com 4 times 11 | Arguments: 12 | nothing 13 | Returns: 14 | the total exection time required to complete the task 15 | """ 16 | t_start = time.perf_counter() 17 | task = [async_comprehension() for i in range(4)] 18 | await asyncio.gather(*task) 19 | t_end = time.perf_counter() 20 | return (t_end - t_start) 21 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/README.md: -------------------------------------------------------------------------------- 1 | # Async Python Project 2 | 3 | This project explores asynchronous programming in Python, focusing on asynchronous generators and async comprehensions. 4 | 5 | ## Table of Contents 6 | 7 | - [Introduction](#introduction) 8 | - [Learning Objectives](#learning-objectives) 9 | - [Requirements](#requirements) 10 | - [Getting Started](#getting-started) 11 | - [Usage](#usage) 12 | - [Documentation](#documentation) 13 | - [Contributing](#contributing) 14 | - [License](#license) 15 | 16 | ## Introduction 17 | 18 | In this project, we will learn how to work with asynchronous generators and async comprehensions in Python. These are powerful features for writing concurrent and efficient code in asynchronous applications. 19 | 20 | ## Learning Objectives 21 | 22 | By the end of this project, you should be able to: 23 | 24 | 1. Write asynchronous generators in Python. 25 | 2. Utilize async comprehensions to work with asynchronous tasks. 26 | 3. Properly type-annotate generators, functions, and coroutines. 27 | 28 | ## Requirements 29 | 30 | - Python 3.7 31 | - Ubuntu 18.04 LTS 32 | - Pycodestyle 2.5.x 33 | 34 | ## Getting Started 35 | 36 | 1. Clone this repository to your local machine: 37 | 38 | ```bash 39 | git clone https://github.com/your-username/async-python-project.git 40 | 41 | -------------------------------------------------------------------------------- /0x02-python_async_comprehension/__pycache__/0-async_generator.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x02-python_async_comprehension/__pycache__/0-async_generator.cpython-38.pyc -------------------------------------------------------------------------------- /0x02-python_async_comprehension/__pycache__/1-async_comprehension.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x02-python_async_comprehension/__pycache__/1-async_comprehension.cpython-38.pyc -------------------------------------------------------------------------------- /0x02-python_async_comprehension/__pycache__/2-measure_runtime.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ambesawi/alx-backend-python/5c6adf600979f4f28293566994680f62814ca297/0x02-python_async_comprehension/__pycache__/2-measure_runtime.cpython-38.pyc -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/README.md: -------------------------------------------------------------------------------- 1 | # Unittests and Integration Tests Project 2 | 3 | This project focuses on the concepts of unit tests and integration tests in software development. It also covers common testing patterns and techniques such as mocking, parametrization, and fixtures. 4 | 5 | ## Table of Contents 6 | 7 | - [Introduction](#introduction) 8 | - [Learning Objectives](#learning-objectives) 9 | - [Requirements](#requirements) 10 | - [Project Structure](#project-structure) 11 | - [Usage](#usage) 12 | - [Testing Patterns](#testing-patterns) 13 | - [Contributing](#contributing) 14 | - [License](#license) 15 | 16 | ## Introduction 17 | 18 | This project aims to enhance your understanding of different testing methodologies used in software development. It covers the differences between unit tests, which focus on individual components, and integration tests, which verify interactions between multiple components. The project also delves into common testing patterns and practices, including the use of mocking, parametrization, and fixtures. 19 | 20 | ## Learning Objectives 21 | 22 | By the end of this project, you will be able to: 23 | 24 | - Differentiate between unit tests and integration tests. 25 | - Apply common testing patterns, such as mocking, parametrization, and fixtures. 26 | 27 | ## Requirements 28 | 29 | - **Operating System**: Ubuntu 18.04 LTS 30 | - **Python Version**: Python 3.7 31 | - **Coding Style**: Pycodestyle (PEP 8) style (version 2.5) 32 | 33 | ## Project Structure 34 | 35 | The project directory includes the following files, among others: 36 | 37 | 38 | -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """A github org client 3 | """ 4 | from typing import ( 5 | List, 6 | Dict, 7 | ) 8 | 9 | from utils import ( 10 | get_json, 11 | access_nested_map, 12 | memoize, 13 | ) 14 | 15 | 16 | class GithubOrgClient: 17 | """A Githib org client 18 | """ 19 | ORG_URL = "https://api.github.com/orgs/{org}" 20 | 21 | def __init__(self, org_name: str) -> None: 22 | """Init method of GithubOrgClient""" 23 | self._org_name = org_name 24 | 25 | @memoize 26 | def org(self) -> Dict: 27 | """Memoize org""" 28 | return get_json(self.ORG_URL.format(org=self._org_name)) 29 | 30 | @property 31 | def _public_repos_url(self) -> str: 32 | """Public repos URL""" 33 | return self.org["repos_url"] 34 | 35 | @memoize 36 | def repos_payload(self) -> Dict: 37 | """Memoize repos payload""" 38 | return get_json(self._public_repos_url) 39 | 40 | def public_repos(self, license: str = None) -> List[str]: 41 | """Public repos""" 42 | json_payload = self.repos_payload 43 | public_repos = [ 44 | repo["name"] for repo in json_payload 45 | if license is None or self.has_license(repo, license) 46 | ] 47 | 48 | return public_repos 49 | 50 | @staticmethod 51 | def has_license(repo: Dict[str, Dict], license_key: str) -> bool: 52 | """Static: has_license""" 53 | assert license_key is not None, "license_key cannot be None" 54 | try: 55 | has_license = access_nested_map(repo, ("license", "key")) == license_key 56 | except KeyError: 57 | return False 58 | return has_license 59 | -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/fixtures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | TEST_PAYLOAD = [ 4 | ( 5 | {"repos_url": "https://api.github.com/orgs/google/repos"}, 6 | [ 7 | { 8 | "id": 7697149, 9 | "node_id": "MDEwOlJlcG9zaXRvcnk3Njk3MTQ5", 10 | "name": "episodes.dart", 11 | "full_name": "google/episodes.dart", 12 | "private": False, 13 | "owner": { 14 | "login": "google", 15 | "id": 1342004, 16 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 17 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 18 | "gravatar_id": "", 19 | "url": "https://api.github.com/users/google", 20 | "html_url": "https://github.com/google", 21 | "followers_url": "https://api.github.com/users/google/followers", 22 | "following_url": "https://api.github.com/users/google/following{/other_user}", 23 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 24 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 25 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 26 | "organizations_url": "https://api.github.com/users/google/orgs", 27 | "repos_url": "https://api.github.com/users/google/repos", 28 | "events_url": "https://api.github.com/users/google/events{/privacy}", 29 | "received_events_url": "https://api.github.com/users/google/received_events", 30 | "type": "Organization", 31 | "site_admin": False 32 | }, 33 | "html_url": "https://github.com/google/episodes.dart", 34 | "description": "A framework for timing performance of web apps.", 35 | "fork": False, 36 | "url": "https://api.github.com/repos/google/episodes.dart", 37 | "forks_url": "https://api.github.com/repos/google/episodes.dart/forks", 38 | "keys_url": "https://api.github.com/repos/google/episodes.dart/keys{/key_id}", 39 | "collaborators_url": "https://api.github.com/repos/google/episodes.dart/collaborators{/collaborator}", 40 | "teams_url": "https://api.github.com/repos/google/episodes.dart/teams", 41 | "hooks_url": "https://api.github.com/repos/google/episodes.dart/hooks", 42 | "issue_events_url": "https://api.github.com/repos/google/episodes.dart/issues/events{/number}", 43 | "events_url": "https://api.github.com/repos/google/episodes.dart/events", 44 | "assignees_url": "https://api.github.com/repos/google/episodes.dart/assignees{/user}", 45 | "branches_url": "https://api.github.com/repos/google/episodes.dart/branches{/branch}", 46 | "tags_url": "https://api.github.com/repos/google/episodes.dart/tags", 47 | "blobs_url": "https://api.github.com/repos/google/episodes.dart/git/blobs{/sha}", 48 | "git_tags_url": "https://api.github.com/repos/google/episodes.dart/git/tags{/sha}", 49 | "git_refs_url": "https://api.github.com/repos/google/episodes.dart/git/refs{/sha}", 50 | "trees_url": "https://api.github.com/repos/google/episodes.dart/git/trees{/sha}", 51 | "statuses_url": "https://api.github.com/repos/google/episodes.dart/statuses/{sha}", 52 | "languages_url": "https://api.github.com/repos/google/episodes.dart/languages", 53 | "stargazers_url": "https://api.github.com/repos/google/episodes.dart/stargazers", 54 | "contributors_url": "https://api.github.com/repos/google/episodes.dart/contributors", 55 | "subscribers_url": "https://api.github.com/repos/google/episodes.dart/subscribers", 56 | "subscription_url": "https://api.github.com/repos/google/episodes.dart/subscription", 57 | "commits_url": "https://api.github.com/repos/google/episodes.dart/commits{/sha}", 58 | "git_commits_url": "https://api.github.com/repos/google/episodes.dart/git/commits{/sha}", 59 | "comments_url": "https://api.github.com/repos/google/episodes.dart/comments{/number}", 60 | "issue_comment_url": "https://api.github.com/repos/google/episodes.dart/issues/comments{/number}", 61 | "contents_url": "https://api.github.com/repos/google/episodes.dart/contents/{+path}", 62 | "compare_url": "https://api.github.com/repos/google/episodes.dart/compare/{base}...{head}", 63 | "merges_url": "https://api.github.com/repos/google/episodes.dart/merges", 64 | "archive_url": "https://api.github.com/repos/google/episodes.dart/{archive_format}{/ref}", 65 | "downloads_url": "https://api.github.com/repos/google/episodes.dart/downloads", 66 | "issues_url": "https://api.github.com/repos/google/episodes.dart/issues{/number}", 67 | "pulls_url": "https://api.github.com/repos/google/episodes.dart/pulls{/number}", 68 | "milestones_url": "https://api.github.com/repos/google/episodes.dart/milestones{/number}", 69 | "notifications_url": "https://api.github.com/repos/google/episodes.dart/notifications{?since,all,participating}", 70 | "labels_url": "https://api.github.com/repos/google/episodes.dart/labels{/name}", 71 | "releases_url": "https://api.github.com/repos/google/episodes.dart/releases{/id}", 72 | "deployments_url": "https://api.github.com/repos/google/episodes.dart/deployments", 73 | "created_at": "2013-01-19T00:31:37Z", 74 | "updated_at": "2019-09-23T11:53:58Z", 75 | "pushed_at": "2014-10-09T21:39:33Z", 76 | "git_url": "git://github.com/google/episodes.dart.git", 77 | "ssh_url": "git@github.com:google/episodes.dart.git", 78 | "clone_url": "https://github.com/google/episodes.dart.git", 79 | "svn_url": "https://github.com/google/episodes.dart", 80 | "homepage": None, 81 | "size": 191, 82 | "stargazers_count": 12, 83 | "watchers_count": 12, 84 | "language": "Dart", 85 | "has_issues": True, 86 | "has_projects": True, 87 | "has_downloads": True, 88 | "has_wiki": True, 89 | "has_pages": False, 90 | "forks_count": 22, 91 | "mirror_url": None, 92 | "archived": False, 93 | "disabled": False, 94 | "open_issues_count": 0, 95 | "license": { 96 | "key": "bsd-3-clause", 97 | "name": "BSD 3-Clause \"New\" or \"Revised\" License", 98 | "spdx_id": "BSD-3-Clause", 99 | "url": "https://api.github.com/licenses/bsd-3-clause", 100 | "node_id": "MDc6TGljZW5zZTU=" 101 | }, 102 | "forks": 22, 103 | "open_issues": 0, 104 | "watchers": 12, 105 | "default_branch": "master", 106 | "permissions": { 107 | "admin": False, 108 | "push": False, 109 | "pull": True 110 | } 111 | }, 112 | { 113 | "id": 7776515, 114 | "node_id": "MDEwOlJlcG9zaXRvcnk3Nzc2NTE1", 115 | "name": "cpp-netlib", 116 | "full_name": "google/cpp-netlib", 117 | "private": False, 118 | "owner": { 119 | "login": "google", 120 | "id": 1342004, 121 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 122 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 123 | "gravatar_id": "", 124 | "url": "https://api.github.com/users/google", 125 | "html_url": "https://github.com/google", 126 | "followers_url": "https://api.github.com/users/google/followers", 127 | "following_url": "https://api.github.com/users/google/following{/other_user}", 128 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 129 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 130 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 131 | "organizations_url": "https://api.github.com/users/google/orgs", 132 | "repos_url": "https://api.github.com/users/google/repos", 133 | "events_url": "https://api.github.com/users/google/events{/privacy}", 134 | "received_events_url": "https://api.github.com/users/google/received_events", 135 | "type": "Organization", 136 | "site_admin": False 137 | }, 138 | "html_url": "https://github.com/google/cpp-netlib", 139 | "description": "The C++ Network Library Project -- header-only, cross-platform, standards compliant networking library.", 140 | "fork": True, 141 | "url": "https://api.github.com/repos/google/cpp-netlib", 142 | "forks_url": "https://api.github.com/repos/google/cpp-netlib/forks", 143 | "keys_url": "https://api.github.com/repos/google/cpp-netlib/keys{/key_id}", 144 | "collaborators_url": "https://api.github.com/repos/google/cpp-netlib/collaborators{/collaborator}", 145 | "teams_url": "https://api.github.com/repos/google/cpp-netlib/teams", 146 | "hooks_url": "https://api.github.com/repos/google/cpp-netlib/hooks", 147 | "issue_events_url": "https://api.github.com/repos/google/cpp-netlib/issues/events{/number}", 148 | "events_url": "https://api.github.com/repos/google/cpp-netlib/events", 149 | "assignees_url": "https://api.github.com/repos/google/cpp-netlib/assignees{/user}", 150 | "branches_url": "https://api.github.com/repos/google/cpp-netlib/branches{/branch}", 151 | "tags_url": "https://api.github.com/repos/google/cpp-netlib/tags", 152 | "blobs_url": "https://api.github.com/repos/google/cpp-netlib/git/blobs{/sha}", 153 | "git_tags_url": "https://api.github.com/repos/google/cpp-netlib/git/tags{/sha}", 154 | "git_refs_url": "https://api.github.com/repos/google/cpp-netlib/git/refs{/sha}", 155 | "trees_url": "https://api.github.com/repos/google/cpp-netlib/git/trees{/sha}", 156 | "statuses_url": "https://api.github.com/repos/google/cpp-netlib/statuses/{sha}", 157 | "languages_url": "https://api.github.com/repos/google/cpp-netlib/languages", 158 | "stargazers_url": "https://api.github.com/repos/google/cpp-netlib/stargazers", 159 | "contributors_url": "https://api.github.com/repos/google/cpp-netlib/contributors", 160 | "subscribers_url": "https://api.github.com/repos/google/cpp-netlib/subscribers", 161 | "subscription_url": "https://api.github.com/repos/google/cpp-netlib/subscription", 162 | "commits_url": "https://api.github.com/repos/google/cpp-netlib/commits{/sha}", 163 | "git_commits_url": "https://api.github.com/repos/google/cpp-netlib/git/commits{/sha}", 164 | "comments_url": "https://api.github.com/repos/google/cpp-netlib/comments{/number}", 165 | "issue_comment_url": "https://api.github.com/repos/google/cpp-netlib/issues/comments{/number}", 166 | "contents_url": "https://api.github.com/repos/google/cpp-netlib/contents/{+path}", 167 | "compare_url": "https://api.github.com/repos/google/cpp-netlib/compare/{base}...{head}", 168 | "merges_url": "https://api.github.com/repos/google/cpp-netlib/merges", 169 | "archive_url": "https://api.github.com/repos/google/cpp-netlib/{archive_format}{/ref}", 170 | "downloads_url": "https://api.github.com/repos/google/cpp-netlib/downloads", 171 | "issues_url": "https://api.github.com/repos/google/cpp-netlib/issues{/number}", 172 | "pulls_url": "https://api.github.com/repos/google/cpp-netlib/pulls{/number}", 173 | "milestones_url": "https://api.github.com/repos/google/cpp-netlib/milestones{/number}", 174 | "notifications_url": "https://api.github.com/repos/google/cpp-netlib/notifications{?since,all,participating}", 175 | "labels_url": "https://api.github.com/repos/google/cpp-netlib/labels{/name}", 176 | "releases_url": "https://api.github.com/repos/google/cpp-netlib/releases{/id}", 177 | "deployments_url": "https://api.github.com/repos/google/cpp-netlib/deployments", 178 | "created_at": "2013-01-23T14:45:32Z", 179 | "updated_at": "2019-11-15T02:26:31Z", 180 | "pushed_at": "2018-12-05T17:42:29Z", 181 | "git_url": "git://github.com/google/cpp-netlib.git", 182 | "ssh_url": "git@github.com:google/cpp-netlib.git", 183 | "clone_url": "https://github.com/google/cpp-netlib.git", 184 | "svn_url": "https://github.com/google/cpp-netlib", 185 | "homepage": "http://cpp-netlib.github.com/", 186 | "size": 8937, 187 | "stargazers_count": 292, 188 | "watchers_count": 292, 189 | "language": "C++", 190 | "has_issues": False, 191 | "has_projects": True, 192 | "has_downloads": True, 193 | "has_wiki": True, 194 | "has_pages": False, 195 | "forks_count": 59, 196 | "mirror_url": None, 197 | "archived": False, 198 | "disabled": False, 199 | "open_issues_count": 0, 200 | "license": { 201 | "key": "bsl-1.0", 202 | "name": "Boost Software License 1.0", 203 | "spdx_id": "BSL-1.0", 204 | "url": "https://api.github.com/licenses/bsl-1.0", 205 | "node_id": "MDc6TGljZW5zZTI4" 206 | }, 207 | "forks": 59, 208 | "open_issues": 0, 209 | "watchers": 292, 210 | "default_branch": "master", 211 | "permissions": { 212 | "admin": False, 213 | "push": False, 214 | "pull": True 215 | } 216 | }, 217 | { 218 | "id": 7968417, 219 | "node_id": "MDEwOlJlcG9zaXRvcnk3OTY4NDE3", 220 | "name": "dagger", 221 | "full_name": "google/dagger", 222 | "private": False, 223 | "owner": { 224 | "login": "google", 225 | "id": 1342004, 226 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 227 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 228 | "gravatar_id": "", 229 | "url": "https://api.github.com/users/google", 230 | "html_url": "https://github.com/google", 231 | "followers_url": "https://api.github.com/users/google/followers", 232 | "following_url": "https://api.github.com/users/google/following{/other_user}", 233 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 234 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 235 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 236 | "organizations_url": "https://api.github.com/users/google/orgs", 237 | "repos_url": "https://api.github.com/users/google/repos", 238 | "events_url": "https://api.github.com/users/google/events{/privacy}", 239 | "received_events_url": "https://api.github.com/users/google/received_events", 240 | "type": "Organization", 241 | "site_admin": False 242 | }, 243 | "html_url": "https://github.com/google/dagger", 244 | "description": "A fast dependency injector for Android and Java.", 245 | "fork": True, 246 | "url": "https://api.github.com/repos/google/dagger", 247 | "forks_url": "https://api.github.com/repos/google/dagger/forks", 248 | "keys_url": "https://api.github.com/repos/google/dagger/keys{/key_id}", 249 | "collaborators_url": "https://api.github.com/repos/google/dagger/collaborators{/collaborator}", 250 | "teams_url": "https://api.github.com/repos/google/dagger/teams", 251 | "hooks_url": "https://api.github.com/repos/google/dagger/hooks", 252 | "issue_events_url": "https://api.github.com/repos/google/dagger/issues/events{/number}", 253 | "events_url": "https://api.github.com/repos/google/dagger/events", 254 | "assignees_url": "https://api.github.com/repos/google/dagger/assignees{/user}", 255 | "branches_url": "https://api.github.com/repos/google/dagger/branches{/branch}", 256 | "tags_url": "https://api.github.com/repos/google/dagger/tags", 257 | "blobs_url": "https://api.github.com/repos/google/dagger/git/blobs{/sha}", 258 | "git_tags_url": "https://api.github.com/repos/google/dagger/git/tags{/sha}", 259 | "git_refs_url": "https://api.github.com/repos/google/dagger/git/refs{/sha}", 260 | "trees_url": "https://api.github.com/repos/google/dagger/git/trees{/sha}", 261 | "statuses_url": "https://api.github.com/repos/google/dagger/statuses/{sha}", 262 | "languages_url": "https://api.github.com/repos/google/dagger/languages", 263 | "stargazers_url": "https://api.github.com/repos/google/dagger/stargazers", 264 | "contributors_url": "https://api.github.com/repos/google/dagger/contributors", 265 | "subscribers_url": "https://api.github.com/repos/google/dagger/subscribers", 266 | "subscription_url": "https://api.github.com/repos/google/dagger/subscription", 267 | "commits_url": "https://api.github.com/repos/google/dagger/commits{/sha}", 268 | "git_commits_url": "https://api.github.com/repos/google/dagger/git/commits{/sha}", 269 | "comments_url": "https://api.github.com/repos/google/dagger/comments{/number}", 270 | "issue_comment_url": "https://api.github.com/repos/google/dagger/issues/comments{/number}", 271 | "contents_url": "https://api.github.com/repos/google/dagger/contents/{+path}", 272 | "compare_url": "https://api.github.com/repos/google/dagger/compare/{base}...{head}", 273 | "merges_url": "https://api.github.com/repos/google/dagger/merges", 274 | "archive_url": "https://api.github.com/repos/google/dagger/{archive_format}{/ref}", 275 | "downloads_url": "https://api.github.com/repos/google/dagger/downloads", 276 | "issues_url": "https://api.github.com/repos/google/dagger/issues{/number}", 277 | "pulls_url": "https://api.github.com/repos/google/dagger/pulls{/number}", 278 | "milestones_url": "https://api.github.com/repos/google/dagger/milestones{/number}", 279 | "notifications_url": "https://api.github.com/repos/google/dagger/notifications{?since,all,participating}", 280 | "labels_url": "https://api.github.com/repos/google/dagger/labels{/name}", 281 | "releases_url": "https://api.github.com/repos/google/dagger/releases{/id}", 282 | "deployments_url": "https://api.github.com/repos/google/dagger/deployments", 283 | "created_at": "2013-02-01T23:14:14Z", 284 | "updated_at": "2019-12-03T12:39:55Z", 285 | "pushed_at": "2019-11-27T21:20:38Z", 286 | "git_url": "git://github.com/google/dagger.git", 287 | "ssh_url": "git@github.com:google/dagger.git", 288 | "clone_url": "https://github.com/google/dagger.git", 289 | "svn_url": "https://github.com/google/dagger", 290 | "homepage": "https://dagger.dev", 291 | "size": 59129, 292 | "stargazers_count": 14492, 293 | "watchers_count": 14492, 294 | "language": "Java", 295 | "has_issues": True, 296 | "has_projects": True, 297 | "has_downloads": True, 298 | "has_wiki": True, 299 | "has_pages": True, 300 | "forks_count": 1741, 301 | "mirror_url": None, 302 | "archived": False, 303 | "disabled": False, 304 | "open_issues_count": 148, 305 | "license": { 306 | "key": "apache-2.0", 307 | "name": "Apache License 2.0", 308 | "spdx_id": "Apache-2.0", 309 | "url": "https://api.github.com/licenses/apache-2.0", 310 | "node_id": "MDc6TGljZW5zZTI=" 311 | }, 312 | "forks": 1741, 313 | "open_issues": 148, 314 | "watchers": 14492, 315 | "default_branch": "master", 316 | "permissions": { 317 | "admin": False, 318 | "push": False, 319 | "pull": True 320 | } 321 | }, 322 | { 323 | "id": 8165161, 324 | "node_id": "MDEwOlJlcG9zaXRvcnk4MTY1MTYx", 325 | "name": "ios-webkit-debug-proxy", 326 | "full_name": "google/ios-webkit-debug-proxy", 327 | "private": False, 328 | "owner": { 329 | "login": "google", 330 | "id": 1342004, 331 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 332 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 333 | "gravatar_id": "", 334 | "url": "https://api.github.com/users/google", 335 | "html_url": "https://github.com/google", 336 | "followers_url": "https://api.github.com/users/google/followers", 337 | "following_url": "https://api.github.com/users/google/following{/other_user}", 338 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 339 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 340 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 341 | "organizations_url": "https://api.github.com/users/google/orgs", 342 | "repos_url": "https://api.github.com/users/google/repos", 343 | "events_url": "https://api.github.com/users/google/events{/privacy}", 344 | "received_events_url": "https://api.github.com/users/google/received_events", 345 | "type": "Organization", 346 | "site_admin": False 347 | }, 348 | "html_url": "https://github.com/google/ios-webkit-debug-proxy", 349 | "description": "A DevTools proxy (Chrome Remote Debugging Protocol) for iOS devices (Safari Remote Web Inspector).", 350 | "fork": False, 351 | "url": "https://api.github.com/repos/google/ios-webkit-debug-proxy", 352 | "forks_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/forks", 353 | "keys_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/keys{/key_id}", 354 | "collaborators_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/collaborators{/collaborator}", 355 | "teams_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/teams", 356 | "hooks_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/hooks", 357 | "issue_events_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues/events{/number}", 358 | "events_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/events", 359 | "assignees_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/assignees{/user}", 360 | "branches_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/branches{/branch}", 361 | "tags_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/tags", 362 | "blobs_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/blobs{/sha}", 363 | "git_tags_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/tags{/sha}", 364 | "git_refs_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/refs{/sha}", 365 | "trees_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/trees{/sha}", 366 | "statuses_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/statuses/{sha}", 367 | "languages_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/languages", 368 | "stargazers_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/stargazers", 369 | "contributors_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/contributors", 370 | "subscribers_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/subscribers", 371 | "subscription_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/subscription", 372 | "commits_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/commits{/sha}", 373 | "git_commits_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/commits{/sha}", 374 | "comments_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/comments{/number}", 375 | "issue_comment_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues/comments{/number}", 376 | "contents_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/contents/{+path}", 377 | "compare_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/compare/{base}...{head}", 378 | "merges_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/merges", 379 | "archive_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/{archive_format}{/ref}", 380 | "downloads_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/downloads", 381 | "issues_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues{/number}", 382 | "pulls_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/pulls{/number}", 383 | "milestones_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/milestones{/number}", 384 | "notifications_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/notifications{?since,all,participating}", 385 | "labels_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/labels{/name}", 386 | "releases_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/releases{/id}", 387 | "deployments_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/deployments", 388 | "created_at": "2013-02-12T19:08:19Z", 389 | "updated_at": "2019-12-04T02:06:43Z", 390 | "pushed_at": "2019-11-24T07:02:13Z", 391 | "git_url": "git://github.com/google/ios-webkit-debug-proxy.git", 392 | "ssh_url": "git@github.com:google/ios-webkit-debug-proxy.git", 393 | "clone_url": "https://github.com/google/ios-webkit-debug-proxy.git", 394 | "svn_url": "https://github.com/google/ios-webkit-debug-proxy", 395 | "homepage": "", 396 | "size": 680, 397 | "stargazers_count": 4630, 398 | "watchers_count": 4630, 399 | "language": "C", 400 | "has_issues": True, 401 | "has_projects": True, 402 | "has_downloads": True, 403 | "has_wiki": False, 404 | "has_pages": False, 405 | "forks_count": 395, 406 | "mirror_url": None, 407 | "archived": False, 408 | "disabled": False, 409 | "open_issues_count": 24, 410 | "license": { 411 | "key": "other", 412 | "name": "Other", 413 | "spdx_id": "NOASSERTION", 414 | "url": None, 415 | "node_id": "MDc6TGljZW5zZTA=" 416 | }, 417 | "forks": 395, 418 | "open_issues": 24, 419 | "watchers": 4630, 420 | "default_branch": "master", 421 | "permissions": { 422 | "admin": False, 423 | "push": False, 424 | "pull": True 425 | } 426 | }, 427 | { 428 | "id": 8459994, 429 | "node_id": "MDEwOlJlcG9zaXRvcnk4NDU5OTk0", 430 | "name": "google.github.io", 431 | "full_name": "google/google.github.io", 432 | "private": False, 433 | "owner": { 434 | "login": "google", 435 | "id": 1342004, 436 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 437 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 438 | "gravatar_id": "", 439 | "url": "https://api.github.com/users/google", 440 | "html_url": "https://github.com/google", 441 | "followers_url": "https://api.github.com/users/google/followers", 442 | "following_url": "https://api.github.com/users/google/following{/other_user}", 443 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 444 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 445 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 446 | "organizations_url": "https://api.github.com/users/google/orgs", 447 | "repos_url": "https://api.github.com/users/google/repos", 448 | "events_url": "https://api.github.com/users/google/events{/privacy}", 449 | "received_events_url": "https://api.github.com/users/google/received_events", 450 | "type": "Organization", 451 | "site_admin": False 452 | }, 453 | "html_url": "https://github.com/google/google.github.io", 454 | "description": None, 455 | "fork": False, 456 | "url": "https://api.github.com/repos/google/google.github.io", 457 | "forks_url": "https://api.github.com/repos/google/google.github.io/forks", 458 | "keys_url": "https://api.github.com/repos/google/google.github.io/keys{/key_id}", 459 | "collaborators_url": "https://api.github.com/repos/google/google.github.io/collaborators{/collaborator}", 460 | "teams_url": "https://api.github.com/repos/google/google.github.io/teams", 461 | "hooks_url": "https://api.github.com/repos/google/google.github.io/hooks", 462 | "issue_events_url": "https://api.github.com/repos/google/google.github.io/issues/events{/number}", 463 | "events_url": "https://api.github.com/repos/google/google.github.io/events", 464 | "assignees_url": "https://api.github.com/repos/google/google.github.io/assignees{/user}", 465 | "branches_url": "https://api.github.com/repos/google/google.github.io/branches{/branch}", 466 | "tags_url": "https://api.github.com/repos/google/google.github.io/tags", 467 | "blobs_url": "https://api.github.com/repos/google/google.github.io/git/blobs{/sha}", 468 | "git_tags_url": "https://api.github.com/repos/google/google.github.io/git/tags{/sha}", 469 | "git_refs_url": "https://api.github.com/repos/google/google.github.io/git/refs{/sha}", 470 | "trees_url": "https://api.github.com/repos/google/google.github.io/git/trees{/sha}", 471 | "statuses_url": "https://api.github.com/repos/google/google.github.io/statuses/{sha}", 472 | "languages_url": "https://api.github.com/repos/google/google.github.io/languages", 473 | "stargazers_url": "https://api.github.com/repos/google/google.github.io/stargazers", 474 | "contributors_url": "https://api.github.com/repos/google/google.github.io/contributors", 475 | "subscribers_url": "https://api.github.com/repos/google/google.github.io/subscribers", 476 | "subscription_url": "https://api.github.com/repos/google/google.github.io/subscription", 477 | "commits_url": "https://api.github.com/repos/google/google.github.io/commits{/sha}", 478 | "git_commits_url": "https://api.github.com/repos/google/google.github.io/git/commits{/sha}", 479 | "comments_url": "https://api.github.com/repos/google/google.github.io/comments{/number}", 480 | "issue_comment_url": "https://api.github.com/repos/google/google.github.io/issues/comments{/number}", 481 | "contents_url": "https://api.github.com/repos/google/google.github.io/contents/{+path}", 482 | "compare_url": "https://api.github.com/repos/google/google.github.io/compare/{base}...{head}", 483 | "merges_url": "https://api.github.com/repos/google/google.github.io/merges", 484 | "archive_url": "https://api.github.com/repos/google/google.github.io/{archive_format}{/ref}", 485 | "downloads_url": "https://api.github.com/repos/google/google.github.io/downloads", 486 | "issues_url": "https://api.github.com/repos/google/google.github.io/issues{/number}", 487 | "pulls_url": "https://api.github.com/repos/google/google.github.io/pulls{/number}", 488 | "milestones_url": "https://api.github.com/repos/google/google.github.io/milestones{/number}", 489 | "notifications_url": "https://api.github.com/repos/google/google.github.io/notifications{?since,all,participating}", 490 | "labels_url": "https://api.github.com/repos/google/google.github.io/labels{/name}", 491 | "releases_url": "https://api.github.com/repos/google/google.github.io/releases{/id}", 492 | "deployments_url": "https://api.github.com/repos/google/google.github.io/deployments", 493 | "created_at": "2013-02-27T16:21:19Z", 494 | "updated_at": "2019-12-03T01:38:02Z", 495 | "pushed_at": "2019-12-03T01:37:58Z", 496 | "git_url": "git://github.com/google/google.github.io.git", 497 | "ssh_url": "git@github.com:google/google.github.io.git", 498 | "clone_url": "https://github.com/google/google.github.io.git", 499 | "svn_url": "https://github.com/google/google.github.io", 500 | "homepage": None, 501 | "size": 8, 502 | "stargazers_count": 38, 503 | "watchers_count": 38, 504 | "language": "HTML", 505 | "has_issues": False, 506 | "has_projects": True, 507 | "has_downloads": True, 508 | "has_wiki": False, 509 | "has_pages": True, 510 | "forks_count": 44, 511 | "mirror_url": None, 512 | "archived": False, 513 | "disabled": False, 514 | "open_issues_count": 0, 515 | "license": None, 516 | "forks": 44, 517 | "open_issues": 0, 518 | "watchers": 38, 519 | "default_branch": "master", 520 | "permissions": { 521 | "admin": False, 522 | "push": False, 523 | "pull": True 524 | } 525 | }, 526 | { 527 | "id": 8566972, 528 | "node_id": "MDEwOlJlcG9zaXRvcnk4NTY2OTcy", 529 | "name": "kratu", 530 | "full_name": "google/kratu", 531 | "private": False, 532 | "owner": { 533 | "login": "google", 534 | "id": 1342004, 535 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 536 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 537 | "gravatar_id": "", 538 | "url": "https://api.github.com/users/google", 539 | "html_url": "https://github.com/google", 540 | "followers_url": "https://api.github.com/users/google/followers", 541 | "following_url": "https://api.github.com/users/google/following{/other_user}", 542 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 543 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 544 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 545 | "organizations_url": "https://api.github.com/users/google/orgs", 546 | "repos_url": "https://api.github.com/users/google/repos", 547 | "events_url": "https://api.github.com/users/google/events{/privacy}", 548 | "received_events_url": "https://api.github.com/users/google/received_events", 549 | "type": "Organization", 550 | "site_admin": False 551 | }, 552 | "html_url": "https://github.com/google/kratu", 553 | "description": None, 554 | "fork": False, 555 | "url": "https://api.github.com/repos/google/kratu", 556 | "forks_url": "https://api.github.com/repos/google/kratu/forks", 557 | "keys_url": "https://api.github.com/repos/google/kratu/keys{/key_id}", 558 | "collaborators_url": "https://api.github.com/repos/google/kratu/collaborators{/collaborator}", 559 | "teams_url": "https://api.github.com/repos/google/kratu/teams", 560 | "hooks_url": "https://api.github.com/repos/google/kratu/hooks", 561 | "issue_events_url": "https://api.github.com/repos/google/kratu/issues/events{/number}", 562 | "events_url": "https://api.github.com/repos/google/kratu/events", 563 | "assignees_url": "https://api.github.com/repos/google/kratu/assignees{/user}", 564 | "branches_url": "https://api.github.com/repos/google/kratu/branches{/branch}", 565 | "tags_url": "https://api.github.com/repos/google/kratu/tags", 566 | "blobs_url": "https://api.github.com/repos/google/kratu/git/blobs{/sha}", 567 | "git_tags_url": "https://api.github.com/repos/google/kratu/git/tags{/sha}", 568 | "git_refs_url": "https://api.github.com/repos/google/kratu/git/refs{/sha}", 569 | "trees_url": "https://api.github.com/repos/google/kratu/git/trees{/sha}", 570 | "statuses_url": "https://api.github.com/repos/google/kratu/statuses/{sha}", 571 | "languages_url": "https://api.github.com/repos/google/kratu/languages", 572 | "stargazers_url": "https://api.github.com/repos/google/kratu/stargazers", 573 | "contributors_url": "https://api.github.com/repos/google/kratu/contributors", 574 | "subscribers_url": "https://api.github.com/repos/google/kratu/subscribers", 575 | "subscription_url": "https://api.github.com/repos/google/kratu/subscription", 576 | "commits_url": "https://api.github.com/repos/google/kratu/commits{/sha}", 577 | "git_commits_url": "https://api.github.com/repos/google/kratu/git/commits{/sha}", 578 | "comments_url": "https://api.github.com/repos/google/kratu/comments{/number}", 579 | "issue_comment_url": "https://api.github.com/repos/google/kratu/issues/comments{/number}", 580 | "contents_url": "https://api.github.com/repos/google/kratu/contents/{+path}", 581 | "compare_url": "https://api.github.com/repos/google/kratu/compare/{base}...{head}", 582 | "merges_url": "https://api.github.com/repos/google/kratu/merges", 583 | "archive_url": "https://api.github.com/repos/google/kratu/{archive_format}{/ref}", 584 | "downloads_url": "https://api.github.com/repos/google/kratu/downloads", 585 | "issues_url": "https://api.github.com/repos/google/kratu/issues{/number}", 586 | "pulls_url": "https://api.github.com/repos/google/kratu/pulls{/number}", 587 | "milestones_url": "https://api.github.com/repos/google/kratu/milestones{/number}", 588 | "notifications_url": "https://api.github.com/repos/google/kratu/notifications{?since,all,participating}", 589 | "labels_url": "https://api.github.com/repos/google/kratu/labels{/name}", 590 | "releases_url": "https://api.github.com/repos/google/kratu/releases{/id}", 591 | "deployments_url": "https://api.github.com/repos/google/kratu/deployments", 592 | "created_at": "2013-03-04T22:52:33Z", 593 | "updated_at": "2019-11-15T22:22:16Z", 594 | "pushed_at": "2017-08-06T05:44:34Z", 595 | "git_url": "git://github.com/google/kratu.git", 596 | "ssh_url": "git@github.com:google/kratu.git", 597 | "clone_url": "https://github.com/google/kratu.git", 598 | "svn_url": "https://github.com/google/kratu", 599 | "homepage": None, 600 | "size": 1777, 601 | "stargazers_count": 280, 602 | "watchers_count": 280, 603 | "language": "JavaScript", 604 | "has_issues": True, 605 | "has_projects": True, 606 | "has_downloads": True, 607 | "has_wiki": True, 608 | "has_pages": True, 609 | "forks_count": 32, 610 | "mirror_url": None, 611 | "archived": False, 612 | "disabled": False, 613 | "open_issues_count": 0, 614 | "license": { 615 | "key": "apache-2.0", 616 | "name": "Apache License 2.0", 617 | "spdx_id": "Apache-2.0", 618 | "url": "https://api.github.com/licenses/apache-2.0", 619 | "node_id": "MDc6TGljZW5zZTI=" 620 | }, 621 | "forks": 32, 622 | "open_issues": 0, 623 | "watchers": 280, 624 | "default_branch": "master", 625 | "permissions": { 626 | "admin": False, 627 | "push": False, 628 | "pull": True 629 | } 630 | }, 631 | { 632 | "id": 8858648, 633 | "node_id": "MDEwOlJlcG9zaXRvcnk4ODU4NjQ4", 634 | "name": "build-debian-cloud", 635 | "full_name": "google/build-debian-cloud", 636 | "private": False, 637 | "owner": { 638 | "login": "google", 639 | "id": 1342004, 640 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 641 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 642 | "gravatar_id": "", 643 | "url": "https://api.github.com/users/google", 644 | "html_url": "https://github.com/google", 645 | "followers_url": "https://api.github.com/users/google/followers", 646 | "following_url": "https://api.github.com/users/google/following{/other_user}", 647 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 648 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 649 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 650 | "organizations_url": "https://api.github.com/users/google/orgs", 651 | "repos_url": "https://api.github.com/users/google/repos", 652 | "events_url": "https://api.github.com/users/google/events{/privacy}", 653 | "received_events_url": "https://api.github.com/users/google/received_events", 654 | "type": "Organization", 655 | "site_admin": False 656 | }, 657 | "html_url": "https://github.com/google/build-debian-cloud", 658 | "description": "Script to create Debian Squeeze & Wheezy Amazon Machine Images (AMIs) and Google Compute Engine images", 659 | "fork": True, 660 | "url": "https://api.github.com/repos/google/build-debian-cloud", 661 | "forks_url": "https://api.github.com/repos/google/build-debian-cloud/forks", 662 | "keys_url": "https://api.github.com/repos/google/build-debian-cloud/keys{/key_id}", 663 | "collaborators_url": "https://api.github.com/repos/google/build-debian-cloud/collaborators{/collaborator}", 664 | "teams_url": "https://api.github.com/repos/google/build-debian-cloud/teams", 665 | "hooks_url": "https://api.github.com/repos/google/build-debian-cloud/hooks", 666 | "issue_events_url": "https://api.github.com/repos/google/build-debian-cloud/issues/events{/number}", 667 | "events_url": "https://api.github.com/repos/google/build-debian-cloud/events", 668 | "assignees_url": "https://api.github.com/repos/google/build-debian-cloud/assignees{/user}", 669 | "branches_url": "https://api.github.com/repos/google/build-debian-cloud/branches{/branch}", 670 | "tags_url": "https://api.github.com/repos/google/build-debian-cloud/tags", 671 | "blobs_url": "https://api.github.com/repos/google/build-debian-cloud/git/blobs{/sha}", 672 | "git_tags_url": "https://api.github.com/repos/google/build-debian-cloud/git/tags{/sha}", 673 | "git_refs_url": "https://api.github.com/repos/google/build-debian-cloud/git/refs{/sha}", 674 | "trees_url": "https://api.github.com/repos/google/build-debian-cloud/git/trees{/sha}", 675 | "statuses_url": "https://api.github.com/repos/google/build-debian-cloud/statuses/{sha}", 676 | "languages_url": "https://api.github.com/repos/google/build-debian-cloud/languages", 677 | "stargazers_url": "https://api.github.com/repos/google/build-debian-cloud/stargazers", 678 | "contributors_url": "https://api.github.com/repos/google/build-debian-cloud/contributors", 679 | "subscribers_url": "https://api.github.com/repos/google/build-debian-cloud/subscribers", 680 | "subscription_url": "https://api.github.com/repos/google/build-debian-cloud/subscription", 681 | "commits_url": "https://api.github.com/repos/google/build-debian-cloud/commits{/sha}", 682 | "git_commits_url": "https://api.github.com/repos/google/build-debian-cloud/git/commits{/sha}", 683 | "comments_url": "https://api.github.com/repos/google/build-debian-cloud/comments{/number}", 684 | "issue_comment_url": "https://api.github.com/repos/google/build-debian-cloud/issues/comments{/number}", 685 | "contents_url": "https://api.github.com/repos/google/build-debian-cloud/contents/{+path}", 686 | "compare_url": "https://api.github.com/repos/google/build-debian-cloud/compare/{base}...{head}", 687 | "merges_url": "https://api.github.com/repos/google/build-debian-cloud/merges", 688 | "archive_url": "https://api.github.com/repos/google/build-debian-cloud/{archive_format}{/ref}", 689 | "downloads_url": "https://api.github.com/repos/google/build-debian-cloud/downloads", 690 | "issues_url": "https://api.github.com/repos/google/build-debian-cloud/issues{/number}", 691 | "pulls_url": "https://api.github.com/repos/google/build-debian-cloud/pulls{/number}", 692 | "milestones_url": "https://api.github.com/repos/google/build-debian-cloud/milestones{/number}", 693 | "notifications_url": "https://api.github.com/repos/google/build-debian-cloud/notifications{?since,all,participating}", 694 | "labels_url": "https://api.github.com/repos/google/build-debian-cloud/labels{/name}", 695 | "releases_url": "https://api.github.com/repos/google/build-debian-cloud/releases{/id}", 696 | "deployments_url": "https://api.github.com/repos/google/build-debian-cloud/deployments", 697 | "created_at": "2013-03-18T16:32:00Z", 698 | "updated_at": "2019-09-23T11:54:00Z", 699 | "pushed_at": "2014-06-17T18:52:10Z", 700 | "git_url": "git://github.com/google/build-debian-cloud.git", 701 | "ssh_url": "git@github.com:google/build-debian-cloud.git", 702 | "clone_url": "https://github.com/google/build-debian-cloud.git", 703 | "svn_url": "https://github.com/google/build-debian-cloud", 704 | "homepage": "", 705 | "size": 986, 706 | "stargazers_count": 32, 707 | "watchers_count": 32, 708 | "language": "Shell", 709 | "has_issues": False, 710 | "has_projects": True, 711 | "has_downloads": True, 712 | "has_wiki": False, 713 | "has_pages": False, 714 | "forks_count": 22, 715 | "mirror_url": None, 716 | "archived": False, 717 | "disabled": False, 718 | "open_issues_count": 5, 719 | "license": { 720 | "key": "other", 721 | "name": "Other", 722 | "spdx_id": "NOASSERTION", 723 | "url": None, 724 | "node_id": "MDc6TGljZW5zZTA=" 725 | }, 726 | "forks": 22, 727 | "open_issues": 5, 728 | "watchers": 32, 729 | "default_branch": "master", 730 | "permissions": { 731 | "admin": False, 732 | "push": False, 733 | "pull": True 734 | } 735 | }, 736 | { 737 | "id": 9060347, 738 | "node_id": "MDEwOlJlcG9zaXRvcnk5MDYwMzQ3", 739 | "name": "traceur-compiler", 740 | "full_name": "google/traceur-compiler", 741 | "private": False, 742 | "owner": { 743 | "login": "google", 744 | "id": 1342004, 745 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 746 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 747 | "gravatar_id": "", 748 | "url": "https://api.github.com/users/google", 749 | "html_url": "https://github.com/google", 750 | "followers_url": "https://api.github.com/users/google/followers", 751 | "following_url": "https://api.github.com/users/google/following{/other_user}", 752 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 753 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 754 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 755 | "organizations_url": "https://api.github.com/users/google/orgs", 756 | "repos_url": "https://api.github.com/users/google/repos", 757 | "events_url": "https://api.github.com/users/google/events{/privacy}", 758 | "received_events_url": "https://api.github.com/users/google/received_events", 759 | "type": "Organization", 760 | "site_admin": False 761 | }, 762 | "html_url": "https://github.com/google/traceur-compiler", 763 | "description": "Traceur is a JavaScript.next-to-JavaScript-of-today compiler", 764 | "fork": False, 765 | "url": "https://api.github.com/repos/google/traceur-compiler", 766 | "forks_url": "https://api.github.com/repos/google/traceur-compiler/forks", 767 | "keys_url": "https://api.github.com/repos/google/traceur-compiler/keys{/key_id}", 768 | "collaborators_url": "https://api.github.com/repos/google/traceur-compiler/collaborators{/collaborator}", 769 | "teams_url": "https://api.github.com/repos/google/traceur-compiler/teams", 770 | "hooks_url": "https://api.github.com/repos/google/traceur-compiler/hooks", 771 | "issue_events_url": "https://api.github.com/repos/google/traceur-compiler/issues/events{/number}", 772 | "events_url": "https://api.github.com/repos/google/traceur-compiler/events", 773 | "assignees_url": "https://api.github.com/repos/google/traceur-compiler/assignees{/user}", 774 | "branches_url": "https://api.github.com/repos/google/traceur-compiler/branches{/branch}", 775 | "tags_url": "https://api.github.com/repos/google/traceur-compiler/tags", 776 | "blobs_url": "https://api.github.com/repos/google/traceur-compiler/git/blobs{/sha}", 777 | "git_tags_url": "https://api.github.com/repos/google/traceur-compiler/git/tags{/sha}", 778 | "git_refs_url": "https://api.github.com/repos/google/traceur-compiler/git/refs{/sha}", 779 | "trees_url": "https://api.github.com/repos/google/traceur-compiler/git/trees{/sha}", 780 | "statuses_url": "https://api.github.com/repos/google/traceur-compiler/statuses/{sha}", 781 | "languages_url": "https://api.github.com/repos/google/traceur-compiler/languages", 782 | "stargazers_url": "https://api.github.com/repos/google/traceur-compiler/stargazers", 783 | "contributors_url": "https://api.github.com/repos/google/traceur-compiler/contributors", 784 | "subscribers_url": "https://api.github.com/repos/google/traceur-compiler/subscribers", 785 | "subscription_url": "https://api.github.com/repos/google/traceur-compiler/subscription", 786 | "commits_url": "https://api.github.com/repos/google/traceur-compiler/commits{/sha}", 787 | "git_commits_url": "https://api.github.com/repos/google/traceur-compiler/git/commits{/sha}", 788 | "comments_url": "https://api.github.com/repos/google/traceur-compiler/comments{/number}", 789 | "issue_comment_url": "https://api.github.com/repos/google/traceur-compiler/issues/comments{/number}", 790 | "contents_url": "https://api.github.com/repos/google/traceur-compiler/contents/{+path}", 791 | "compare_url": "https://api.github.com/repos/google/traceur-compiler/compare/{base}...{head}", 792 | "merges_url": "https://api.github.com/repos/google/traceur-compiler/merges", 793 | "archive_url": "https://api.github.com/repos/google/traceur-compiler/{archive_format}{/ref}", 794 | "downloads_url": "https://api.github.com/repos/google/traceur-compiler/downloads", 795 | "issues_url": "https://api.github.com/repos/google/traceur-compiler/issues{/number}", 796 | "pulls_url": "https://api.github.com/repos/google/traceur-compiler/pulls{/number}", 797 | "milestones_url": "https://api.github.com/repos/google/traceur-compiler/milestones{/number}", 798 | "notifications_url": "https://api.github.com/repos/google/traceur-compiler/notifications{?since,all,participating}", 799 | "labels_url": "https://api.github.com/repos/google/traceur-compiler/labels{/name}", 800 | "releases_url": "https://api.github.com/repos/google/traceur-compiler/releases{/id}", 801 | "deployments_url": "https://api.github.com/repos/google/traceur-compiler/deployments", 802 | "created_at": "2013-03-27T18:05:40Z", 803 | "updated_at": "2019-12-02T16:45:54Z", 804 | "pushed_at": "2018-05-28T04:37:54Z", 805 | "git_url": "git://github.com/google/traceur-compiler.git", 806 | "ssh_url": "git@github.com:google/traceur-compiler.git", 807 | "clone_url": "https://github.com/google/traceur-compiler.git", 808 | "svn_url": "https://github.com/google/traceur-compiler", 809 | "homepage": "", 810 | "size": 27487, 811 | "stargazers_count": 8033, 812 | "watchers_count": 8033, 813 | "language": "JavaScript", 814 | "has_issues": True, 815 | "has_projects": True, 816 | "has_downloads": True, 817 | "has_wiki": True, 818 | "has_pages": True, 819 | "forks_count": 604, 820 | "mirror_url": None, 821 | "archived": False, 822 | "disabled": False, 823 | "open_issues_count": 296, 824 | "license": { 825 | "key": "apache-2.0", 826 | "name": "Apache License 2.0", 827 | "spdx_id": "Apache-2.0", 828 | "url": "https://api.github.com/licenses/apache-2.0", 829 | "node_id": "MDc6TGljZW5zZTI=" 830 | }, 831 | "forks": 604, 832 | "open_issues": 296, 833 | "watchers": 8033, 834 | "default_branch": "master", 835 | "permissions": { 836 | "admin": False, 837 | "push": False, 838 | "pull": True 839 | } 840 | }, 841 | { 842 | "id": 9065917, 843 | "node_id": "MDEwOlJlcG9zaXRvcnk5MDY1OTE3", 844 | "name": "firmata.py", 845 | "full_name": "google/firmata.py", 846 | "private": False, 847 | "owner": { 848 | "login": "google", 849 | "id": 1342004, 850 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=", 851 | "avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4", 852 | "gravatar_id": "", 853 | "url": "https://api.github.com/users/google", 854 | "html_url": "https://github.com/google", 855 | "followers_url": "https://api.github.com/users/google/followers", 856 | "following_url": "https://api.github.com/users/google/following{/other_user}", 857 | "gists_url": "https://api.github.com/users/google/gists{/gist_id}", 858 | "starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}", 859 | "subscriptions_url": "https://api.github.com/users/google/subscriptions", 860 | "organizations_url": "https://api.github.com/users/google/orgs", 861 | "repos_url": "https://api.github.com/users/google/repos", 862 | "events_url": "https://api.github.com/users/google/events{/privacy}", 863 | "received_events_url": "https://api.github.com/users/google/received_events", 864 | "type": "Organization", 865 | "site_admin": False 866 | }, 867 | "html_url": "https://github.com/google/firmata.py", 868 | "description": None, 869 | "fork": False, 870 | "url": "https://api.github.com/repos/google/firmata.py", 871 | "forks_url": "https://api.github.com/repos/google/firmata.py/forks", 872 | "keys_url": "https://api.github.com/repos/google/firmata.py/keys{/key_id}", 873 | "collaborators_url": "https://api.github.com/repos/google/firmata.py/collaborators{/collaborator}", 874 | "teams_url": "https://api.github.com/repos/google/firmata.py/teams", 875 | "hooks_url": "https://api.github.com/repos/google/firmata.py/hooks", 876 | "issue_events_url": "https://api.github.com/repos/google/firmata.py/issues/events{/number}", 877 | "events_url": "https://api.github.com/repos/google/firmata.py/events", 878 | "assignees_url": "https://api.github.com/repos/google/firmata.py/assignees{/user}", 879 | "branches_url": "https://api.github.com/repos/google/firmata.py/branches{/branch}", 880 | "tags_url": "https://api.github.com/repos/google/firmata.py/tags", 881 | "blobs_url": "https://api.github.com/repos/google/firmata.py/git/blobs{/sha}", 882 | "git_tags_url": "https://api.github.com/repos/google/firmata.py/git/tags{/sha}", 883 | "git_refs_url": "https://api.github.com/repos/google/firmata.py/git/refs{/sha}", 884 | "trees_url": "https://api.github.com/repos/google/firmata.py/git/trees{/sha}", 885 | "statuses_url": "https://api.github.com/repos/google/firmata.py/statuses/{sha}", 886 | "languages_url": "https://api.github.com/repos/google/firmata.py/languages", 887 | "stargazers_url": "https://api.github.com/repos/google/firmata.py/stargazers", 888 | "contributors_url": "https://api.github.com/repos/google/firmata.py/contributors", 889 | "subscribers_url": "https://api.github.com/repos/google/firmata.py/subscribers", 890 | "subscription_url": "https://api.github.com/repos/google/firmata.py/subscription", 891 | "commits_url": "https://api.github.com/repos/google/firmata.py/commits{/sha}", 892 | "git_commits_url": "https://api.github.com/repos/google/firmata.py/git/commits{/sha}", 893 | "comments_url": "https://api.github.com/repos/google/firmata.py/comments{/number}", 894 | "issue_comment_url": "https://api.github.com/repos/google/firmata.py/issues/comments{/number}", 895 | "contents_url": "https://api.github.com/repos/google/firmata.py/contents/{+path}", 896 | "compare_url": "https://api.github.com/repos/google/firmata.py/compare/{base}...{head}", 897 | "merges_url": "https://api.github.com/repos/google/firmata.py/merges", 898 | "archive_url": "https://api.github.com/repos/google/firmata.py/{archive_format}{/ref}", 899 | "downloads_url": "https://api.github.com/repos/google/firmata.py/downloads", 900 | "issues_url": "https://api.github.com/repos/google/firmata.py/issues{/number}", 901 | "pulls_url": "https://api.github.com/repos/google/firmata.py/pulls{/number}", 902 | "milestones_url": "https://api.github.com/repos/google/firmata.py/milestones{/number}", 903 | "notifications_url": "https://api.github.com/repos/google/firmata.py/notifications{?since,all,participating}", 904 | "labels_url": "https://api.github.com/repos/google/firmata.py/labels{/name}", 905 | "releases_url": "https://api.github.com/repos/google/firmata.py/releases{/id}", 906 | "deployments_url": "https://api.github.com/repos/google/firmata.py/deployments", 907 | "created_at": "2013-03-27T23:20:35Z", 908 | "updated_at": "2019-09-23T11:54:02Z", 909 | "pushed_at": "2013-03-27T23:34:35Z", 910 | "git_url": "git://github.com/google/firmata.py.git", 911 | "ssh_url": "git@github.com:google/firmata.py.git", 912 | "clone_url": "https://github.com/google/firmata.py.git", 913 | "svn_url": "https://github.com/google/firmata.py", 914 | "homepage": None, 915 | "size": 160, 916 | "stargazers_count": 15, 917 | "watchers_count": 15, 918 | "language": "Python", 919 | "has_issues": True, 920 | "has_projects": True, 921 | "has_downloads": True, 922 | "has_wiki": True, 923 | "has_pages": False, 924 | "forks_count": 15, 925 | "mirror_url": None, 926 | "archived": False, 927 | "disabled": False, 928 | "open_issues_count": 0, 929 | "license": { 930 | "key": "apache-2.0", 931 | "name": "Apache License 2.0", 932 | "spdx_id": "Apache-2.0", 933 | "url": "https://api.github.com/licenses/apache-2.0", 934 | "node_id": "MDc6TGljZW5zZTI=" 935 | }, 936 | "forks": 15, 937 | "open_issues": 0, 938 | "watchers": 15, 939 | "default_branch": "master", 940 | "permissions": { 941 | "admin": False, 942 | "push": False, 943 | "pull": True 944 | } 945 | } 946 | ], 947 | ['episodes.dart', 'cpp-netlib', 'dagger', 'ios-webkit-debug-proxy', 'google.github.io', 'kratu', 'build-debian-cloud', 'traceur-compiler', 'firmata.py'], 948 | ['dagger', 'kratu', 'traceur-compiler', 'firmata.py'], 949 | ) 950 | ] 951 | -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/test_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Unittests and integration tests """ 3 | 4 | from client import GithubOrgClient 5 | from fixtures import TEST_PAYLOAD 6 | from parameterized import parameterized, parameterized_class 7 | import unittest 8 | from unittest.mock import patch, PropertyMock 9 | 10 | 11 | class TestGithubOrgClient(unittest.TestCase): 12 | """ Class Testing Github Org Client """ 13 | 14 | @parameterized.expand([ 15 | ('google'), 16 | ('abc') 17 | ]) 18 | @patch('client.get_json') 19 | def test_org(self, input, mock): 20 | """Test that GithubOrgClient.org returns the correct value""" 21 | test_class = GithubOrgClient(input) 22 | test_class.org() 23 | mock.called_with_once(test_class.ORG_URL.format(org=input)) 24 | 25 | def test_public_repos_url(self): 26 | """ Test that the result of _public_repos_url 27 | return the correct value based on the given payload 28 | """ 29 | with patch('client.GithubOrgClient.org', 30 | new_callable=PropertyMock) as mock: 31 | payload = {"repos_url": "Hello World"} 32 | mock.return_value = payload 33 | test_class = GithubOrgClient('test') 34 | result = test_class._public_repos_url 35 | self.assertEqual(result, payload["repos_url"]) 36 | 37 | @patch('client.get_json') 38 | def test_public_repos(self, mock_json): 39 | """ 40 | this method unit-test GithubOrgClient.public_repos 41 | Test that the list of repos is what you expect from the chosen payload. 42 | Test that the mocked property and the mocked get_json was called once. 43 | """ 44 | payload = [{"name": "Google"}, {"name": "Twitter"}] 45 | mock_json.return_value = payload 46 | 47 | with patch('client.GithubOrgClient._public_repos_url', 48 | new_callable=PropertyMock) as mock_public: 49 | 50 | mock_public.return_value = "hello world" 51 | test_class = GithubOrgClient('test') 52 | result = test_class.public_repos() 53 | 54 | expected = [item["name"] for item in payload] 55 | self.assertEqual(result, expected) 56 | 57 | mock_public.assert_called_once() 58 | mock_json.assert_called_once() 59 | 60 | @parameterized.expand([ 61 | ({"license": {"key": "my_license"}}, "my_license", True), 62 | ({"license": {"key": "other_license"}}, "my_license", False) 63 | ]) 64 | def test_has_license(self, repo, license_key, expected): 65 | """ unit-test for GithubOrgClient.has_license """ 66 | result = GithubOrgClient.has_license(repo, license_key) 67 | self.assertEqual(result, expected) 68 | 69 | 70 | @parameterized_class( 71 | ("org_payload", "repos_payload", "expected_repos", "apache2_repos"), 72 | TEST_PAYLOAD 73 | ) 74 | class TestIntegrationGithubOrgClient(unittest.TestCase): 75 | """ Class - Integration test of fixtures """ 76 | @classmethod 77 | def setUpClass(cls): 78 | """method called before tests in an individual class are run""" 79 | config = {'return_value.json.side_effect': 80 | [ 81 | cls.org_payload, cls.repos_payload, 82 | cls.org_payload, cls.repos_payload 83 | ] 84 | } 85 | cls.get_patcher = patch('requests.get', **config) 86 | cls.mock = cls.get_patcher.start() 87 | 88 | def test_public_repos(self): 89 | """ Integration test: public repos""" 90 | test_class = GithubOrgClient("google") 91 | 92 | self.assertEqual(test_class.org, self.org_payload) 93 | self.assertEqual(test_class.repos_payload, self.repos_payload) 94 | self.assertEqual(test_class.public_repos(), self.expected_repos) 95 | self.assertEqual(test_class.public_repos("XLICENSE"), []) 96 | self.mock.assert_called() 97 | 98 | def test_public_repos_with_license(self): 99 | """ Integration test for public repos with License """ 100 | test_class = GithubOrgClient("google") 101 | 102 | self.assertEqual(test_class.public_repos(), self.expected_repos) 103 | self.assertEqual(test_class.public_repos("XLICENSE"), []) 104 | self.assertEqual(test_class.public_repos( 105 | "apache-2.0"), self.apache2_repos) 106 | self.mock.assert_called() 107 | 108 | @classmethod 109 | def tearDownClass(cls): 110 | """method called after tests in an individual class have run""" 111 | cls.get_patcher.stop() 112 | -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/test_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Test for access_nested_map function 4 | """ 5 | import unittest 6 | import requests 7 | from unittest.mock import patch 8 | from utils import access_nested_map, get_json, memoize 9 | from typing import Mapping, Sequence, Any 10 | from parameterized import parameterized 11 | 12 | 13 | class TestAccessNestedMap(unittest.TestCase): 14 | """ 15 | Tests the access_nested_map function 16 | """ 17 | @parameterized.expand([ 18 | ({"a": 1}, ("a",), 1), 19 | ({"a": {"b": 2}}, ("a",), {"b": 2}), 20 | ({"a": {"b": 2}}, ("a", "b"), 2) 21 | ]) 22 | def test_access_nested_map(self, nested_map: Mapping, 23 | path: Sequence, expected: int) -> None: 24 | """ 25 | Test the access_nested_map method. 26 | Args: 27 | nested_map (Dict): A dictionary that may have nested dictionaries 28 | path (List, tuple, set): Keys to get to the required value in the 29 | nested dictionary 30 | """ 31 | response = access_nested_map(nested_map, path) 32 | self.assertEqual(response, expected) 33 | 34 | @parameterized.expand([ 35 | ({}, ("a",)), 36 | ({"a": 1}, ("a", "b")) 37 | ]) 38 | def test_access_nested_map_exception(self, nested_map: Mapping, 39 | path: Sequence) -> None: 40 | """ 41 | Test the access_nested_map method raises an error when expected to 42 | Args: 43 | nested_map (Dict): A dictionary that may have nested dictionaries 44 | path (List, tuple, set): Keys to get to the required value in the 45 | nested dictionary 46 | """ 47 | with self.assertRaises(Exception): 48 | access_nested_map(nested_map, path) 49 | 50 | 51 | class TestGetJson(unittest.TestCase): 52 | """ 53 | Test the get_json function 54 | """ 55 | @parameterized.expand([ 56 | ("http://example.com", {"payload": True}), 57 | ("http://holberton.io", {"payload": False}) 58 | ]) 59 | @patch("requests.get") 60 | def test_get_json(self, test_url, test_payload, mock_requests_get): 61 | """ 62 | Test the get_json method to ensure it returns the expected output. 63 | Args: 64 | url: url to send http request to 65 | payload: expected json response 66 | """ 67 | mock_requests_get.return_value.json.return_value = test_payload 68 | result = get_json(test_url) 69 | self.assertEqual(result, test_payload) 70 | mock_requests_get.assert_called_once_with(test_url) 71 | 72 | 73 | class TestMemoize(unittest.TestCase): 74 | """ 75 | Test the memoization decorator, memoize 76 | """ 77 | def test_memoize(self): 78 | """ 79 | Test that utils.memoize decorator works as intended 80 | """ 81 | class TestClass: 82 | 83 | def a_method(self): 84 | return 42 85 | 86 | @memoize 87 | def a_property(self): 88 | return self.a_method() 89 | with patch.object(TestClass, 'a_method') as mock_object: 90 | test = TestClass() 91 | test.a_property() 92 | test.a_property() 93 | mock_object.assert_called_once() 94 | -------------------------------------------------------------------------------- /0x03-Unittests_and_integration_tests/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Generic utilities for github org client. 3 | """ 4 | import requests 5 | from functools import wraps 6 | from typing import ( 7 | Mapping, 8 | Sequence, 9 | Any, 10 | Dict, 11 | Callable, 12 | ) 13 | 14 | __all__ = [ 15 | "access_nested_map", 16 | "get_json", 17 | "memoize", 18 | ] 19 | 20 | 21 | def access_nested_map(nested_map: Mapping, path: Sequence) -> Any: 22 | """Access nested map with key path. 23 | Parameters 24 | ---------- 25 | nested_map: Mapping 26 | A nested map 27 | path: Sequence 28 | a sequence of key representing a path to the value 29 | Example 30 | ------- 31 | >>> nested_map = {"a": {"b": {"c": 1}}} 32 | >>> access_nested_map(nested_map, ["a", "b", "c"]) 33 | 1 34 | """ 35 | for key in path: 36 | if not isinstance(nested_map, Mapping): 37 | raise KeyError(key) 38 | nested_map = nested_map[key] 39 | 40 | return nested_map 41 | 42 | 43 | def get_json(url: str) -> Dict: 44 | """Get JSON from remote URL. 45 | """ 46 | response = requests.get(url) 47 | return response.json() 48 | 49 | 50 | def memoize(fn: Callable) -> Callable: 51 | """Decorator to memoize a method. 52 | Example 53 | ------- 54 | class MyClass: 55 | @memoize 56 | def a_method(self): 57 | print("a_method called") 58 | return 42 59 | >>> my_object = MyClass() 60 | >>> my_object.a_method 61 | a_method called 62 | 42 63 | >>> my_object.a_method 64 | 42 65 | """ 66 | attr_name = "_{}".format(fn.__name__) 67 | 68 | @wraps(fn) 69 | def memoized(self): 70 | """"memoized wraps""" 71 | if not hasattr(self, attr_name): 72 | setattr(self, attr_name, fn(self)) 73 | return getattr(self, attr_name) 74 | 75 | return property(memoized) 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Variable Annotations Project 2 | 3 | ## Learning Objectives 4 | 5 | By the end of this project, you will gain knowledge and skills in the following areas: 6 | 7 | - Understanding type annotations in Python 3. 8 | - Using type annotations to specify function signatures and variable types. 9 | - Exploring the concept of duck typing in Python. 10 | - Validating your code for type correctness using Mypy. 11 | 12 | ## Requirements 13 | 14 | ### General 15 | 16 | - **Editors**: You are allowed to use vi, vim, or emacs for coding. 17 | - **Python Version**: All code will be interpreted/compiled using Python 3 (version 3.7). 18 | - **File Endings**: Ensure that all your files end with a newline character. 19 | - **Shebang Line**: The first line of all your Python files should be exactly `#!/usr/bin/env python3`. 20 | - **README.md**: A mandatory README.md file must be present at the root of your project folder. 21 | - **Code Style**: Your code should adhere to the pycodestyle style (version 2.5). 22 | - **Executable Files**: All your Python files must be executable. 23 | - **File Length**: The length of your files will be tested using `wc`. 24 | - **Documentation**: 25 | - All your modules should have documentation. You can check this using `python3 -c 'print(__import__("my_module").__doc__)'`. 26 | - All your classes should have documentation. You can check this using `python3 -c 'print(__import__("my_module").MyClass.__doc__)'`. 27 | - All your functions, both inside and outside a class, should have documentation. You can check this using `python3 -c 'print(__import__("my_module").my_function.__doc__)'` and `python3 -c 'print(__import__("my_module").MyClass.my_function.__doc__)'`. 28 | 29 | ### Documentation Guidelines 30 | 31 | - A documentation is not just a single word; it should be a complete sentence that explains the purpose of the module, class, or method. The length of your documentation will be verified. 32 | 33 | ## Project Overview 34 | 35 | This project is designed to help you improve your Python programming skills with a focus on variable annotations and type hinting. You will learn how to specify data types for variables, function parameters, and return values using type annotations. Additionally, you will explore the concept of duck typing and how to use the Mypy tool to validate your code for type correctness. 36 | 37 | ## Getting Started 38 | 39 | To get started with this project, follow these steps: 40 | 41 | 1. Clone the repository to your local machine. 42 | 43 | 44 | 2. Ensure you have the required Python version (3.7) installed. 45 | 46 | 3. Use your preferred editor (vi, vim, emacs) to work on the project files. 47 | 48 | 4. Follow the project requirements and guidelines outlined above to complete the tasks. 49 | 50 | 5. Use Mypy to validate your code for type correctness. 51 | 52 | ## Additional Resources 53 | 54 | - [Python Type Hints (PEP 484)](https://www.python.org/dev/peps/pep-0484/) 55 | - [Mypy Documentation](https://mypy.readthedocs.io/en/stable/index.html) 56 | 57 | Happy coding! 58 | 59 | --------------------------------------------------------------------------------