diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..a425c4c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,23 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +on: push + +jobs: + code_quality: + runs-on: ubuntu-latest + name: Checks with black, isort and possibly run tests + container: python:3.9 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Run script + run: | + pip install flake8 isort pytest + pip install requests + ls -la + flake8 . + isort --check . + py.test tests diff --git a/homework1/.gitignore b/homework1/.gitignore deleted file mode 100644 index 1ceb2fd..0000000 --- a/homework1/.gitignore +++ /dev/null @@ -1,132 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# ide -.idea/ diff --git a/homework1/requirements.txt b/homework1/requirements.txt deleted file mode 100644 index 769dce2..0000000 --- a/homework1/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest -pytest-sugar \ No newline at end of file diff --git a/homework1/sample_project/calculator/calc.py b/homework1/sample_project/calculator/calc.py deleted file mode 100644 index f214d8f..0000000 --- a/homework1/sample_project/calculator/calc.py +++ /dev/null @@ -1,2 +0,0 @@ -def check_power_of_2(a: int) -> bool: - return bool(a & (a - 1) == 0 and (a != 0)) diff --git a/homework1/sample_project/requirements.txt b/homework1/sample_project/requirements.txt deleted file mode 100644 index 1bf5204..0000000 --- a/homework1/sample_project/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest -pytest-sugar diff --git a/homework1/sample_project/tests/__init__.py b/homework1/sample_project/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/homework1/sample_project/tests/test_calculator.py b/homework1/sample_project/tests/test_calculator.py deleted file mode 100644 index 1cfe600..0000000 --- a/homework1/sample_project/tests/test_calculator.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest - -from sample_project.calculator.calc import check_power_of_2 - -def test_positive_case(): - """Testing that actual powers of 2 give True""" - assert check_power_of_2(65536) - assert check_power_of_2(8) - assert check_power_of_2(256) - assert check_power_of_2(2048) -def test_negative_case(): - """Testing that non-powers of 2 give False""" - assert not check_power_of_2(12) - assert not check_power_of_2(0) - assert not check_power_of_2(-16) diff --git a/homework1/tasks/__init__.py b/homework1/tasks/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/homework1/tasks/task02.py b/homework1/tasks/task02.py deleted file mode 100644 index 3f71dc6..0000000 --- a/homework1/tasks/task02.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Sequence - - -def check_fibonacci(data: Sequence[int]) -> bool: - for element in range(2, len(data)): - if data[element] == data[element - 1] + data[element - 2]: - continue - else: - return False - return True - diff --git a/homework1/tasks/task03.py b/homework1/tasks/task03.py deleted file mode 100644 index fd0e17f..0000000 --- a/homework1/tasks/task03.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Tuple - - -def find_maximum_and_minimum(file_name: str) -> Tuple[int, int]: - max = 1 - min = 1 - with open(file_name) as fi: - for line in fi: - if int(line) > max: - max = int(line) - elif int(line) < min: - min = int(line) - else: - continue - a = min, max - print(a) - return a diff --git a/homework1/tasks/task04.py b/homework1/tasks/task04.py deleted file mode 100644 index 4369551..0000000 --- a/homework1/tasks/task04.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List - -def check_sum_of_four(a: List[int], b: List[int], c: List[int], d: List[int]) -> int: - counter = 0 - for i in range (0, len(a)): - if a[i] + b[i] + c[i] + d[i] == 0: - counter += 1 - else: - continue - return counter \ No newline at end of file diff --git a/homework1/tasks/task05.py b/homework1/tasks/task05.py deleted file mode 100644 index a02440a..0000000 --- a/homework1/tasks/task05.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import List - - -def find_maximal_subarray_sum(nums: List[int], k: int) -> int: - summ = 0 - current_sum = 0 - for num in nums: - current_sum = sum(nums[num:k+num]) - if current_sum > summ: - summ = current_sum - return summ \ No newline at end of file diff --git a/homework1/tests/__init__.py b/homework1/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/homework1/tests/some_file.txt b/homework1/tests/some_file.txt deleted file mode 100644 index 1341a1e..0000000 --- a/homework1/tests/some_file.txt +++ /dev/null @@ -1,10 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -16 -18 -22222222 \ No newline at end of file diff --git a/homework1/tests/tests.py b/homework1/tests/tests.py deleted file mode 100644 index d799d48..0000000 --- a/homework1/tests/tests.py +++ /dev/null @@ -1,49 +0,0 @@ -import pytest - -from tasks.task02 import check_fibonacci -from tasks.task03 import find_maximum_and_minimum -from tasks.task04 import check_sum_of_four -from tasks.task05 import find_maximal_subarray_sum - - -def test_task_02(): - check1 = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] - check2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - check3 = [25, 26, 1, 2, 3, 5, 8, 13, 21, 34, 55] - - assert check_fibonacci(check1) - assert check_fibonacci(check2) is False - assert check_fibonacci(check3) is False - - -def test_task_03(): - assert find_maximum_and_minimum("some_file.txt") - - -def test_task_04(): - a = [2, 4, 6, 8] - b = [0, -4, 6, 8] - c = [-2, 0, -12, 8] - d = [0, 0, 0, -24] - - a1 = [0, 5, 5, 5, 5, 5, 5, 5, 5, 5] - b1 = [0, 6, -5, 5, 7, 2, 3, 6, 2, 3] - c1 = [0, 2, 3, 4, 5, 6, 7, 1, 6, 1] - d1 = [0, 3, -3, 4, 6, 7, 8, 9, 1, 3] - - # check - assert (check_sum_of_four(a, b, c, d), - check_sum_of_four(a1, b1, c1, d1), check_sum_of_four(b, b1, c1, d), check_sum_of_four(a, b1, c1, d)) - - -def test_task_05(): - nums = [1, 3, -1, -3, 5, 3, 6, 7] - k = 3 - - nums_1 = [0, 2, -2, 4, 6, 7, 8, 9, 9, 12, 12, -4, -5, -22, -30] - k_1 = 2 - - nums_2 = [0, 1, 2, 3] - k_2 = 10 - assert (find_maximal_subarray_sum(nums, k), find_maximal_subarray_sum(nums_1, k_1), - find_maximal_subarray_sum(nums_2, k_2)) diff --git a/homework1/__init__.py b/homework4/__init__.py similarity index 100% rename from homework1/__init__.py rename to homework4/__init__.py diff --git a/homework4/task01.py b/homework4/task01.py new file mode 100644 index 0000000..70d54fb --- /dev/null +++ b/homework4/task01.py @@ -0,0 +1,40 @@ +""" +Write a function that gets file path as an argument. +Read the first line of the file. +If first line is a number return true if number in an interval [1, 3)* +and false otherwise. +In case of any error, a ValueError should be thrown. + +Write a test for that function using pytest library. +You should create files required for the testing inside the test run and +remove them after the test run. +(Opposite to previous homeworks when you used files created manually +before the test.) + +Definition of done: + - function is created + - function is properly formatted + - function has positive and negative tests + - tests do a cleanup and remove remove files generated by tests + +You will learn: + - how to test Exceptional cases + - how to clean up after tests + - how to check if file exists** + - how to handle*** and raise**** exceptions in test. Use sample + from the documentation. + +* https://en.wikipedia.org/wiki/Interval_(mathematics)#Terminology +** https://docs.python.org/3/library/os.path.html +*** https://docs.python.org/3/tutorial/errors.html#handling-exceptions +**** https://docs.python.org/3/tutorial/errors.html#raising-exceptions +""" + + +def read_magic_number(path: str) -> bool: + try: + with open(path, 'r') as file: + line = file.readline() + return 1 <= float(line) < 3 + except BaseException: + raise ValueError diff --git a/homework4/task02.py b/homework4/task02.py new file mode 100644 index 0000000..43ca935 --- /dev/null +++ b/homework4/task02.py @@ -0,0 +1,41 @@ +""" +Write a function that accepts an URL as input +and count how many letters `i` are present in the HTML by this URL. + +Write a test that check that your function works. +Test should use Mock instead of real network interactions. + +You can use urlopen* or any other network libraries. +In case of any network error raise ValueError("Unreachable {url}). + +Definition of done: + - function is created + - function is properly formatted + - function has positive and negative tests + - test could be run without internet connection + +You will learn: + - how to test using mocks + - how to write complex mocks + - how to raise an exception form mocks + - do a simple network requests + + +>>> count_dots_on_i("https://example.com/") +59 + +* https://docs.python.org/3/library/urllib.request.html#urllib.request.urlopen +""" + +import requests +from requests import RequestException + +# i misunderstood that we can use any lib for this task + + +def count_dots_on_i(url: str) -> int: + try: + r = requests.get(url) + return r.text.count("i") + except RequestException: + raise ValueError(f"Unreachable {url}") diff --git a/homework4/task03.py b/homework4/task03.py new file mode 100644 index 0000000..aea89de --- /dev/null +++ b/homework4/task03.py @@ -0,0 +1,28 @@ +""" +Write a function that will receive a string and write it to stderr +if line starts with "error" and to the stdout otherwise. + +my_precious_logger("error: file not found") +# stderr +'error: file not found' + +my_precious_logger("OK") +# stdout +'OK' + +Definition of done: + - function is created + - function is properly formatted + - function has positive tests +You will learn: + - how to write to stderr + - how to test output to the stderr and stdout +""" + + +import sys + + +def my_precious_logger(text: str): + temp = sys.stderr if text.startswith("error") else sys.stdout + temp.write(text) diff --git a/homework4/task04.py b/homework4/task04.py new file mode 100644 index 0000000..34b6a12 --- /dev/null +++ b/homework4/task04.py @@ -0,0 +1,30 @@ +from typing import List + + +def fizzbuzz(n: int) -> List[str]: + """ + given n, return list + :param n: int + :return: list + + >>> fizzbuzz(5) + ['1', '2', 'fizz', '4', 'buzz'] + + >>> fizzbuzz(10) + ['1', '2', 'fizz', '4', 'buzz', 'fizz', '7', '8', 'fizz', 'buzz'] + + >>> fizzbuzz(1) + ['1'] + """ + + result_list = [] + for i in range(1, n + 1): + if i % 3 == 0 and i % 5 == 0: + result_list.append('fizz buzz') + elif i % 3 == 0: + result_list.append('fizz') + elif i % 5 == 0: + result_list.append('buzz') + else: + result_list.append(str(i)) + return result_list diff --git a/homework4/test_read_magic_number_file.txt b/homework4/test_read_magic_number_file.txt new file mode 100644 index 0000000..0c7da43 --- /dev/null +++ b/homework4/test_read_magic_number_file.txt @@ -0,0 +1 @@ +2.6407384244194305 \ No newline at end of file diff --git a/homework1/sample_project/__init__.py b/tests/__init__.py similarity index 100% rename from homework1/sample_project/__init__.py rename to tests/__init__.py diff --git a/homework1/sample_project/calculator/__init__.py b/tests/homework4/__init__.py similarity index 100% rename from homework1/sample_project/calculator/__init__.py rename to tests/homework4/__init__.py diff --git a/tests/homework4/test_task01.py b/tests/homework4/test_task01.py new file mode 100644 index 0000000..db349b8 --- /dev/null +++ b/tests/homework4/test_task01.py @@ -0,0 +1,31 @@ +import os + +import pytest + +from homework4.task01 import read_magic_number + + +@pytest.mark.parametrize(("filename", "file_text", "result_bool"), + [("test_read_magic_number_file.txt", "2", True)]) +def test_magic_number_true(filename, file_text, result_bool): + try: + with open(filename, "w") as f: + f.write(file_text) + assert result_bool == read_magic_number(f.name) + except Exception as e: + raise e + finally: + os.unlink(f.name) + + +@pytest.mark.parametrize(("filename", "file_text", "result_bool"), + [("test_read_magic_number_file.txt", "5", False)]) +def test_magic_number_false(filename, file_text, result_bool): + try: + with open(filename, "w") as f: + f.write(file_text) + assert result_bool == read_magic_number(f.name) + except Exception as e: + raise e + finally: + os.unlink(f.name) diff --git a/tests/homework4/test_task02.py b/tests/homework4/test_task02.py new file mode 100644 index 0000000..145e5ea --- /dev/null +++ b/tests/homework4/test_task02.py @@ -0,0 +1,28 @@ +import pytest +import requests + +from homework4.task02 import count_dots_on_i + + +class MockingResponce: + @property + def text(self): + return "i i i i i asdghjkl" + + +@pytest.fixture() +def mock_response(monkeypatch): + def mock_get(*args, **kwargs): + return MockingResponce() + monkeypatch.setattr(requests, "get", mock_get) + + +@pytest.mark.usefixtures("mock_response") +def test_mock_count_dots_on_i_positive(): + result = count_dots_on_i("asd") + assert result == 5 + + +@pytest.mark.xfail(raises=ValueError) +def test_network_exception_passing(): + count_dots_on_i("asdf") diff --git a/tests/homework4/test_task03.py b/tests/homework4/test_task03.py new file mode 100644 index 0000000..7ac0776 --- /dev/null +++ b/tests/homework4/test_task03.py @@ -0,0 +1,14 @@ +import pytest + +from homework4.task03 import my_precious_logger + + +@pytest.mark.parametrize( + ("stderr_input", "stdout_input"), + [("error", "all right")]) +def test_logger(capsys, stderr_input, stdout_input): + my_precious_logger(stderr_input) + my_precious_logger(stdout_input) + caught = capsys.readouterr() + assert caught.err == stderr_input + assert caught.out == stdout_input diff --git a/tests/homework4/test_task04.py b/tests/homework4/test_task04.py new file mode 100644 index 0000000..337c026 --- /dev/null +++ b/tests/homework4/test_task04.py @@ -0,0 +1,25 @@ +from homework4.task04 import fizzbuzz + + +def test_fizzbuzz_doctest(): + """ + given n, return list + :param n: int + :return: list + + >>> fizzbuzz(5) + ['1', '2', 'fizz', '4', 'buzz'] + + >>> fizzbuzz(10) + ['1', '2', 'fizz', '4', 'buzz', 'fizz', '7', '8', 'fizz', 'buzz'] + """ + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + +def test_fizzbuzz_pytest(): + assert fizzbuzz(5) == ["1", "2", "fizz", "4", "buzz"]