Skip to content
Closed
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
11 changes: 11 additions & 0 deletions Solve task 1/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from typing import Final
import time

EPOCH_MS_DEFAULT: Final[int] = 1288834974657
NODE_ID_DEFAULT: Final[int] = 1
TIMESTAMP_BITS: Final[int] = 41
NODE_ID_BITS: Final[int] = 10
SEQUENCE_ID_BITS: Final[int] = 12
TIMESTAMP_MS_MAX: Final[int] = 2**TIMESTAMP_BITS - 1
NODE_ID_MAX: Final[int] = 2**NODE_ID_BITS - 1
SEQUENCE_ID_MAX: Final[int] = 2**SEQUENCE_ID_BITS - 1
32 changes: 32 additions & 0 deletions Solve task 1/snowflake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import time

from constants import *

def read_current_millis(epoch_ms: int) -> int:
return int(time.time()*1000) - epoch_ms

def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int:
return int(bin(snowflake_id)[3:44], 2) + epoch_ms

def decode_node_id(snowflake_id: int) -> int:
return int(bin(snowflake_id)[44:54], 2)

def decode_sequence_id(snowflake_id: int) -> int:
return int(bin(snowflake_id)[54:], 2)

def generate_snowflake_id(
sequence_id: int,
node_id: int = NODE_ID_DEFAULT,
epoch_ms: int = EPOCH_MS_DEFAULT) -> int | None:
if node_id < 0 or node_id > NODE_ID_MAX:
print (f"node_id must be in [0, {NODE_ID_MAX}]")
return None
elif sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX:
print (f"sequence_id be in [0, {SEQUENCE_ID_MAX}]")
return None
else:
timestamp = time.time()
if timestamp > TIMESTAMP_MS_MAX:
print ("overflows")
return None
return int('0' + bin(int(time.time()*1000) + epoch_ms)[2:].zfill(41) + bin(node_id)[2:].zfill(10) + bin(sequence_id)[2:].zfill(12), 2)
67 changes: 67 additions & 0 deletions Solve task 2/cart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import Final
from crud import read_product, update_product
from storage import (
NAME_INDEX,
PRICE_INDEX,
QUANTITY_INDEX,
Product,
)


type CartLine = tuple[int, int]

# TODO: задайте позиции полей внутри кортежа CartLine
LINE_PRODUCT_ID_INDEX: Final = 0
LINE_QUANTITY_INDEX: Final = 1


def add_to_cart(
storage: list[Product],
cart: list[CartLine],
product_id: int,
quantity: int,
) -> CartLine | None:
prod = read_product(storage, product_id)
if prod is None:
return None
if prod[QUANTITY_INDEX] < quantity:
print (f"not enough stock for product {product_id}: {prod[QUANTITY_INDEX]} available, {quantity} requested")
return None
storage[storage.index(prod)] = update_product(storage, product_id, (prod[NAME_INDEX], prod[PRICE_INDEX], prod[QUANTITY_INDEX] - quantity))
for i in range(len(cart)):
if cart[i][LINE_PRODUCT_ID_INDEX] is product_id:
cart[i] = (product_id, cart[i][LINE_QUANTITY_INDEX] + quantity)
return cart[i]
cart.append(product_id, quantity)
return cart[-1]


def find_cart_line(cart: list[CartLine], product_id: int) -> CartLine | None:
for line in cart:
if line[LINE_PRODUCT_ID_INDEX] is product_id:
return line
return None


def remove_from_cart(
storage: list[Product],
cart: list[CartLine],
product_id: int,
quantity: int,
) -> CartLine | None:
prod_cart = find_cart_line(cart, product_id)
if prod_cart is None:
print (f"product {product_id} is not in the cart")
return None
if prod_cart[LINE_QUANTITY_INDEX] < quantity:
print (f"cart holds only {prod_cart[LINE_QUANTITY_INDEX]} unit(s) of product {product_id}, cannot remove {quantity}")
return None
prod = read_product(storage, product_id)
if prod is None:
return None
storage[storage.index(prod)] = update_product(storage, product_id, (prod[NAME_INDEX], prod[PRICE_INDEX], prod[QUANTITY_INDEX] + quantity))
if (prod_cart[LINE_QUANTITY_INDEX] - quantity) == 0:
cart.remove(prod_cart)
return 0
cart [cart.index(prod_cart)] = CartLine(product_id, prod_cart[LINE_QUANTITY_INDEX] - quantity)
return cart [cart.index(prod_cart)]
55 changes: 55 additions & 0 deletions Solve task 2/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from decimal import Decimal

from storage import (
NAME_INDEX,
PRODUCT_ID_INDEX,
PRODUCT_ID_MIN,
Product,
)
from utils import normalize_price


def generate_product_id(storage: list[Product]) -> int:
if not storage:
return 0
return max(storage)[PRODUCT_ID_INDEX] + 1


def create_product(storage: list[Product], fields: tuple[str, Decimal, int]) -> int | None:
for prod in storage:
if fields [0] is prod[NAME_INDEX]:
print (f"product name '{fields [0]}' is already taken")
return None
new_product = (generate_product_id(storage), fields[0], normalize_price(fields[1]), fields[2])
storage.append(new_product)
return new_product[0]


def read_product(storage: list[Product], product_id: int) -> Product | None:
for prod in storage:
if prod[0] is product_id:
return prod
print (f"no product with id {product_id}")
return None


def update_product(
storage: list[Product],
product_id: int,
fields: tuple[str, Decimal, int],
) -> Product | None:
for i in range(len(storage)):
if storage[i][PRODUCT_ID_INDEX] is product_id:
storage[i] = (product_id, fields[0], normalize_price(fields[1]), fields[2])
return storage[i]
print (f"no product with id {product_id}")
return None


def delete_product(storage: list[Product], product_id: int) -> int | None:
for i in range(len(storage)):
if storage[i][PRODUCT_ID_INDEX] is product_id:
del storage[i]
return product_id
print (f"no product with id {product_id}")
return None
12 changes: 12 additions & 0 deletions Solve task 2/storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from decimal import Decimal
from typing import Final


type Product = tuple[int, str, Decimal, int]

PRODUCT_ID_INDEX: Final = 0
NAME_INDEX: Final = 1
PRICE_INDEX: Final = 2
QUANTITY_INDEX: Final = 3

PRODUCT_ID_MIN: Final[int] = 1
10 changes: 10 additions & 0 deletions Solve task 2/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from decimal import ROUND_HALF_UP, Decimal
from typing import Final


PRICE_PRECISION: Final[int] = 2
PRICE_STEP: Final = Decimal(1).scaleb(-PRICE_PRECISION)


def normalize_price(price: Decimal) -> Decimal:
return price.quantize(PRICE_STEP, rounding=ROUND_HALF_UP)
69 changes: 69 additions & 0 deletions Solve task 3/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from decimal import Decimal
from storage import (
NAME_INDEX,
PRODUCT_ID_INDEX,
PRODUCT_ID_MIN,
Product,
)
from utils import normalize_price, normalize_product_name


def generate_product_id(storage: list[Product]) -> int:
if not storage:
return PRODUCT_ID_MIN
return max(storage)[PRODUCT_ID_INDEX] + 1


def create_product(storage: list[Product], fields: tuple[str, Decimal, int]) -> int | None:
fields = (normalize_product_name(fields[0]), fields[1], fields[2])
if fields[0] == "":
print ("product name must not be blank")
return None
for prod in storage:
if fields[0] == prod[NAME_INDEX]:
print (f"product name '{fields [0]}' is already taken")
return None
new_product = (generate_product_id(storage), fields[0], normalize_price(fields[1]), fields[2])
storage.append(new_product)
return new_product[0]


def read_product(storage: list[Product], product_id: int) -> Product | None:
for prod in storage:
if prod[0] is product_id:
return prod
print (f"no product with id {product_id}")
return None


def update_product(
storage: list[Product],
product_id: int,
fields: tuple[str, Decimal, int],
) -> Product | None:
norm_name = normalize_product_name(fields[0])
if norm_name == "":
print ("product name must not be blank")
return None
prod = 0
for i in range(len(storage)):
if storage[i][NAME_INDEX] == norm_name and storage[i][PRODUCT_ID_INDEX] != product_id:
print (f"product name '{norm_name}' is already taken")
return None
elif storage[i][PRODUCT_ID_INDEX] == product_id:
prod = (product_id, norm_name, normalize_price(fields[1]), fields[2])
prod_num = i
if prod != 0:
storage[prod_num] = prod
return prod
print (f"no product with id {product_id}")
return None


def delete_product(storage: list[Product], product_id: int) -> int | None:
for i in range(len(storage)):
if storage[i][PRODUCT_ID_INDEX] is product_id:
del storage[i]
return product_id
print (f"no product with id {product_id}")
return None
94 changes: 94 additions & 0 deletions Solve task 3/run_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from decimal import Decimal, InvalidOperation
from typing import Final

from crud import (
create_product,
delete_product,
read_product,
update_product,
)
from storage import Product
from utils import get_storage_str_representation


PROMPT: Final[str] = "admin> "
HELP_TEXT: Final[str] = """Available commands:
help show this message
exit leave the console
show print the whole store as a table
create <name...> <price> <quantity> add a product, print its new id
read <id> print the product with that id
update <id> <name...> <price> <quantity> overwrite that product's fields
delete <id> remove the product with that id

For create and update the price and quantity are the last two words of the
line; everything before them is the product name, so it may contain spaces
(for example "Gibson SG Junior") and needs no quoting."""


def show_help() -> None:
print(HELP_TEXT)


def print_result(result: object) -> None:
if result: print (result)



def run_command(storage: list[Product], line: str) -> bool:
line = line.split()
match line:
case ["help"]:
show_help()
return True
case ["exit"]:
return False
case ["show"]:
get_storage_str_representation(storage)
return True
case ["create", *_, price, quantity]:#попробовать заменить на line[-1] и line[-2] price и quantity
name = " ".join(line[1:-2])
pocket = create_product(storage, (name, Decimal(price), int(quantity)))
if pocket:
print (pocket)
return True
case ["read", id_num]:
output = read_product(storage, int(id_num))
if output:
print (output)
return True
case ["update", id_num, *_, price, quantity]:#попробовать заменить на line[-1] и line[-2] price и quantity
name = " ".join(line[2:-2])
pocket = update_product (storage, int(id_num), (name, Decimal(price), int(quantity)))
if pocket:
print (pocket)
return True
case ["delete", id_num]:
pocket = delete_product(storage, int(id_num))
if pocket:
print (pocket)
return True
case _:
line = " ".join(line)
print (f"'{line}' is not a command")
return True



def main() -> None:

storage: list[Product] = []
running = True

while running:
line = input(PROMPT).strip()

try:
running = run_command(storage, line)

except (ValueError):
print(f"{line!r} names a command but its arguments are invalid")


if __name__ == "__main__":
main()
12 changes: 12 additions & 0 deletions Solve task 3/storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from decimal import Decimal
from typing import Final


type Product = tuple[int, str, Decimal, int]

PRODUCT_ID_INDEX: Final = 0
NAME_INDEX: Final = 1
PRICE_INDEX: Final = 2
QUANTITY_INDEX: Final = 3

PRODUCT_ID_MIN: Final[int] = 1
Loading
Loading