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
Empty file.
53 changes: 53 additions & 0 deletions homeworks/Simon Kozhin/hw4/contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@


class ContractError(Exception):
"""We use this error when someone breaks our contract."""
def __init__(self, *args):
if args:
self.message = args[0]
else:
self.message = None
def __str__(self):
if self.message:
return (f"ContractError {self.message}")
else:
return ("ContractError has been raised")




#: Special value, that indicates that validation for this type is not required.
Any = object()


def contract(arg_types=None, return_type=None, raises=None):
def decorator(func):
def wrapped(*args, **kwargs):
for index, value in enumerate(tuple((*args, *kwargs,))):
if type(value) is not Any and type(value) != arg_types[index]:
raise ContractError ("Не поддерживаемый тип данных") from TypeError

try:
a = func(*args, **kwargs)
except(Exception
if raises is None or Any in raises
else raises) as ex:
raise ex

except(Exception) as ex:
raise ContractError(f"Непредвиденная ошибка {type(ex)} ")

if type(a) != return_type and type(a) is not Any:
raise ContractError("Неверный тип возвращаемых данных")
return a

return wrapped
return decorator

@contract(arg_types=(int, Any))
def add_two_numbers(first, second):
return first + second

add_two_numbers(1, 2) # ok
add_two_numbers(1, 3.4) # ok
add_two_numbers(2.1, 1) # raises ContractError
85 changes: 85 additions & 0 deletions homeworks/Simon Kozhin/hw4/hw4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## Теория

### Exceptions

- `try/except/else/finally`: https://pythonz.net/references/named/try-except-finally/
- `raise`: https://pythonz.net/references/named/raise/
- Иерархия Exception: https://docs.python.org/3/library/exceptions.html#exception-hierarchy
- Когда не нужно использовать Exception? https://sobolevn.me/2019/02/python-exceptions-considered-an-antipattern

### Decorators

- Декораторы шаг за шагом: https://pythonworld.ru/osnovy/dekoratory.html

### Generators

- Iterable vs Iterator vs Generator: https://nvie.com/posts/iterators-vs-generators/

### Comprehensions

- Comprehensions: https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Comprehensions.html

### Context managers

- Менеджеры контекста: https://pythonz.net/references/named/contextmanager/
- `with`: https://pythonz.net/references/named/with/


## Практика

Задача: реализовать декоратор `@contract`. Смотри файл `contract.py`

Требования:

1. Необходимо проверять типы аргументов и тип выходного значения функции. Указываем кортеж типов для `arg_types`. Каждый тип в кортеже - соответсвует типу аргумента. Для типа выходного значения - указываем `return_type`

```python
@contract(arg_types=(int, int), return_type=int)
def add_two_numbers(first, second):
return first + second

add_two_numbers(1, 2) # ok
```

2. Если передан неправильный тип, вызываем ошибку `ContractError`:

```python
add_two_numbers('a', 'b') # raises ContractError
```

3. Параметр `raises` отвечает за типы исключений, которые функция может кидать. Если выкинутое исключение отсутсвует в списке разрешенных, то мы добавляем `ContractError` (смотри `raise from`). Пример:

```python
@contract(arg_types=(int, int), return_type=float, raises=(ZeroDivisionError,))
def div(first, second):
return first / second

div(1, 2) # ok
div(1, 0) # raises ZeroDisionError
div(1, None) # raises ContractError from TypeError
```

4. Можно не передавать какое-то значение из `arg_types` или `return_type`. Или передать значение `None`: тогда ничего не будет происходить. Пример:

```python
# validates only return type, args and raises are ignored:
@contract(return_type=int)

# validation is completely disabled:
@contract(return_type=None, arg_types=None, raises=None)

# return type and raises checks are disabled:
@contract(arg_types=(str, str))
```

5. Можно передать специальное значение `Any` для того, чтобы игнорировать какой-то один тип внутри `arg_types` или `raises`. Например:

```python
@contract(arg_types=(int, Any))
def add_two_numbers(first, second):
return first + second

add_two_numbers(1, 2) # ok
add_two_numbers(1, 3.4) # ok
add_two_numbers(2.1, 1) # raises ContractError
```
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import argparse


ARG_HELP_FUNC = '''cowsay "Some text" - you get a cow what say your text ***
highligh "*Your code*" - you get a highlighted code **********
time Region/City - you get a real time in this city '''

ARG_HELP_PARAM = 'the argument of function ("Your text"), "*Your code*" etc.'



def main():
parser = argparse.ArgumentParser(description='Ultra super useful script')
parser.add_argument('function', help=ARG_HELP_FUNC)
parser.add_argument('param_of_func', help=ARG_HELP_PARAM)
args = parser.parse_args()

# if args.function == 'cowsay':
# cowsay(args.param_of_func)
# if args.function == 'highligh':
# highligh(args.param_of_func)
# if args.function == 'time':
# time(args.param_of_func)
FOO.get(args.function)(args.param_of_func)

def cowsay(param):
from cowpy import cow

msg = cow.milk_random_cow(param)
print(msg)


def highligh(param):
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import TerminalFormatter

lexer = PythonLexer()
formatter = TerminalFormatter(linenos = True)
print(highlight(param, lexer, formatter))


def time(param):
from datetime import datetime
from pytz import timezone

dt_format = "%d-%m-%Y %H:%M:%S"
timedate = datetime.now(timezone(param))
print('Дата и время выбранной зоны: \n', timedate.strftime(dt_format))


FOO = {
'cowsay': cowsay,
'highligh': highligh,
'time': time,
}
Loading