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
51 changes: 51 additions & 0 deletions homeworks/ALTokarev7/1/array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class Array(object):

def __init__(self, *args):
self._data = args

def __len__(self):
return len(self._data)

def __str__(self):
return str(self._data)

def __getitem__(self, ind):
return self._data[ind]

def __iter__(self):
return iter(self._data)

def __add__(self, other):
res = Array()
res._data = self._data + other._data
return res

def append(self, arg):
self._data = self._data + (arg,)

def index(self, obj):
if obj in self._data:
return (self._data.index(obj))
return -1


def main():
mas_a = Array(1, 2)
print(f'first array = {mas_a}')
mas_b = Array(3, 4, 5, 6)
print(f'second array = {mas_b}')
mas_a.append(33)
print(f'first array after append(33) = {mas_a}')
mas_sum = mas_a + mas_b
print(f'array of sum first and second: {mas_sum}')
print(f'length of sum array is {len(mas_sum)}')
print(f'index of element 1 in sum array is {mas_sum.index(1)}')

for el in mas_sum:
print(el)

print(f'Sum array el number [1] is {mas_sum[1]}')


if __name__ == "__main__":
main()
29 changes: 29 additions & 0 deletions homeworks/ALTokarev7/2/contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class ContractError(Exception):
"""We use this error when someone breaks our contract."""


#: 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):
if arg_types is not None:
for num in range(len(args)):
if arg_types[num] != Any and arg_types[num] is not None:
if type(args[num]) != arg_types[num]:
raise ContractError
try:
ret = func(*args)
except Exception as ex:
if type(ex) in raises:
raise ex
else:
raise ContractError from ex
if return_type is not None and return_type != Any:
if type(ret) != return_type:
raise ContractError
return ret
return wrapped
return decorator
Empty file.
28 changes: 28 additions & 0 deletions homeworks/ALTokarev7/5/todo/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Main file. Contains program execution logic.
"""

from todo.custom_exceptions import UserExitException
from todo.runtime import parse_user_input, perform_command


def main():
"""
Main method, works infinitely until user runs `exit` command.
Or hits `Ctrl+C` in the console.
"""
while True:
try:
perform_command(parse_user_input())
except UserExitException:
break
except Exception as ex:
print('You have done something wrong!', ex)


if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print()
print('Shutting down, bye!')
106 changes: 106 additions & 0 deletions homeworks/ALTokarev7/5/todo/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@

from todo.custom_exceptions import UserExitException
from todo.models import BaseItem
from todo.reflection import find_classes


class BaseCommand(object):
label: str

def perform(self, store):
raise NotImplementedError()


class ListCommand(BaseCommand):
label = 'list'

def perform(self, store):
if len(store.items) == 0:
print('There are no items in the storage.')
return

for index, obj in enumerate(store.items):
print('{0}: {1}'.format(index, str(obj)))


class NewCommand(BaseCommand):
label = 'new'

def perform(self, store):
classes = self._load_item_classes()

print('Select item type:')
for index, name in enumerate(classes.keys()):
print('{0}: {1}'.format(index, name))

selected_key = None

while True:
try:
selected_key = self._select_item(classes)
except ValueError:
print('Bad input, try again.')
except IndexError:
print('Wrong index, try again.')
else:
break

selected_class = classes[selected_key]
print('Selected: {0}'.format(selected_class.__name__))
print()

new_object = selected_class.construct()

store.items.append(new_object)
print('Added {0}'.format(str(new_object)))
print()
return new_object

def _load_item_classes(self) -> dict:
# Dynamic load:
return dict(find_classes(BaseItem))

def _select_item(self, classes):
selection = int(input('Input number: '))
if selection < 0:
raise IndexError('Index needs to be >0')
return list(classes.keys())[selection]


class DoneCommand(BaseCommand):
label = 'done'

def perform(self, store):
num = int(input('Input number of item to change status on done: '))
if num < 0:
raise IndexError('Index needs to be >0')
if num >= len(store.items):
raise IndexError('Wrong index, try again.')

store.items[num].done = True

print('item {0} is done!'.format(store.items[num]))
print()


class UndoneCommand(BaseCommand):
label = 'undone'

def perform(self, store):
num = int(input('Input number of item to change status on undone: '))
if num < 0:
raise IndexError('Index needs to be >0')
if num >= len(store.items):
raise IndexError('Wrong index, try again.')

store.items[num].done = False

print('item {0} is undone!'.format(store.items[num]))
print()


class ExitCommand(BaseCommand):
label = 'exit'

def perform(self, _store):
raise UserExitException('See you next time!')
2 changes: 2 additions & 0 deletions homeworks/ALTokarev7/5/todo/custom_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class UserExitException(Exception):
"""We use this exception when user wants to exit."""
71 changes: 71 additions & 0 deletions homeworks/ALTokarev7/5/todo/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
class BaseItem(object):

status = {False: '-', True: '+'}

def __init__(self, heading):
self.heading = heading
self.done = False # TODO: make sure we can use it...

def __repr__(self):
return self.__class__.__name__

def __str__(self):
return '{0} {1}'.format(
self.status[self.done],
self.__class__.__name__[:-4]
)

@classmethod
def construct(cls):
raise NotImplementedError()


class ToDoItem(BaseItem):
def __str__(self):
return '{0}: {1}'.format(
super().__str__(),
self.heading,
)

@classmethod
def construct(cls):
heading = input('Input heading: ')
return cls(heading)


class ToBuyItem(BaseItem):
def __init__(self, heading, price):
super().__init__(heading)
self.price = price

def __str__(self):
return '{0}: {1} for {2}'.format(
super().__str__(),
self.heading,
self.price,
)

@classmethod
def construct(cls):
heading = input('Input heading: ')
price = input('Input price: ')
return cls(heading, price)


class ToReadItem(BaseItem):
def __init__(self, heading, url):
super().__init__(heading)
self.url = url

def __str__(self):
return '{0}: {1} from {2}'.format(
super().__str__(),
self.heading,
self.url,
)

@classmethod
def construct(cls):
heading = input('Input heading: ')
url = input('Input url: ')
return cls(heading, url)
34 changes: 34 additions & 0 deletions homeworks/ALTokarev7/5/todo/reflection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import inspect
import sys


def find_classes(base_class) -> tuple:
"""
Finds all subclasses of a class inside module.

:param base_class: Base class to search children.
:return: tuple of subclasses
"""
return inspect.getmembers(
sys.modules[base_class.__module__],
_reflect_filter(base_class),
)


def _reflect_filter(base_class):
"""
Reflection is used to load modules dynamically.

This method is complex. It does some dark magic.
How is it even possible to understand it?

:param base_class: Target base class
:return: function to filter only subclasses of `base_class`
"""
def class_filter(klass):
return inspect.isclass(
klass,
) and klass.__module__ == base_class.__module__ and issubclass(
klass, base_class,
) and klass is not base_class
return class_filter
51 changes: 51 additions & 0 deletions homeworks/ALTokarev7/5/todo/runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from todo.commands import BaseCommand
from todo.custom_exceptions import UserExitException
from todo.reflection import find_classes
from todo.storage import Storage


def get_routes() -> dict:
"""
This function contains the dictionary of possible commands.
:return: `dict` of possible commands, with the format: `name -> class`
"""
routes = find_classes(BaseCommand)
return {
route().label: route
for _, route in routes
}


def perform_command(command: str) -> None:
"""
Performs the command by name.
Stores the result in `Storage()`.
:param command: command name, selected by user.
"""
command = command.lower()
routes = get_routes()

try:
command_class = routes[command]
except KeyError:
print('Bad command, try again.')
return

command_inst = command_class()
storage = Storage()

try:
command_inst.perform(storage)
except UserExitException as ex:
# Handling `exit` command.
print(ex)
raise


def parse_user_input():
"""
Вернёт одну из команд exit list new
"""
commands = get_routes().keys()
message = 'Input your command: ({0}): '.format('|'.join(commands))
return input(message)
Loading