Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
max-line-length = 120
exclude = venv, code_2.py, code.py
ignore = D103, TAE001, D100, D104
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,4 @@ make.exe

*.json
*sqlite3
.idea
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: python
python:
- "3.9"
install:
- pip install -r requirements.txt
script:
- make style
- make test
after_success:
- bash <(curl -s https://codecov.io/bash)
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
style:
flake8 .

test:
pytest --cov=code_2 --cov-branch tests/test_code.py
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[![Build Status](https://travis-ci.com/DmitryTokyo/level_2_1.svg?branch=master)](https://travis-ci.com/DmitryTokyo/level_2_1)
[![codecov](https://codecov.io/gh/DmitryTokyo/level_2_1/branch/master/graph/badge.svg?token=JVY6FRT1EG)](https://codecov.io/gh/DmitryTokyo/level_2_1)

# Testing sandbox level 2.1

Welcome to the testing sandbox: practice-driven testing instrument.
Expand Down
5 changes: 3 additions & 2 deletions code.py → code_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import os
import sqlite3
import sys
import re
from pathlib import Path
from typing import Optional, Set, re, Callable, Union, Collection, Mapping, Any
from typing import Optional, Set, Callable, Union, Collection, Mapping, Any

import deal as deal
from PIL import UnidentifiedImageError
Expand Down Expand Up @@ -176,7 +177,6 @@ def _load_workbook_from_xls(file_path, file_contents) -> Workbook:
xls_sheet = xls_workbook.sheet_by_index(0)
nrows = xls_sheet.nrows
ncols = xls_sheet.ncols

wb = Workbook()
ws = wb[wb.sheetnames[0]]

Expand All @@ -186,6 +186,7 @@ def _load_workbook_from_xls(file_path, file_contents) -> Workbook:
value = cell.value
if value and cell.ctype == 3:
value = datetime.datetime(*xlrd.xldate_as_tuple(value, xls_workbook.datemode))
print(value)
ws.cell(row=row + 1, column=col + 1).value = value

return wb
Expand Down
109 changes: 109 additions & 0 deletions level1_basics/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import ast
import datetime
import io
import re
from typing import Iterable, Any, Optional, Generator

from PIL import Image
from requests import get
from requests.exceptions import MissingSchema


def chunks(some_list: list, chunk_size: int) -> Generator:
for chunk_num in range(0, len(some_list), chunk_size):
yield some_list[chunk_num:chunk_num + chunk_size]


def flat(some_list: list[list]) -> list:
return [item for sublist in some_list for item in sublist]


def has_recursive_calls(funcdef) -> bool:
return bool([
n for n in ast.walk(funcdef)
if (
isinstance(n, ast.Call)
and isinstance(n.func, ast.Name)
and n.func.id == funcdef.name
)
])


def parse_iso_datetime(iso_datetime: str) -> Optional[datetime.datetime]:
if iso_datetime.endswith('Z'):
iso_datetime = iso_datetime[:-1]
try:
return datetime.datetime.fromisoformat(iso_datetime)
except ValueError:
return None


def get_image_height_in_pixels(url: str) -> Optional[int]:
try:
img_data = get(url).content
except MissingSchema:
return None
im = Image.open(io.BytesIO(img_data))
return im.size[1]


def if_logs_has_any_of_commands(log: list[str], commands: list[str]) -> bool:
is_section_present = False
for required_command in commands:
for base_command in log:
if (
base_command.startswith(f'{required_command} ')
or f' {required_command} ' in base_command
or base_command == required_command
):
is_section_present = True
break
return is_section_present


def extract_all_constants_from_ast(ast_tree: ast.AST) -> list[str]:
return list({n.s for n in ast.walk(ast_tree) if isinstance(n, ast.Str)})


def is_camel_case_word(word: str) -> bool:
uppercase_letters_amount = re.subn(r'[A-Z]', '', word)[1]
lowercase_letters_amount = re.subn(r'[a-z]', '', word)[1]
return bool(
(lowercase_letters_amount and uppercase_letters_amount >= 2)
or re.findall(r'[a-z][A-Z]', word),
)


def split_camel_case_words(camel_cased_word: str) -> list[str]:
words_start_indexes = [m.start(0) for m in re.finditer(r'[A-Z]', camel_cased_word)]
if words_start_indexes[0] > 0:
words_start_indexes.insert(0, 0)
if words_start_indexes[-1] < len(camel_cased_word):
words_start_indexes.append(len(camel_cased_word))
words = []
for word_start_index, word_end_index in zip(words_start_indexes, words_start_indexes[1:]):
words.append(camel_cased_word[word_start_index:word_end_index].lower())
return words


def is_path_in_exclude_list(path: str, exclude: list[str]) -> bool:
return any(e in path for e in exclude)


def get_full_class_name(obj: Any) -> str:
module = obj.__class__.__module__
if module is None or module == str.__class__.__module__:
return obj.__class__.__name__
return module + '.' + obj.__class__.__name__


def max_with_default(items: Iterable, default: Optional = None):
default = default or 0
items = list(items)
if not items and default is not None:
return default
return max(items)


def is_python_class_name(name: str) -> bool:
return name[0] == name[0].upper() and name[1:] == name[1:].lower()
35 changes: 35 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,38 @@ openpyxl==3.0.7
pillow==8.1.2
pytz==2021.1
xlrd==2.0.1

coverage==5.5
pytest-cov==2.12.0
requests-mock==1.9.3
pytest-mock==3.6.1

flake8==3.9.2

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: излишнее по флэйку. разве не достаточно только одного flake8==3.9.2?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я добавил расширения из рабочего проекта. Единственное что, сейчас убрал расширешиние с аннотациями, тк я в тестовом файле нигде не использую

flake8-2020==1.6.0
flake8-blind-except==0.2.0
flake8-bugbear==20.11.1
flake8-builtins==1.5.3
flake8-commas==2.0.0
flake8-comprehensions==3.3.1
flake8-debugger==4.0.0
flake8-docstrings==1.5.0
flake8-eradicate==1.0.0
flake8-polyfill==1.0.2
flake8-print==4.0.0
flake8-quotes==3.2.0
flake8-string-format==0.3.0
flake8-fixme==1.1.1
flake8-variables-names==0.0.4
flake8-class-attributes-order==0.1.2
flake8-broken-line==0.3.0
flake8-tidy-imports==4.2.1
flake8-typing-imports==1.10.1
flake8-if-statements==0.1.0
flake8-functions==0.0.5
flake8-expression-complexity==0.0.9
flake8-printf-formatting==1.1.2
flake8-multiline-containers==0.0.17
flake8-absolute-import==1.0
flake8-simplify==0.13.0
flake8-functions-names==0.0.5
mypy-extensions==0.4.3
Empty file added tests/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import functools
import sys
from contextlib import contextmanager
from io import StringIO


@contextmanager
def does_not_raise():
yield


def redirect_stdout(decorated_function):
@functools.wraps(decorated_function)
def wrapper(*args):
sys.stdout = StringIO()
sys.stdout = sys.__stdout__
decorated_function(*args)
return wrapper
Loading