Slide 1

Slide 1 text

Это вообще не просто! Александр Гончаров,

Slide 2

Slide 2 text

Существует миф, что IT - это просто

Slide 3

Slide 3 text

Существует миф, что IT - это просто

Slide 4

Slide 4 text

Существует миф, что IT - это просто

Slide 5

Slide 5 text

Существует миф, что IT - это просто

Slide 6

Slide 6 text

Так что, действительно просто?

Slide 7

Slide 7 text

Существует миф, что IT - это просто

Slide 8

Slide 8 text

Существует миф, что IT - это просто

Slide 9

Slide 9 text

Существует миф, что IT - это просто

Slide 10

Slide 10 text

Расскажу, как у меня

Slide 11

Slide 11 text

Добро пожаловать в мой мир!

Slide 12

Slide 12 text

Это программирование, поэтому можно немного ошибиться, и ничего за это не будет

Slide 13

Slide 13 text

Celery celery -A project worker -Q=default --loglevel=info Queue “default” Task Worker Task Task

Slide 14

Slide 14 text

Celery celery -A project worker -Q=default --loglevel=info Queue “default” Task Worker Task Task Queue “=default”

Slide 15

Slide 15 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value 'value' ● > test.py --queues=value 'value' ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 16

Slide 16 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value 'value' ● > test.py --queues=value 'value' ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 17

Slide 17 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value 'value' ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 18

Slide 18 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value 'value' ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 19

Slide 19 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 20

Slide 20 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value 'value' ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 21

Slide 21 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 22

Slide 22 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue 'value' ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 23

Slide 23 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 24

Slide 24 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value 'value' ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 25

Slide 25 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 26

Slide 26 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” '=value' ● > test.py -Q"=value" 'value'

Slide 27

Slide 27 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” =value ● > test.py -Q"=value" 'value'

Slide 28

Slide 28 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” =value ● > test.py -Q"=value" 'value'

Slide 29

Slide 29 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” =value ● > test.py -Q"=value" value

Slide 30

Slide 30 text

Celery from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--queues', '-Q') args = parser.parse_args() print(args.queues) ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value value ● > test.py -Q=”=value” =value ● > test.py -Q"=value" value

Slide 31

Slide 31 text

Celery import click @click.command() @click.option('--queues', '-Q') def echo(queues): print(queues) if __name__ == '__main__': echo() ● > test.py --queues value value ● > test.py --queues=value value ● > test.py -Q value value ● > test.py -Qvalue value ● > test.py -Q=value =value ● > test.py -Q=”=value” ==value ● > test.py -Q"=value" =value

Slide 32

Slide 32 text

Django ● Всё покрыто тестами # settings.py SUBSCRIPTION = { ‘duration’: timedelta(days=30), ‘price’: Decimal(100), } # service.py subscriptions = getattr( settings, ‘SUBSCRIPTIONS’, DEFAULT_SETTINGS )

Slide 33

Slide 33 text

Django ● Всё покрыто тестами ● Выкатываю в прод - работает не так, как ожидал # settings.py SUBSCRIPTION = { ‘duration’: timedelta(days=30), ‘price’: Decimal(100), } # service.py subscriptions = getattr( settings, ‘SUBSCRIPTIONS’, DEFAULT_SETTINGS )

Slide 34

Slide 34 text

Django ● Всё покрыто тестами ● Выкатываю в прод - работает не так, как ожидал ● Никаких ошибок нет # settings.py SUBSCRIPTION = { ‘duration’: timedelta(days=30), ‘price’: Decimal(100), } # service.py subscriptions = getattr( settings, ‘SUBSCRIPTIONS’, DEFAULT_SETTINGS )

Slide 35

Slide 35 text

Django ● Всё покрыто тестами ● Выкатываю в прод - работает не так, как ожидал ● Никаких ошибок нет ● В чём ошибка? # settings.py SUBSCRIPTION = { ‘duration’: timedelta(days=30), ‘price’: Decimal(100), } # service.py subscriptions = getattr( settings, ‘SUBSCRIPTIONS’, DEFAULT_SETTINGS )

Slide 36

Slide 36 text

Django ● Всё покрыто тестами ● Выкатываю в прод - работает не так, как ожидал ● Никаких ошибок нет ● В чём ошибка? ● Проверяю - забыл одну букву # settings.py SUBSCRIPTIONS = { ‘duration’: timedelta(days=30), ‘price’: Decimal(100), } # service.py subscriptions = getattr( settings, ‘SUBSCRIPTIONS’, DEFAULT_SETTINGS )

Slide 37

Slide 37 text

Bumblebee rm -rf /usr/lib/…

Slide 38

Slide 38 text

Bumblebee rm -rf /usr/lib/… rm -rf /usr /lib/…

Slide 39

Slide 39 text

Bumblebee rm -rf /usr/lib/… rm -rf /usr /lib/…

Slide 40

Slide 40 text

Sqlalchemy ● Пытаюсь записать несколько строк в БД (psycopg.errors.UniqueViolation) duplicate key value violates unique constraint "ix_tag_name" DETAIL: Key (lower('name'::text))=(name) already exists. [SQL: INSERT INTO tag (name, id) VALUES (%(name)s::VARCHAR, nextval('tag_id_seq')) RETURNING tag.id] [parameters: {'name': 'ai'}]

Slide 41

Slide 41 text

Sqlalchemy ● Пытаюсь записать несколько строк в БД ● Получаю ошибку, что такая строка уже существует (psycopg.errors.UniqueViolation) duplicate key value violates unique constraint "ix_tag_name" DETAIL: Key (lower('name'::text))=(name) already exists. [SQL: INSERT INTO tag (name, id) VALUES (%(name)s::VARCHAR, nextval('tag_id_seq')) RETURNING tag.id] [parameters: {'name': 'ai'}]

Slide 42

Slide 42 text

Sqlalchemy ● Пытаюсь записать несколько строк в БД ● Получаю ошибку, что такая строка уже существует ● А строки разные! (psycopg.errors.UniqueViolation) duplicate key value violates unique constraint "ix_tag_name" DETAIL: Key (lower('name'::text))=(name) already exists. [SQL: INSERT INTO tag (name, id) VALUES (%(name)s::VARCHAR, nextval('tag_id_seq')) RETURNING tag.id] [parameters: {'name': 'ai'}]

Slide 43

Slide 43 text

Sqlalchemy ● Пытаюсь записать несколько строк в БД ● Получаю ошибку, что такая строка уже существует ● А строки разные! ● Смотрю, что уже есть в таблице - а там ничего!

Slide 44

Slide 44 text

Sqlalchemy class Tag(BigIntBase): name: Mapped[str] __table_args__ = ( Index( "ix_tag_name", func.lower('name'), unique=True), ) ● Пытаюсь записать несколько строк в БД ● Получаю ошибку, что такая строка уже существует ● А строки разные! ● Смотрю, что уже есть в таблице - а там ничего! ● А потому что “name” - это не название колонки, а строка!

Slide 45

Slide 45 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски epoch = (100, 200) jobs = Jobs.objects.filter( block__gte=epoch[0], block__lt=epoch[1], ) .order_by("block")

Slide 46

Slide 46 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски ● Есть же специальный тип: range epoch = (100, 200) jobs = Jobs.objects.filter( block__gte=epoch[0], block__lt=epoch[1], ) .order_by("block")

Slide 47

Slide 47 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски ● Есть же специальный тип: range ● Время рефакторинга! epoch = (100, 200) jobs = Jobs.objects.filter( block__gte=epoch[0], block__lt=epoch[1], ) .order_by("block")

Slide 48

Slide 48 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски ● Есть же специальный тип: range ● Время рефакторинга! ● Всё сломалось epoch = range(100, 201) jobs = Jobs.objects.filter( block__gte=epoch[0], block__lt=epoch[1], ) .order_by("block")

Slide 49

Slide 49 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски ● Есть же специальный тип: range ● Время рефакторинга! ● Всё сломалось ● А потому что [1] теперь не то, чем было! epoch = range(100, 201) jobs = Jobs.objects.filter( block__gte=epoch[0], block__lt=epoch[1], ) .order_by("block")

Slide 50

Slide 50 text

Лучшее - враг хорошего ● Однажды я решил, что использовать tuple[int, int] для интервалов - это не по- сеньорски ● Есть же специальный тип: range ● Время рефакторинга! ● Всё сломалось ● А потому что [1] теперь не то, чем было! epoch = range(100, 201) jobs = Jobs.objects.filter( block__gte=epoch.start, block__lt=epoch.stop, ) .order_by("block")

Slide 51

Slide 51 text

#!/bin/bash ● Почему нельзя ставить флаги после “#!” ? #!/bin/bash -e false echo "Shouldn’t execute" > ./script.sh + false > bash script.sh Shouldn't execute

Slide 52

Slide 52 text

#!/bin/bash ● Почему нельзя ставить флаги после “#!” ? #!/bin/bash -e false echo "Shouldn’t execute" > ./script.sh (nothing) > bash script.sh Shouldn't execute

Slide 53

Slide 53 text

#!/bin/bash ● Почему нельзя ставить флаги после “#!” ? #!/bin/bash -e false echo "Shouldn’t execute" > ./script.sh (nothing) > bash script.sh Shouldn't execute

Slide 54

Slide 54 text

#!/bin/bash ● Почему нельзя ставить флаги после “#!” ? #!/bin/bash set -e false echo "Shouldn’t execute" > ./script.sh (nothing) > bash script.sh (nothing)

Slide 55

Slide 55 text

Это программирование, поэтому у нас есть версии и VCS

Slide 56

Slide 56 text

Зачем вообще версии? ZeroVer! ● Иногда устаёшь от этих SemVer, LTS, v2024.08, и хочется просто писать код. 1.0 1.0.0-rc1 18.0 2024.08 0.0.1 0.1.0dev 0.9999999 0.0

Slide 57

Slide 57 text

Зачем вообще версии? ZeroVer! ● Иногда устаёшь от этих SemVer, LTS, v2024.08, и хочется просто писать код. 1.0 1.0.0-rc1 18.0 2024.08 0.0.1 0.1.0dev 0.9999999 0.0 React native 0.75.2 Three.js r167 FastAPI 0.112.1 Hugo 0.133.1 Ruff 0.6.2 Zoxide 0.9.4 Numba 0.60.0 …

Slide 58

Slide 58 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные

Slide 59

Slide 59 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 60

Slide 60 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 61

Slide 61 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 62

Slide 62 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 63

Slide 63 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 64

Slide 64 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 65

Slide 65 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 66

Slide 66 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно

Slide 67

Slide 67 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 68

Slide 68 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 69

Slide 69 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 70

Slide 70 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 71

Slide 71 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 72

Slide 72 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 73

Slide 73 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 74

Slide 74 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 75

Slide 75 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 76

Slide 76 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 77

Slide 77 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 78

Slide 78 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 79

Slide 79 text

У нас есть git! ● Мы как волшебники - можем путешествовать во времени и создавать параллельные вселенные ● Просто смотрим на ветки VCS - и всегда всё понятно ● А если непонятно - наши коллеги всегда напишут понятные сообщения

Slide 80

Slide 80 text

Это программирование, поэтому все умные и пишут классный код

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

Langchain: усидеть на двух стульях

Slide 83

Slide 83 text

Langchain: усидеть на двух стульях

Slide 84

Slide 84 text

Langchain: усидеть на двух стульях

Slide 85

Slide 85 text

Langchain: усидеть на двух стульях Патч века: - historic_messages = config["configurable"]["message_history"].messages + historic_messages = await config["configurable"]["message_history"].aget_messages() Почему? ● Копипаста ● Метод называется “messages”, а не “get_messages”

Slide 86

Slide 86 text

“Soon” 2019 год

Slide 87

Slide 87 text

“Soon” 2019 год 2024 год

Slide 88

Slide 88 text

Bittensor ● Блокчейн, много $$$

Slide 89

Slide 89 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения

Slide 90

Slide 90 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат

Slide 91

Slide 91 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно

Slide 92

Slide 92 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому…

Slide 93

Slide 93 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… is_success, msg = do_stuff()

Slide 94

Slide 94 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… try: is_success, msg = do_stuff() if not is_success: exc_class = parse_error(msg) raise exc_class(msg) except Exception: # handle exception

Slide 95

Slide 95 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… try: is_success, msg = do_stuff() if not is_success: exc_class = parse_error(msg) raise exc_class(msg) except Exception: # handle exception

Slide 96

Slide 96 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… ● Но и это ещё не всё class Subtensor: def __init__(...): # Attempt to connect to chosen endpoint try: self.connect(...) except ConnectionRefusedError: _logger.error(...) exit(1)

Slide 97

Slide 97 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… ● Но и это ещё не всё class Subtensor: def __init__(...): # Attempt to connect to chosen endpoint try: self.connect(...) except ConnectionRefusedError: _logger.error(...) exit(1)

Slide 98

Slide 98 text

Bittensor ● Блокчейн, много $$$ ● Очень любят исключения ● Но ещё больше любят возвращать результат ● Но коды ошибок - это как-то сложно ● Поэтому… ● Но и это ещё не всё class Subtensor: def __init__(...): # Attempt to connect to chosen endpoint try: self.connect(...) except ConnectionRefusedError: _logger.error(...) exit(1)

Slide 99

Slide 99 text

Это программирование, поэтому все просто

Slide 100

Slide 100 text

Это обычный тест

Slide 101

Slide 101 text

Это обычный bash set -euxo pipefail SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

Slide 102

Slide 102 text

Это обычный код ● Посылаем задание ● После - замеряем время, за сколько нам придёт ответ ● Что может пойти не так? before_time = now() await send_request(job) start_time = now() response = await ws.recv() response_time = now() score = response_time - start_time

Slide 103

Slide 103 text

Это обычный код ● Посылаем задание ● После - замеряем время, за сколько нам придёт ответ ● Что может пойти не так? before_time = now() await send_request(job) start_time = now() response = await ws.recv() response_time = now() score = response_time - start_time

Slide 104

Slide 104 text

Это обычный npm ● Хотите установить фреймворк? ● Подождите пару минут, пока скачаются сотни зависимостей ● Не переживайте! Вряд ли хоть в одной из них есть уязвимости > npx create-next-app added 360 packages in 3m > npx create-remix 631 > npx create-gatsby 864 > npx create-react-app 1480

Slide 105

Slide 105 text

Это обычный npm ● Хотите установить фреймворк? ● Подождите пару минут, пока скачаются сотни зависимостей ● Не переживайте! Вряд ли хоть в одной из них есть уязвимости > npx create-next-app added 360 packages in 3m > npx create-remix 631 > npx create-gatsby 864 > npx create-react-app 1480

Slide 106

Slide 106 text

Это обычный npm ● Хотите установить фреймворк? ● Подождите пару минут, пока скачаются сотни зависимостей ● Не переживайте! Вряд ли хоть в одной из них есть уязвимости > npx create-next-app added 360 packages in 3m > npx create-remix 631 > npx create-gatsby 864 > npx create-react-app 1480

Slide 107

Slide 107 text

Это обычный npm ● Хотите установить фреймворк? ● Подождите пару минут, пока скачаются сотни зависимостей ● Не переживайте! Вряд ли хоть в одной из них есть уязвимости > npx create-next-app added 360 packages in 3m > npx create-remix 631 > npx create-gatsby 864 > npx create-react-app 1480

Slide 108

Slide 108 text

Это программирование, поэтому все логично

Slide 109

Slide 109 text

Бэкап postgres ● Делаем бэкап: pg_dump postgres > dump.sql

Slide 110

Slide 110 text

Бэкап postgres ● Делаем бэкап: pg_dump postgres > dump.sql ● Восстанавливаемся из бэкапа: pg_restore postgres < dump.sql

Slide 111

Slide 111 text

Бэкап postgres ● Делаем бэкап: pg_dump postgres > dump.sql ● Восстанавливаемся из бэкапа: pg_restore postgres < dump.sql pg_restore: error: input file does not appear to be a valid archive

Slide 112

Slide 112 text

Бэкап postgres ● Делаем бэкап: pg_dump postgres > dump.sql ● Восстанавливаемся из бэкапа: pg_restore postgres < dump.sql pg_restore: error: input file does not appear to be a valid archive ● psql postgres < dump.sql

Slide 113

Slide 113 text

Dockerfile args ● В Docker при сборке контейнера можно передавать параметры ● docker build --build-arg VERSION=123 FROM alpine AS base RUN echo "Base image: $VERSION" FROM base ARG VERSION RUN echo "Child image: $VERSION" #5 Base image: #6 Child image: 123 1 2

Slide 114

Slide 114 text

Dockerfile args ● В Docker при сборке контейнера можно передавать параметры ● docker build --build-arg VERSION=123 FROM alpine AS base ARG VERSION RUN echo "Base image: $VERSION" FROM base RUN echo "Child image: $VERSION" #5 Base image: 123 #6 Child image: 123 1 2

Slide 115

Slide 115 text

Dockerfile args ● В Docker при сборке контейнера можно передавать параметры ● docker build --build-arg VERSION=123 ARG VERSION FROM alpine:{$VERSION} AS base RUN echo "Base image: $VERSION" FROM base RUN echo "Child image: $VERSION" #5 Base image: #6 Child image: 1 2

Slide 116

Slide 116 text

Dockerfile args ● В Docker при сборке контейнера можно передавать параметры ● docker build --build-arg VERSION=123 ARG VERSION FROM alpine:{$VERSION} AS base RUN echo "Base image: $VERSION" FROM base RUN echo "Child image: $VERSION" #5 Base image: #6 Child image: 1 2

Slide 117

Slide 117 text

Dockerfile args ● В Docker при сборке контейнера можно передавать параметры ● docker build --build-arg VERSION=123 ARG VERSION FROM alpine:{$VERSION} AS base ARG VERSION RUN echo "Base image: $VERSION" FROM base RUN echo "Child image: $VERSION" #5 Base image: 123 #6 Child image: 123 1 2

Slide 118

Slide 118 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 119

Slide 119 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 120

Slide 120 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 121

Slide 121 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 122

Slide 122 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 123

Slide 123 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 124

Slide 124 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 125

Slide 125 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 126

Slide 126 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 127

Slide 127 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 128

Slide 128 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > [1, 2, 3] == [1, 2, 3] false > [1, 2, 3] === [1, 2, 3] false > JSON.stringify([1, 2, 3]) == JSON.stringify([1, 2, 3]) true > [-5, -2, 2, 1].sort() [-2, -5, 1, 2] > ('b' + 'a' + + 'a' + 'a') .toLowerCase() 'banana'

Slide 129

Slide 129 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 130

Slide 130 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 131

Slide 131 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 132

Slide 132 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 133

Slide 133 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 134

Slide 134 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 135

Slide 135 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 136

Slide 136 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 137

Slide 137 text

Javascript ● Да, всему этому есть логическое объяснение ● Но я не хочу это знать! > new Date(0) Thu Jan 01 1970 03:00:00 GMT+0300 (Moscow Standard Time) new Date('0') Sat Jan 01 2000 00:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024-01-01') Mon Jan 01 2024 03:00:00 GMT+0300 (Moscow Standard Time) > new Date('2024/01/01') Mon Jan 01 2024 00:00:00 GMT+0300 (Moscow Standard Time)

Slide 138

Slide 138 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 139

Slide 139 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 140

Slide 140 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 141

Slide 141 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 142

Slide 142 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 143

Slide 143 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 144

Slide 144 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 145

Slide 145 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 146

Slide 146 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! {'a': 1} # это словарь dict(a=1) # это то же самое {'a'} # это множество (set) {} # это не пустое множество, это пустой словарь set() # а вот это пустое множество

Slide 147

Slide 147 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 148

Slide 148 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 149

Slide 149 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 150

Slide 150 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 151

Slide 151 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 152

Slide 152 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 153

Slide 153 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 154

Slide 154 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 155

Slide 155 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 156

Slide 156 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 157

Slide 157 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 158

Slide 158 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 159

Slide 159 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 160

Slide 160 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! 1 # это просто число (int) (1+2) # это число (1, 2) # это кортеж (tuple) (1) # это тоже просто число 1, # это тоже кортеж () # это пустой кортеж (,) # SyntaxError

Slide 161

Slide 161 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 162

Slide 162 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 163

Slide 163 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 164

Slide 164 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 165

Slide 165 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 166

Slide 166 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 167

Slide 167 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 168

Slide 168 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 169

Slide 169 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 170

Slide 170 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это (ха-ха) кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 171

Slide 171 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это кортеж (i for i in range(3)) # это не кортеж, это генератор :D

Slide 172

Slide 172 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это кортеж (i for i in range(3)) # это не кортеж, это генератор

Slide 173

Slide 173 text

Python: скобки ● Ну да, ну да, вот наш питон-то простой и логичный! [] # это пустой список [1] # это список с одним элементом [1, 2, 3] # это список с 3 элементами [i for i in range(3)] # это тоже список с 3 элементами () # это пустой кортеж (1) # это просто число (1, 2, 3) # это кортеж (i for i in range(3)) # это не кортеж, это генератор

Slide 174

Slide 174 text

Python: не даст отстрелить ногу ● Удобно, что питон отслеживает потенциально опасные места и не даёт нам делать плохие вещи data = {1: 2} for key, value in data.items(): data[key+1] = value+1 RuntimeError: dictionary changed size during iteration data = [1, 2] for value in data: data.append(value+1) Всё ок! Прощай, RAM :)

Slide 175

Slide 175 text

Python: не даст отстрелить ногу ● Удобно, что питон отслеживает потенциально опасные места и не даёт нам делать плохие вещи data = {1: 2} for key, value in data.items(): data[key+1] = value+1 RuntimeError: dictionary changed size during iteration data = [1, 2] for value in data: data.append(value+1) Всё ок! Прощай, RAM :)

Slide 176

Slide 176 text

Python: не даст отстрелить ногу ● Удобно, что питон отслеживает потенциально опасные места и не даёт нам делать плохие вещи data = {1: 2} for key, value in data.items(): data[key+1] = value+1 RuntimeError: dictionary changed size during iteration data = [1, 2] for value in data: data.append(value+1) Всё ок! Прощай, RAM :)

Slide 177

Slide 177 text

Python: не даст отстрелить ногу ● Удобно, что питон отслеживает потенциально опасные места и не даёт нам делать плохие вещи data = {1: 2} for key, value in data.items(): data[key+1] = value+1 RuntimeError: dictionary changed size during iteration data = [1, 2] for value in data: data.append(value+1) Всё ок!

Slide 178

Slide 178 text

Pytest > ls bot.py config.py history.py knowledge.py logs.py __main__.py models.py __pycache__/ shell.py tests/ tools.py utils.py

Slide 179

Slide 179 text

Pytest > ls bot.py config.py history.py knowledge.py logs.py __main__.py models.py __pycache__/ shell.py tests/ tools.py utils.py > pdm run pytest . ERROR collecting src/tests/test_bot.py ImportError while importing test module '/home/user/workspace/project/src/tests/test_bot.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: .pyenv/versions/3.11.4/lib/python3.11/importlib/__init__.py:126: in import_module return _bootstrap._gcd_import(name[level:], package, level) tests/test_bot.py:3: in from ..bot import message_handler E ImportError: attempted relative import beyond top-level package

Slide 180

Slide 180 text

Pytest > touch __init__.py > pdm run pytest . tests/test_bot.py

Slide 181

Slide 181 text

Dataclass @dataclass class Base: a: str class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) Child(a='test') > Child(a=’test’, b=’test’) TypeError: Base.__init__() got an unexpected keyword argument 'b'

Slide 182

Slide 182 text

Dataclass @dataclass class Base: a: str class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) Child(a='test') > Child(a=’test’, b=’test’) TypeError: Base.__init__() got an unexpected keyword argument 'b'

Slide 183

Slide 183 text

Dataclass @dataclass class Base: a: str class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) Child(a='test') > Child(a=’test’, b=’test’) TypeError: Base.__init__() got an unexpected keyword argument 'b'

Slide 184

Slide 184 text

Dataclass @dataclass class Base: a: str class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) Child(a='test') > Child(a=’test’, b=’test’) TypeError: Base.__init__() got an unexpected keyword argument 'b'

Slide 185

Slide 185 text

Dataclass @dataclass class Base: a: str class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) Child(a='test') > Child(a=’test’, b=’test’) TypeError: Base.__init__() got an unexpected keyword argument 'b'

Slide 186

Slide 186 text

Dataclass @dataclass class Base: a: str @dataclass class Child(Base): b: str > Base() TypeError: Base.__init__() missing 1 required positional argument: 'a' > Base(a=’test’) Base(a='test') > Child(a=’test’) TypeError: Child.__init__() missing 1 required positional argument: 'b' > Child(a=’test’, b=’test’) Child(a='test', b='test2')

Slide 187

Slide 187 text

Это программирование, поэтому никакой неведомой фигни не происходит

Slide 188

Slide 188 text

Pull request ● Создаю как обычно PR в master ● Ловлю конфликт с файлом, которого у меня нет ● Но который есть в master master

Slide 189

Slide 189 text

Pull request ● Создаю как обычно PR в master ● Ловлю конфликт с файлом, которого у меня нет ● Но который есть в master master

Slide 190

Slide 190 text

Pull request # ci.yml test: steps: - uses: actions/checkout@v3 with: fetch-depth: 0 master

Slide 191

Slide 191 text

PgBouncer ● Приложения можно подключать к базе напрямую App Postgres

Slide 192

Slide 192 text

PgBouncer ● Приложения можно подключать к базе напрямую ● Но если их много, то слишком много соединений с БД App Postgres App App App App App

Slide 193

Slide 193 text

PgBouncer ● Приложения можно подключать к базе напрямую ● Но если их много, то слишком много соединений с БД ● Решение - PgBouncer, который управляет пулом соединений App Postgres App App App App App PgBouncer

Slide 194

Slide 194 text

PgBouncer ● Делаем бэкап: pg_dump postgres > dump.sql -- dump.sql SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config( 'search_path', '', false); SET check_function_bodies = false; SET xmloption = content; SET client_min_messages = warning; SET row_security = off; ...

Slide 195

Slide 195 text

PgBouncer ● Делаем бэкап: pg_dump postgres > dump.sql ● Восстанавливаемся из бэкапа: psql postgres < dump.sql -- dump.sql SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config( 'search_path', '', false); SET check_function_bodies = false; SET xmloption = content; SET client_min_messages = warning; SET row_security = off; ...

Slide 196

Slide 196 text

No content

Slide 197

Slide 197 text

PgBouncer ● SELECT pg_catalog.set_config( 'search_path', '', false); ● “Забудь всё, что ты знал до этого” App Postgres App App psql App PgBouncer

Slide 198

Slide 198 text

PgBouncer ● SELECT pg_catalog.set_config( 'search_path', '', false); ● “Забудь всё, что ты знал до этого” App Postgres App App App PgBouncer

Slide 199

Slide 199 text

PgBouncer ● SELECT pg_catalog.set_config( 'search_path', '', false); ● “Забудь всё, что ты знал до этого” App Postgres App App psql App PgBouncer

Slide 200

Slide 200 text

Это программирование, поэтому помощь повсюду: документация, IDE, LLM, …

Slide 201

Slide 201 text

PDM > pdm add django-attachments~=1.5 django-bleach~=0.6.1 django-bootstrap3~=12.1.0 django-cacheops~=7.0.2 django-ckeditor~=5.9.0 django-contrib-comments~=1.9.2 django-cors-headers~=3.7.0 django-debug-toolbar~=3.5.0 django-elasticsearch-dsl~=7.1.1 django-filter~=2.3.0 Adding packages to default dependencies: django-attachments~=1.5, django-bleach~=0.6.1, django-bootstrap3~=12.1.0, django-cacheops~=7.0.2, django-ckeditor~=5.9.0, django-contrib-comments~=1.9.2, django-cors-headers~=3.7.0, django-debug-toolbar~=3.5.0, django-elasticsearch-dsl~=7.1.1, django-filter~=2.3.0

Slide 202

Slide 202 text

PDM > pdm add django-attachments~=1.5 django-bleach~=0.6.1 django-bootstrap3~=12.1.0 django-cacheops~=7.0.2 django-ckeditor~=5.9.0 django-contrib-comments~=1.9.2 django-cors-headers~=3.7.0 django-debug-toolbar~=3.5.0 django-elasticsearch-dsl~=7.1.1 django-filter~=2.3.0 Adding packages to default dependencies: django-attachments~=1.5, django-bleach~=0.6.1, django-bootstrap3~=12.1.0, django-cacheops~=7.0.2, django-ckeditor~=5.9.0, django-contrib-comments~=1.9.2, django-cors-headers~=3.7.0, django-debug-toolbar~=3.5.0, django-elasticsearch-dsl~=7.1.1, django-filter~=2.3.0 0:00:09 🔒 Lock failed. ERROR:

Slide 203

Slide 203 text

PDM > pdm add django-attachments~=1.5 django-bleach~=0.6.1 django-bootstrap3~=12.1.0 django-cacheops~=7.0.2 django-ckeditor~=5.9.0 django-contrib-comments~=1.9.2 django-cors-headers~=3.7.0 django-debug-toolbar~=3.5.0 django-elasticsearch-dsl~=7.1.1 django-filter~=2.3.0 Adding packages to default dependencies: django-attachments~=1.5, django-bleach~=0.6.1, django-bootstrap3~=12.1.0, django-cacheops~=7.0.2, django-ckeditor~=5.9.0, django-contrib-comments~=1.9.2, django-cors-headers~=3.7.0, django-debug-toolbar~=3.5.0, django-elasticsearch-dsl~=7.1.1, django-filter~=2.3.0 0:00:09 🔒 Lock failed. ERROR: 0:00:09 🔒 Lock failed.

Slide 204

Slide 204 text

PDM > pdm add django-attachments~=1.5 django-bleach~=0.6.1 django-bootstrap3~=12.1.0 django-cacheops~=7.0.2 django-ckeditor~=5.9.0 django-contrib-comments~=1.9.2 django-cors-headers~=3.7.0 django-debug-toolbar~=3.5.0 django-elasticsearch-dsl~=7.1.1 django-filter~=2.3.0 Adding packages to default dependencies: django-attachments~=1.5, django-bleach~=0.6.1, django-bootstrap3~=12.1.0, django-cacheops~=7.0.2, django-ckeditor~=5.9.0, django-contrib-comments~=1.9.2, django-cors-headers~=3.7.0, django-debug-toolbar~=3.5.0, django-elasticsearch-dsl~=7.1.1, django-filter~=2.3.0 0:00:09 🔒 Lock failed. ERROR: 0:00:09 🔒 Lock failed. See /home/user/.local/state/pdm/log/pdm-lock-4aauctl8.log for detailed debug log. [ResolutionImpossible]: Unable to find a resolution WARNING: Add '-v' to see the detailed traceback

Slide 205

Slide 205 text

Мой любимый def parse_json_markdown( json_string: str, *, parser: Callable[[str], Any] = parse_partial_json ) -> dict: """ Parse a JSON string from a Markdown string. Args: json_string: The Markdown string. Returns: The parsed JSON object as a Python dictionary. """

Slide 206

Slide 206 text

Мой любимый vscode

Slide 207

Slide 207 text

Мой любимый vscode

Slide 208

Slide 208 text

Мой любимый vscode

Slide 209

Slide 209 text

Мой любимый vscode

Slide 210

Slide 210 text

Мой любимый vscode

Slide 211

Slide 211 text

Мой любимый vscode

Slide 212

Slide 212 text

Vscode: почему?! ● Пора уже разобраться ● Всё, что до синтаксической ошибки - работает ● Всё, что после - не работает Б р о Н е б р о

Slide 213

Slide 213 text

Celery flower, что ты умеешь? > celery flower --help Usage: celery flower [OPTIONS] [TORNADO_ARGV]... Web based tool for monitoring and administrating Celery clusters. Options: --help Show this message and exit.

Slide 214

Slide 214 text

Copilot А дальше сам!

Slide 215

Slide 215 text

ChatGPT

Slide 216

Slide 216 text

ChatGPT jobs: linter: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ env.PYTHON_DEFAULT_VERSION }} uses: actions/setup-python@v4 - name: Install dependencies run: python -m pip install --upgrade nox 'pdm>=2.12,<3' - name: Run linters run: nox -vs lint

Slide 217

Slide 217 text

ChatGPT

Slide 218

Slide 218 text

ChatGPT

Slide 219

Slide 219 text

ChatGPT

Slide 220

Slide 220 text

ChatGPT

Slide 221

Slide 221 text

ChatGPT

Slide 222

Slide 222 text

ChatGPT

Slide 223

Slide 223 text

ChatGPT

Slide 224

Slide 224 text

ChatGPT

Slide 225

Slide 225 text

ChatGPT

Slide 226

Slide 226 text

ChatGPT

Slide 227

Slide 227 text

ChatGPT

Slide 228

Slide 228 text

ChatGPT

Slide 229

Slide 229 text

ChatGPT

Slide 230

Slide 230 text

ChatGPT

Slide 231

Slide 231 text

ChatGPT

Slide 232

Slide 232 text

ChatGPT

Slide 233

Slide 233 text

ChatGPT

Slide 234

Slide 234 text

ChatGPT

Slide 235

Slide 235 text

ChatGPT

Slide 236

Slide 236 text

ChatGPT

Slide 237

Slide 237 text

ChatGPT

Slide 238

Slide 238 text

Ruff last_weights = Weights.objects.order_by('-created_at').first() if ( last_weights and last_weights.revealed_at is None and last_weights.block <= current_block_number - (reveal_weights_interval - reveal_in_advance) ):

Slide 239

Slide 239 text

Ruff last_weights = Weights.objects.order_by('-created_at').first() if ( last_weights and last_weights.revealed_at is None and last_weights.block <= current_block_number - (reveal_weights_interval - reveal_in_advance) ):

Slide 240

Slide 240 text

Ruff calls = [ ("archive", dump.netuid, block) for block in list(chain.from_iterable(dumpable_blocks))[::-1] if block != 1673 ] Что получаем Откуда Фильтр

Slide 241

Slide 241 text

Ruff calls = [ ("archive", dump.netuid, block) for block in list(chain.from_iterable(dumpable_blocks))[::-1] if block != 1 ]

Slide 242

Slide 242 text

Pytest: рецепт успеха > pytest -W ignore::DeprecationWarning -s -x -vv tests -k test_set_scores == test session starts == platform linux -- Python 3.11.4, pytest-8.2.2, pluggy-1.5.0 rootdir: /home/user/workspace/ configfile: pytest.ini plugins: xdist-3.6.1, anyio-4.4.0, django-constance-3.1.0, asyncio-0.23.7 asyncio: mode=Mode.STRICT collected 1 item / 1 deselected / 0 selected == 1 deselected in 0.21s ==

Slide 243

Slide 243 text

React ● В документации вот такой код const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = "X"; setSquares(nextSquares); } X

Slide 244

Slide 244 text

React ● В документации вот такой код ● Минут пять убиваю, чтобы понять, зачем делать слайс и менять в нём только первый элемент ● Так нихрена и не понял ● Ладно, читаю дальше const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = "X"; setSquares(nextSquares); } X

Slide 245

Slide 245 text

React “Теперь вы можете добавлять крестики на доску… но только в верхний левый квадрат. Ваша функция "handleClick" жестко запрограммирована для обновления индекса для верхнего левого квадрата (0). Давайте обновим "handleClick", чтобы иметь возможность обновлять любой квадрат.” const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = "X"; setSquares(nextSquares); } X

Slide 246

Slide 246 text

Это программирование, поэтому всё надёжно

Slide 247

Slide 247 text

Github

Slide 248

Slide 248 text

Github Форкаем публичный репо Случайно коммитим ключ В ужасе удаляем форк

Slide 249

Slide 249 text

Github Кто-то нас форкнул 10 лет назад Случайно коммитим ключ В ужасе удаляем свой репо

Slide 250

Slide 250 text

Github Есть приватный репо Форкаем и добавляем ключи Делаем приватный репо публичным

Slide 251

Slide 251 text

Это программирование, поэтому ну его к чёрту!

Slide 252

Slide 252 text

Beer Meetup ● Прихожу в бар

Slide 253

Slide 253 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой

Slide 254

Slide 254 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой ● Никого нет

Slide 255

Slide 255 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой ● Никого нет ● Приходят какие-то девушки

Slide 256

Slide 256 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой ● Никого нет ● Приходят какие-то девушки ● Я им затираю про питон, они ничего не понимают

Slide 257

Slide 257 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой ● Никого нет ● Приходят какие-то девушки ● Я им затираю про питон, они ничего не понимают ● Проверяю календарь

Slide 258

Slide 258 text

Beer Meetup ● Прихожу в бар ● Сижу полчаса наедине с выпивкой ● Никого нет ● Приходят какие-то девушки ● Я им затираю про питон, они ничего не понимают ● Проверяю календарь ● Я перепутал даты и пришёл ровно на неделю раньше

Slide 259

Slide 259 text

Я же говорил: Это вообще не просто!

Slide 260

Slide 260 text

Спасибо за внимание! Блог погромиста https://pogrom.dev