matthew-ide 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- matthew_ide/.DS_Store +0 -0
- matthew_ide/__init__.py +15 -0
- matthew_ide/app/.DS_Store +0 -0
- matthew_ide/app/dev_runner.py +3 -0
- matthew_ide/app/matthew_app.py +114 -0
- matthew_ide/app/runner.py +10 -0
- matthew_ide/assets/demo.yaml +421 -0
- matthew_ide/features/.DS_Store +0 -0
- matthew_ide/features/app_folder/__init__.py +44 -0
- matthew_ide/features/events/__init__.py +5 -0
- matthew_ide/features/events/hook.py +51 -0
- matthew_ide/features/events/sender/__init__.py +0 -0
- matthew_ide/features/events/sender/api_sender.py +62 -0
- matthew_ide/features/events/sender/event_sender.py +32 -0
- matthew_ide/features/events/sender/no_sender.py +11 -0
- matthew_ide/features/run_code/__init__.py +80 -0
- matthew_ide/features/run_code/_runner.py +160 -0
- matthew_ide/features/update/__init__.py +56 -0
- matthew_ide/py.typed +0 -0
- matthew_ide/screens/.DS_Store +0 -0
- matthew_ide/screens/code_simulator/__init__.py +7 -0
- matthew_ide/screens/code_simulator/components/code_editor.py +93 -0
- matthew_ide/screens/code_simulator/components/current_task_info.py +33 -0
- matthew_ide/screens/code_simulator/components/explorer.py +137 -0
- matthew_ide/screens/code_simulator/components/test_results/__init__.py +5 -0
- matthew_ide/screens/code_simulator/components/test_results/result_item.py +59 -0
- matthew_ide/screens/code_simulator/components/test_results/test_results.py +54 -0
- matthew_ide/screens/code_simulator/editor.tcss +19 -0
- matthew_ide/screens/code_simulator/model.py +87 -0
- matthew_ide/screens/code_simulator/screen.py +172 -0
- matthew_ide/screens/message_box/mb_screen.py +38 -0
- matthew_ide/screens/message_box/mb_screen.tcss +49 -0
- matthew_ide/screens/save_question/__init__.py +39 -0
- matthew_ide/screens/save_question/styles.tcss +49 -0
- matthew_ide/screens/welcome/__init__.py +107 -0
- matthew_ide/screens/welcome/styles.tcss +42 -0
- matthew_ide/shared/.DS_Store +0 -0
- matthew_ide/shared/__init__.py +19 -0
- matthew_ide/shared/io/__init__.py +0 -0
- matthew_ide/shared/io/load.py +133 -0
- matthew_ide/shared/io/save_quiz.py +72 -0
- matthew_ide/shared/state/__init__.py +11 -0
- matthew_ide/shared/state/data_state.py +151 -0
- matthew_ide-1.2.0.dist-info/METADATA +40 -0
- matthew_ide-1.2.0.dist-info/RECORD +47 -0
- matthew_ide-1.2.0.dist-info/WHEEL +4 -0
- matthew_ide-1.2.0.dist-info/entry_points.txt +3 -0
matthew_ide/.DS_Store
ADDED
|
Binary file
|
matthew_ide/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
__version__ = version(__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
APP_PACKAGE_NAME = "analyst-klondike"
|
|
8
|
+
APP_FOLDER_NAME = "AnalystKlondike"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
WELLCOME_SCREEN_APP_NAME = "Клондайк аналитика"
|
|
12
|
+
WELCOME_SCREEN_APP_TITLE = "Klondike"
|
|
13
|
+
WELCOME_SCREEN_APP_SUBTITLE = "code editor"
|
|
14
|
+
|
|
15
|
+
EVENT_DESTINATION: Literal["local_db", "remote_db", "no_events"] = "local_db"
|
|
Binary file
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import pyperclip # type: ignore
|
|
6
|
+
from textual import on, work
|
|
7
|
+
from textual.reactive import reactive
|
|
8
|
+
from textual.app import App
|
|
9
|
+
|
|
10
|
+
from matthew_ide import APP_PACKAGE_NAME
|
|
11
|
+
from matthew_ide.features.app_folder import init_app_working_folder
|
|
12
|
+
from matthew_ide.features.events import send_event
|
|
13
|
+
from matthew_ide.features.update import is_outdated
|
|
14
|
+
from matthew_ide.screens.code_simulator import CodeSimulatorScreen
|
|
15
|
+
from matthew_ide.screens.message_box.mb_screen import MessageBoxScreen
|
|
16
|
+
from matthew_ide.screens.save_question import SaveQuestion, SaveQuestionModalResult
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MatthewApp(App[int]):
|
|
20
|
+
|
|
21
|
+
MODES = { # type: ignore
|
|
22
|
+
"code_simulator": CodeSimulatorScreen,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
demo_file_name = reactive("demo.yaml")
|
|
26
|
+
save_func: reactive[Callable[[], None] | None] = reactive(None)
|
|
27
|
+
|
|
28
|
+
@work
|
|
29
|
+
async def on_mount(self) -> None:
|
|
30
|
+
self.theme = "textual-dark"
|
|
31
|
+
self.title = self.app_title
|
|
32
|
+
self.sub_title = "Интерактивный тренажер Python на вашем компьютере"
|
|
33
|
+
|
|
34
|
+
self._try_init_app()
|
|
35
|
+
self.send_event("app_opened")
|
|
36
|
+
await self._display_message_if_app_outdated()
|
|
37
|
+
|
|
38
|
+
self.switch_mode("code_simulator")
|
|
39
|
+
|
|
40
|
+
def send_event(
|
|
41
|
+
self,
|
|
42
|
+
event_name: str,
|
|
43
|
+
event_json: dict[str, str | int | bool] | None = None) -> None:
|
|
44
|
+
send_event(self, event_name, event_location="/", event_json=event_json)
|
|
45
|
+
|
|
46
|
+
async def _display_message_if_app_outdated(self) -> None:
|
|
47
|
+
update_check = is_outdated()
|
|
48
|
+
|
|
49
|
+
if update_check is None:
|
|
50
|
+
await self.push_screen_wait(MessageBoxScreen(
|
|
51
|
+
message="Ошибка при загрузке последней версии приложения"
|
|
52
|
+
))
|
|
53
|
+
self.send_event("fail_to_get_latest_version")
|
|
54
|
+
self.exit()
|
|
55
|
+
if update_check and update_check.is_outdated:
|
|
56
|
+
await self.push_screen_wait(MessageBoxScreen(
|
|
57
|
+
message=f"Доступна новая версия {update_check.latest_version} " +
|
|
58
|
+
f"(сейчас установлена {update_check.current_version}). \n"
|
|
59
|
+
"Обновите приложение. \n" +
|
|
60
|
+
"Для этого закройте приложение и запустите команду: \n" +
|
|
61
|
+
"[@click=app.copy_update_str_to_clipboard]uv tool upgrade analyst-klondike[/]"
|
|
62
|
+
))
|
|
63
|
+
self.send_event("app_is_outdated")
|
|
64
|
+
self.exit()
|
|
65
|
+
|
|
66
|
+
@on(CodeSimulatorScreen.NotifyToChangeAppTitle)
|
|
67
|
+
def on_task_selected(self, event: CodeSimulatorScreen.NotifyToChangeAppTitle) -> None:
|
|
68
|
+
self.sub_title = event.task_title
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def app_title(self) -> str:
|
|
72
|
+
try:
|
|
73
|
+
return f"Клондайк аналитика {version(APP_PACKAGE_NAME)}"
|
|
74
|
+
except PackageNotFoundError:
|
|
75
|
+
return "Клондайк аналитика"
|
|
76
|
+
|
|
77
|
+
# Copy to clipboard update string
|
|
78
|
+
def action_copy_update_str_to_clipboard(self) -> None:
|
|
79
|
+
try:
|
|
80
|
+
pyperclip.copy('uv tool upgrade analyst-klondike')
|
|
81
|
+
self.notify(
|
|
82
|
+
message="Скопировано uv tool upgrade analyst-klondike",
|
|
83
|
+
title="Клондайк аналитика",
|
|
84
|
+
severity="information"
|
|
85
|
+
)
|
|
86
|
+
self.send_event("update_command_is_copied")
|
|
87
|
+
except Exception: # pylint: disable=W0718
|
|
88
|
+
self.notify(
|
|
89
|
+
message="Ошибка при копировании uv tool upgrade analyst-klondike в буфер обмена",
|
|
90
|
+
title="Клондайк аналитика",
|
|
91
|
+
severity="error"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
async def action_quit(self) -> None:
|
|
95
|
+
def _callback(res: SaveQuestionModalResult | None) -> None:
|
|
96
|
+
if res == "save":
|
|
97
|
+
if self.save_func:
|
|
98
|
+
self.save_func()
|
|
99
|
+
if res != "cancel":
|
|
100
|
+
self.send_event("app_normally_closed")
|
|
101
|
+
self.exit(0)
|
|
102
|
+
|
|
103
|
+
self.push_screen(SaveQuestion(), _callback)
|
|
104
|
+
|
|
105
|
+
def _try_init_app(self) -> None:
|
|
106
|
+
try:
|
|
107
|
+
init_app_working_folder()
|
|
108
|
+
self.send_event("app_folder_created")
|
|
109
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
110
|
+
self.send_event("fail_to_create_app_folder")
|
|
111
|
+
self.notify(
|
|
112
|
+
"Не удалось создать папку с данными приложения",
|
|
113
|
+
severity="error"
|
|
114
|
+
)
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
quiz_info:
|
|
2
|
+
min_supported_app_version: 1.0.17
|
|
3
|
+
user_info:
|
|
4
|
+
email: analyst_klondike
|
|
5
|
+
quizes:
|
|
6
|
+
python_basics:
|
|
7
|
+
title: Основы Python
|
|
8
|
+
questions:
|
|
9
|
+
Изменить порядок слов в предложении:
|
|
10
|
+
text: "Дано предложение, без запятых, только английские символы, используются\
|
|
11
|
+
\ только строчные буквы. \n\nНаписать функцию, меняющую порядок слов в предложении\
|
|
12
|
+
\ на обратный. \n\nНапример 'the sky is blue' -> 'blue is sky the'"
|
|
13
|
+
code_template: "def solution(s: str) -> str:\n pass"
|
|
14
|
+
code: "def solution(s: str) -> str:\n words = s.split()\n rev = reversed(words)\n\
|
|
15
|
+
\ return \" \".join(rev) "
|
|
16
|
+
test_cases:
|
|
17
|
+
- s: hello
|
|
18
|
+
expected: hello
|
|
19
|
+
- s: hello world
|
|
20
|
+
expected: world hello
|
|
21
|
+
- s: all work and no play makes jack a dull boy
|
|
22
|
+
expected: boy dull a jack makes play no and work all
|
|
23
|
+
is_passed: passed
|
|
24
|
+
params:
|
|
25
|
+
s: str
|
|
26
|
+
return: str
|
|
27
|
+
Сумма всех четных чисел до N:
|
|
28
|
+
text: Напишите функцию, которая вычисляет сумму всех четных чисел в промежутке
|
|
29
|
+
от 1 до N, включая N.
|
|
30
|
+
code_template: "def solution(n: int):\n return 0"
|
|
31
|
+
code: "def solution(n: int):\n return 0"
|
|
32
|
+
test_cases:
|
|
33
|
+
- n: 1
|
|
34
|
+
expected: 0
|
|
35
|
+
- n: 10
|
|
36
|
+
expected: 30
|
|
37
|
+
- n: 19
|
|
38
|
+
expected: 90
|
|
39
|
+
is_passed: failed
|
|
40
|
+
params:
|
|
41
|
+
n: int
|
|
42
|
+
return: int
|
|
43
|
+
Разворот числа:
|
|
44
|
+
text: 'Напишите программу, которая развернет число: 12345 -> 54321. Для отрицательных
|
|
45
|
+
чисел вернуть тоже самое число (без разворотов). Считаем, что функция принимает
|
|
46
|
+
только натуральные числа.'
|
|
47
|
+
code_template: "def solution(n: int):\n return n"
|
|
48
|
+
code: "def solution(n: int):\n print(\"Hello, world\")\n return n"
|
|
49
|
+
test_cases:
|
|
50
|
+
- n: 0
|
|
51
|
+
expected: 0
|
|
52
|
+
- n: 123
|
|
53
|
+
expected: 321
|
|
54
|
+
- n: 123456
|
|
55
|
+
expected: 654321
|
|
56
|
+
is_passed: failed
|
|
57
|
+
params:
|
|
58
|
+
n: int
|
|
59
|
+
return: int
|
|
60
|
+
more_difficult_tasks:
|
|
61
|
+
title: Сложные задачи по Python
|
|
62
|
+
questions:
|
|
63
|
+
Самый длинный префикс:
|
|
64
|
+
text: "Дан список слов. \nНаписать функцию, которая вернет самый длинный префикс.\n\
|
|
65
|
+
Префикс - набор букв, с которых начинается слово.\nНапример:\n - solution(['flower',\
|
|
66
|
+
\ 'flow', 'flight']) -> 'fl'"
|
|
67
|
+
code_template: "def solution(words: list[str]) -> str:\n return ''"
|
|
68
|
+
code: "def solution(words: list[str]) -> str:\n return ''"
|
|
69
|
+
test_cases:
|
|
70
|
+
- words:
|
|
71
|
+
- flower
|
|
72
|
+
- flow
|
|
73
|
+
- flight
|
|
74
|
+
expected: fl
|
|
75
|
+
- words:
|
|
76
|
+
- abc
|
|
77
|
+
- xyz
|
|
78
|
+
- hgf
|
|
79
|
+
expected: ''
|
|
80
|
+
- words:
|
|
81
|
+
- europe
|
|
82
|
+
- europe
|
|
83
|
+
- europe
|
|
84
|
+
expected: europe
|
|
85
|
+
is_passed: not_runned
|
|
86
|
+
params:
|
|
87
|
+
words: list
|
|
88
|
+
return: str
|
|
89
|
+
Сумма чисел:
|
|
90
|
+
text: 'Дан массив чисел и число target. Написать функцию, которая вернет список,
|
|
91
|
+
состоящий из двух индексов элементов, которые в сумме дают число target.
|
|
92
|
+
Допустим, что в массиве существует только одна пара таких элементов.
|
|
93
|
+
|
|
94
|
+
Например:
|
|
95
|
+
|
|
96
|
+
- solution([2,7,11,15], 9) -> [0,1], т.к. 2 + 7 = 9, числа находятся на
|
|
97
|
+
позициях 0 и 1 соответственно.'
|
|
98
|
+
code_template: "def solution(nums: list, target: int) -> list[int]:\n return\
|
|
99
|
+
\ []"
|
|
100
|
+
code: "def solution(nums: list, target: int) -> list[int]:\n return []"
|
|
101
|
+
test_cases:
|
|
102
|
+
- nums:
|
|
103
|
+
- 2
|
|
104
|
+
- 7
|
|
105
|
+
- 11
|
|
106
|
+
- 15
|
|
107
|
+
target: 9
|
|
108
|
+
expected:
|
|
109
|
+
- 0
|
|
110
|
+
- 1
|
|
111
|
+
- nums:
|
|
112
|
+
- 2
|
|
113
|
+
- 7
|
|
114
|
+
- 11
|
|
115
|
+
- 15
|
|
116
|
+
target: 18
|
|
117
|
+
expected:
|
|
118
|
+
- 1
|
|
119
|
+
- 2
|
|
120
|
+
is_passed: not_runned
|
|
121
|
+
params:
|
|
122
|
+
nums: list
|
|
123
|
+
target: int
|
|
124
|
+
return: list
|
|
125
|
+
Группировка анаграмм:
|
|
126
|
+
text: 'Написать функцию, которая группирует слова-анаграммы вместе.
|
|
127
|
+
|
|
128
|
+
Например для списка слов [''eat'',''tea'',''the'',''teh'',''hte'',''abc'',''edf'']
|
|
129
|
+
функция должна вернуть
|
|
130
|
+
|
|
131
|
+
[[''eat'',''tea''], [''the'',''teh'',''hte''], ''abc'',''edf''].
|
|
132
|
+
|
|
133
|
+
Два слова являются анаграммами если они состоят из одних и тех же букв,
|
|
134
|
+
но в разном порядке.'
|
|
135
|
+
code_template: "def solution(words: list):\n return []"
|
|
136
|
+
code: "def solution(words: list):\n return []"
|
|
137
|
+
test_cases:
|
|
138
|
+
- words:
|
|
139
|
+
- eat
|
|
140
|
+
- tea
|
|
141
|
+
- the
|
|
142
|
+
- teh
|
|
143
|
+
- hte
|
|
144
|
+
- abc
|
|
145
|
+
- edf
|
|
146
|
+
expected:
|
|
147
|
+
- - eat
|
|
148
|
+
- tea
|
|
149
|
+
- - the
|
|
150
|
+
- teh
|
|
151
|
+
- hte
|
|
152
|
+
- abc
|
|
153
|
+
- edf
|
|
154
|
+
is_passed: not_runned
|
|
155
|
+
params:
|
|
156
|
+
words: list
|
|
157
|
+
return: list
|
|
158
|
+
list_string_tasks:
|
|
159
|
+
title: Списки и строки
|
|
160
|
+
questions:
|
|
161
|
+
Поиск подстрок:
|
|
162
|
+
text: 'Написать функцию, которая принимает строку subs и строку long_string.
|
|
163
|
+
|
|
164
|
+
Функция вернет список индексов всех вхождений подстроки subs в строке long_string.
|
|
165
|
+
|
|
166
|
+
Номера позиций начинаются с нуля.
|
|
167
|
+
|
|
168
|
+
Например:
|
|
169
|
+
|
|
170
|
+
- подстрока "hello" встречается в строке "hello, world, all people hello"
|
|
171
|
+
два раза: на позиции 0 (начало строки) и 25.
|
|
172
|
+
|
|
173
|
+
- подстрока "xyz" встречается в строке "abc def xyz ghr" один раз на позиции
|
|
174
|
+
8.
|
|
175
|
+
|
|
176
|
+
Таким образом:
|
|
177
|
+
|
|
178
|
+
- solution("hello, world, all people hello") -> [0, 25]
|
|
179
|
+
|
|
180
|
+
- solution("xyz", "abc def xyz ghr") -> [8]
|
|
181
|
+
|
|
182
|
+
- solution("", "my string") -> [] (для пустой строки вернет пустой список)
|
|
183
|
+
|
|
184
|
+
- solution("hello", "ok, great!") -> [] (нет вхождений)'
|
|
185
|
+
code_template: "def solution(subs: str, long_string: str):\n return []"
|
|
186
|
+
code: "def solution(subs: str, long_string: str):\n return []"
|
|
187
|
+
test_cases:
|
|
188
|
+
- subs: abc
|
|
189
|
+
long_string: _abc_abc
|
|
190
|
+
expected:
|
|
191
|
+
- 1
|
|
192
|
+
- 5
|
|
193
|
+
- subs: hello
|
|
194
|
+
long_string: hello world hello
|
|
195
|
+
expected:
|
|
196
|
+
- 0
|
|
197
|
+
- 12
|
|
198
|
+
- subs: xyz
|
|
199
|
+
long_string: abc def xyz ghr
|
|
200
|
+
expected:
|
|
201
|
+
- 8
|
|
202
|
+
is_passed: not_runned
|
|
203
|
+
params:
|
|
204
|
+
subs: str
|
|
205
|
+
long_string: str
|
|
206
|
+
return: list
|
|
207
|
+
Нерадивый ученик:
|
|
208
|
+
text: 'Ученик написал на доске предложение:
|
|
209
|
+
|
|
210
|
+
''привет, мир. какая хорошая погода. мне все нравится.''
|
|
211
|
+
|
|
212
|
+
Но он забыл, что предложения начинаются с большой буквы.
|
|
213
|
+
|
|
214
|
+
Напишите функцию, которая принимает строку с таким предложением и возвращает
|
|
215
|
+
новую строку, где все предложения начинаются с большой буквы.
|
|
216
|
+
|
|
217
|
+
Считаем, что предложение может заканчиваться только точкой.'
|
|
218
|
+
code_template: "def solution(sentence: str):\n return ''"
|
|
219
|
+
code: "def solution(sentence: str):\n return ''"
|
|
220
|
+
test_cases:
|
|
221
|
+
- sentence: ''
|
|
222
|
+
expected: ''
|
|
223
|
+
- sentence: привет.
|
|
224
|
+
expected: Привет.
|
|
225
|
+
- sentence: анализ данных - лучшая профессия.
|
|
226
|
+
expected: Анализ данных - лучшая профессия.
|
|
227
|
+
- sentence: привет, мир. какая хорошая погода. мне все нравится.
|
|
228
|
+
expected: Привет, мир. Какая хорошая погода. Мне все нравится.
|
|
229
|
+
is_passed: not_runned
|
|
230
|
+
params:
|
|
231
|
+
sentence: str
|
|
232
|
+
return: str
|
|
233
|
+
Аббревиатура:
|
|
234
|
+
text: 'Напишите функцию, которая принимает название учреждения и возвращает
|
|
235
|
+
аббревиатуру.
|
|
236
|
+
|
|
237
|
+
Например: - Министерство Иностранных Дел -> МИД - Российская Федерация ->
|
|
238
|
+
РФ
|
|
239
|
+
|
|
240
|
+
Нельзя привязываться к числу слов, их может быть бесконечное число. Буквы
|
|
241
|
+
в entity могут быть как большими, так и маленькими. Если в entity одно слово,
|
|
242
|
+
то вернуть его первую букву, например: ''учреждение'' -> ''У'''
|
|
243
|
+
code_template: "def solution(entity: str):\n return ''"
|
|
244
|
+
code: "def solution(entity: str):\n return ''"
|
|
245
|
+
test_cases:
|
|
246
|
+
- entity: ''
|
|
247
|
+
expected: ''
|
|
248
|
+
- entity: учреждение
|
|
249
|
+
expected: У
|
|
250
|
+
- entity: Российская Федерация
|
|
251
|
+
expected: РФ
|
|
252
|
+
- entity: министерство иностранных дел
|
|
253
|
+
expected: МИД
|
|
254
|
+
- entity: союз советских социалистических республик
|
|
255
|
+
expected: СССР
|
|
256
|
+
is_passed: not_runned
|
|
257
|
+
params:
|
|
258
|
+
entity: str
|
|
259
|
+
return: str
|
|
260
|
+
Локальные максимумы:
|
|
261
|
+
text: 'Напишите функцию, которая принимает список и возвращает список локальных
|
|
262
|
+
максимумов. Крайние элементы списка максимумами не являются.
|
|
263
|
+
|
|
264
|
+
Локальный максимум - это элемент, который:
|
|
265
|
+
|
|
266
|
+
- больше предыдущего
|
|
267
|
+
|
|
268
|
+
- больше следующего
|
|
269
|
+
|
|
270
|
+
Например:
|
|
271
|
+
|
|
272
|
+
- [1,2,5,3,4,7,8,3,2,0] -> [5, 8]
|
|
273
|
+
|
|
274
|
+
- [3,2,1] -> [] пустой список, не лок. максимумов.'
|
|
275
|
+
code_template: "def solution(lst: list):\n return []"
|
|
276
|
+
code: "def solution(lst: list):\n return []"
|
|
277
|
+
test_cases:
|
|
278
|
+
- lst:
|
|
279
|
+
- 8
|
|
280
|
+
- 7
|
|
281
|
+
- 6
|
|
282
|
+
- 5
|
|
283
|
+
- 4
|
|
284
|
+
expected: []
|
|
285
|
+
- lst:
|
|
286
|
+
- 8
|
|
287
|
+
- 10
|
|
288
|
+
- 6
|
|
289
|
+
- 5
|
|
290
|
+
- 4
|
|
291
|
+
expected:
|
|
292
|
+
- 10
|
|
293
|
+
- lst:
|
|
294
|
+
- 1
|
|
295
|
+
- 4
|
|
296
|
+
- 2
|
|
297
|
+
- 5
|
|
298
|
+
- 10
|
|
299
|
+
- 3
|
|
300
|
+
- 2
|
|
301
|
+
expected:
|
|
302
|
+
- 4
|
|
303
|
+
- 10
|
|
304
|
+
- lst:
|
|
305
|
+
- 1
|
|
306
|
+
- 2
|
|
307
|
+
- 5
|
|
308
|
+
- 3
|
|
309
|
+
- 4
|
|
310
|
+
- 7
|
|
311
|
+
- 8
|
|
312
|
+
- 3
|
|
313
|
+
- 2
|
|
314
|
+
- 0
|
|
315
|
+
expected:
|
|
316
|
+
- 5
|
|
317
|
+
- 8
|
|
318
|
+
is_passed: not_runned
|
|
319
|
+
params:
|
|
320
|
+
lst: list
|
|
321
|
+
return: list
|
|
322
|
+
Сумма положительных:
|
|
323
|
+
text: 'Написать функцию, которая принимает список чисел и вернет сумму только
|
|
324
|
+
положительных элементов.
|
|
325
|
+
|
|
326
|
+
Для пустого списка вернуть 0. Аналогично, вернуть 0 если нет ни одного положительного
|
|
327
|
+
элемента.
|
|
328
|
+
|
|
329
|
+
Например:
|
|
330
|
+
|
|
331
|
+
- solution([]) -> 0
|
|
332
|
+
|
|
333
|
+
- solution([1, 2, -3]) -> 3
|
|
334
|
+
|
|
335
|
+
- solution([3, 4, -2, 7, -10, 12]) -> 26'
|
|
336
|
+
code_template: "def solution(lst: list):\n return 0"
|
|
337
|
+
code: "def solution(lst: list):\n return 0"
|
|
338
|
+
test_cases:
|
|
339
|
+
- lst: []
|
|
340
|
+
expected: 0
|
|
341
|
+
- lst:
|
|
342
|
+
- 14
|
|
343
|
+
expected: 14
|
|
344
|
+
- lst:
|
|
345
|
+
- 2
|
|
346
|
+
- 5
|
|
347
|
+
- 8
|
|
348
|
+
expected: 15
|
|
349
|
+
- lst:
|
|
350
|
+
- 3
|
|
351
|
+
- -2
|
|
352
|
+
- -2
|
|
353
|
+
- -15
|
|
354
|
+
- -10
|
|
355
|
+
- 12
|
|
356
|
+
expected: 15
|
|
357
|
+
- lst:
|
|
358
|
+
- 1
|
|
359
|
+
- 2
|
|
360
|
+
- -3
|
|
361
|
+
expected: 3
|
|
362
|
+
- lst:
|
|
363
|
+
- 3
|
|
364
|
+
- 4
|
|
365
|
+
- -2
|
|
366
|
+
- 7
|
|
367
|
+
- -10
|
|
368
|
+
- 12
|
|
369
|
+
expected: 26
|
|
370
|
+
- lst:
|
|
371
|
+
- -3
|
|
372
|
+
- -4
|
|
373
|
+
- -2
|
|
374
|
+
- -7
|
|
375
|
+
- -10
|
|
376
|
+
- -12
|
|
377
|
+
expected: 0
|
|
378
|
+
is_passed: not_runned
|
|
379
|
+
params:
|
|
380
|
+
lst: list
|
|
381
|
+
return: int
|
|
382
|
+
Простое число:
|
|
383
|
+
text: 'Напишите функцию, которая возращает true, если число является простым.
|
|
384
|
+
|
|
385
|
+
Число является простым, если нацело делится только на 1 и само себя.
|
|
386
|
+
|
|
387
|
+
Например:
|
|
388
|
+
|
|
389
|
+
- 7 - простое, т.к. делится нацело только на себя и 1.
|
|
390
|
+
|
|
391
|
+
- 8, к примеру, простым не является, потому что без остатка делится еще
|
|
392
|
+
и на 2, и 4.
|
|
393
|
+
|
|
394
|
+
Подсказка: пройдетесь по всем числам, меньше заданного и проверьте делимость'
|
|
395
|
+
code_template: "def solution(n: int):\n return True"
|
|
396
|
+
code: "def solution(n: int):\n return True"
|
|
397
|
+
test_cases:
|
|
398
|
+
- n: 1
|
|
399
|
+
expected: true
|
|
400
|
+
- n: 2
|
|
401
|
+
expected: true
|
|
402
|
+
- n: 3
|
|
403
|
+
expected: true
|
|
404
|
+
- n: 4
|
|
405
|
+
expected: false
|
|
406
|
+
- n: 5
|
|
407
|
+
expected: true
|
|
408
|
+
- n: 6
|
|
409
|
+
expected: false
|
|
410
|
+
- n: 8
|
|
411
|
+
expected: false
|
|
412
|
+
- n: 11
|
|
413
|
+
expected: true
|
|
414
|
+
- n: 13
|
|
415
|
+
expected: true
|
|
416
|
+
- n: 14
|
|
417
|
+
expected: false
|
|
418
|
+
is_passed: not_runned
|
|
419
|
+
params:
|
|
420
|
+
n: int
|
|
421
|
+
return: bool
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from platformdirs import user_data_dir
|
|
4
|
+
|
|
5
|
+
from matthew_ide import APP_FOLDER_NAME
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def init_app_working_folder() -> None:
|
|
9
|
+
_create_app_folder()
|
|
10
|
+
write_user_id()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NoUserIdException(Exception):
|
|
14
|
+
def __init__(self, user_id_file_path: str) -> None:
|
|
15
|
+
super().__init__(*user_id_file_path)
|
|
16
|
+
self.user_id_file_path = user_id_file_path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def read_user_id() -> str:
|
|
20
|
+
app_folder = _get_app_folder()
|
|
21
|
+
user_id_file = app_folder / "user_id.txt"
|
|
22
|
+
if not user_id_file.exists():
|
|
23
|
+
raise FileExistsError()
|
|
24
|
+
user_id = user_id_file.read_text()
|
|
25
|
+
if user_id == "":
|
|
26
|
+
raise NoUserIdException(str(user_id_file))
|
|
27
|
+
return user_id
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def write_user_id() -> None:
|
|
31
|
+
app_folder = _get_app_folder()
|
|
32
|
+
user_id_file = app_folder / "user_id.txt"
|
|
33
|
+
user_id = str(uuid.uuid4())
|
|
34
|
+
user_id_file.write_text(user_id)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _get_app_folder() -> Path:
|
|
38
|
+
return Path(user_data_dir()) / APP_FOLDER_NAME
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _create_app_folder() -> None:
|
|
42
|
+
app_folder = _get_app_folder()
|
|
43
|
+
if not app_folder.exists():
|
|
44
|
+
app_folder.mkdir()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
|
|
3
|
+
from textual import log
|
|
4
|
+
from textual.app import App
|
|
5
|
+
|
|
6
|
+
from matthew_ide import EVENT_DESTINATION
|
|
7
|
+
|
|
8
|
+
from .sender.event_sender import BaseEventSender
|
|
9
|
+
from .sender.api_sender import ApiEventSender
|
|
10
|
+
from .sender.no_sender import NoEventSender
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _create_sender(
|
|
14
|
+
sender_type: Literal["local_db", "remote_db", "no_events"]
|
|
15
|
+
) -> BaseEventSender:
|
|
16
|
+
if sender_type == "local_db":
|
|
17
|
+
return ApiEventSender(
|
|
18
|
+
api_url="https://localhost:7150/api/NeonApi/PostEvent")
|
|
19
|
+
if sender_type == "remote_db":
|
|
20
|
+
return ApiEventSender(
|
|
21
|
+
api_url="https://www.xn----7sbbaat6aaehdfdhwgj7f.xn--p1ai/api/NeonApi/PostEvent")
|
|
22
|
+
if sender_type == "no_events":
|
|
23
|
+
return NoEventSender()
|
|
24
|
+
raise ValueError(f"Event sender <{sender_type}> supported")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _wrapper():
|
|
28
|
+
|
|
29
|
+
_sender = _create_sender(EVENT_DESTINATION)
|
|
30
|
+
|
|
31
|
+
def _send_event(
|
|
32
|
+
app: App[Any],
|
|
33
|
+
event_name: str,
|
|
34
|
+
event_location: str,
|
|
35
|
+
event_json: dict[str, str | int | bool] | None = None) -> None:
|
|
36
|
+
|
|
37
|
+
async def _send_async(event_name: str,
|
|
38
|
+
event_location: str) -> None:
|
|
39
|
+
try:
|
|
40
|
+
await _sender.send_event(event_name=event_name,
|
|
41
|
+
event_location=event_location,
|
|
42
|
+
event_json=event_json)
|
|
43
|
+
except Exception as ex: # pylint: disable=broad-exception-caught
|
|
44
|
+
log(f"Ошибка отправки события {event_name}/{event_location}: {str(ex)}")
|
|
45
|
+
|
|
46
|
+
app.run_worker(_send_async(event_name, event_location), thread=True)
|
|
47
|
+
|
|
48
|
+
return _send_event
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
send_event = _wrapper()
|
|
File without changes
|