darkkeks / kks Goto Github PK
View Code? Open in Web Editor NEWKoKoS - утилита для удобного решения задач курса АКОС.
KoKoS - утилита для удобного решения задач курса АКОС.
При синхронизации с фильтром (kks sync sm01
) в файл .kks-contests/.index
(список существующих контестов) записываются только синхронизированные в последний раз контестов. Из-за этого команды kks (un)hide
могут не работать
Traceback (most recent call last):
File "/home/alex/.local/bin/kks", line 8, in <module>
sys.exit(cli())
File "/home/alex/.local/lib/python3.8/site-packages/click/core.py", line 829, in call
return self.main(*args, **kwargs)
File "/home/alex/.local/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/alex/.local/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/alex/.local/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/alex/.local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/alex/.local/lib/python3.8/site-packages/kks/cmd/submit.py", line 21, in submit
rootdir = find_problem_rootdir()
File "/home/alex/.local/lib/python3.8/site-packages/kks/cmd/submit.py", line 54, in find_problem_rootdir
if cwd.is_relative_to(hidden):
AttributeError: 'PosixPath' object has no attribute 'is_relative_to'
is_relative_to
была добавлена в версии питона 3.9 вродеПарсинг страниц, получаемых от ejudge, работает неоптимально.
Например, в функции parse_rows
в ejudge_standings
в каждой строке таблицы теги ищутся по 3 раза
В vvd170501/kks@0fffb16 реализован альтернативный вариант - все теги <td>
находятся за один вызов find
, а потом, в зависимости от класса, содержимое тегов сохраняется в нужные переменные.
Время работы функции parse_rows
(на момент запуска команды в таблице 32 строки, 73 столбца):
Возможно, парсинг в классе Для Statement
можно оптимизировать похожим образомStatement
очевидных оптимизаций нет, и при синхронизации в любом случае запросы к ejudge занимают намного больше времени, чем парсинг страниц
В версии 1.7.0 (0958b08) класс kks.util.testing.RunOptions
используется как при запуске, так и при компиляции решения (опция asan
). Этот же класс используется при запуске генератора тестов (см kks.cmd.gen
), хотя в этом случае в нём используется только опция ignore_exit_code
(и неявно используется asan
в случае, если генератор написан на C++)
Стоит создать отдельный класс для опций компиляции (туда же можно добавить аргумент verbose
, который передаётся из kks run
и kks test
). Также, возможно, есть смысл создать отдельный класс для опций запуска генератора (как вариант - использовать наследование от какого-нибуть базового класса)
(см. #45 (comment))
При запуске синхронизации выводится предупреждение для каждой ранее синхронизированной задачи. Учитывая то, что к концу года задач будет намного больше, стоит как-то изменить вывод (см. #25 (comment))
Также для скрытых контестов выводится путь до папки контеста относительно корневой директории (например, .kks-contests/sm01/1
), что тоже значительно увеличивает длину вывода (см. #25 (comment))
В некоторых задачах (по крайней мере, sm10-1), не требуется перевод строки в конце вывода.
kks sync
всегда добавляет перевод строки к примерам из условия (на этой задаче корректное решение не пройдёт тестирование через kks test
).
Есть ли смысл что-то с этим делать?
После kks sync
в контесте ht01 создались файлы с расширением .c, а надо — с .s.
Компилятор там сейчас такой:
gas-armv7l - GNU AS 10.2.0 (armv7l)
Было бы хорошо добавить синхронизацию условий вместе с семплами.
Например, это позволит полностью взаимодействовать с ejudge чеез терминал (наверное, единственное, что нельзя будет сделать без использования браузера — отправка/получение сообщений).
Для синхронизации не потребуется дополнительных запросов к ejudge, т.к. для семпла уже запрашивается полная страница с задачей.
Возможно, стоило бы добавить в команду "kks sync" скачивание исходного кода отправленных ранее решений (например, может пригодиться для использования кода из ДЗ на КР).
Альтернативный вариант - добавить для этого отдельную команду.
Предлагаю команду deadlines, которая выводит все актуальные контесты в таком формате:
Номер контест, дата, сколько баллов осталось.
Типа
sm01 02.03.1998 -1000
Опция --ignore-exit-code
в команде kks gen
используется только для объекта класса TestSource
, в котором она ни на что не влияет. Если флаг добавлен к этой команде по ошибке, а не с расчетом на добавление функционала в будущем, то его стоит удалить.
В текущей версии (1.12.7
) для синхронизации условий используется парсинг страницы.
В #66 / #71 при синхронизации через ssh используются ответы от API, полученные с помощью ejudge-fuse.
Можно использовать API вместо парсинга страницы для обычной синхронизации условий.
Плюсы:
API.problem_status
даже при недоступном условии (хотя вряд ли есть смысл её получать без условия)Минусы:
API.problem_status
(сейчас она парсится из того же кода страницы, откуда берётся условие).При запуске kks gen
c указанием аргументов (например kks gen 1
), происходит вылет с ошибкой
File "/home/user/.local/lib/python3.9/site-packages/kks/util/testing.py", line 26, in generate_input
args = [test] + (additional_args or [])
TypeError: can only concatenate list (not "tuple") to list
python 3.9.1
Сейчас (версия kks 1.9.0) команда kks run
всегда завершается с кодом 0.
Возможно, правильнее будет завершать работу команды с тем же кодом, который возвращает скомпилированное и запущенное решение.
Тогда будет иметь смысл (например) такой вариант запуска: kks run || echo RE
Запрос для очень актуальной фичи, учитывая классный (🤡) формат контрольных
Можно определять расширение для шаблонного файла решения, который создаётся при синхронизации (файл вида sm12-3.c
), по полному названию задачи (названия следуют шаблону "[pref]/..."). Судя по задачам прошлых лет, существующие префиксы - "c", "asm", "unix" и пустая строка.
Очевидные расширения: "c" -> "c", "asm"->"S"
Для префикса "unix" и любых других, если они появятся, можно пока оставить расширение "c" по умолчанию
Во время проведения КР kks top -m
выдаёт некорректные результаты.
На страницах задач не указывается полный балл, поэтому для его получения используется API. Во время проведения КР и тестирования задач его значение равно 1, поэтому в качестве максимального балла используется kks.cmd.top.MIN_SCORE
, равное 20
На скриншоте - вывод команды во время проведения КР06 (опция max_kr
включена)
В интерфейсе ejudge после дедлайна полностью скрывается описание задачи (остаётся только дата начала и дедлайн). Из-за этого, если кеш для Добавлено в #109kks top --max
был очищен, максимальный балл для таких задач становится равным 0. Поэтому для отклонённых задач пересчёт баллов перестаёт работать.
API позволяет получить максимальные баллы даже после дедлайнов
# выставить для всех задач правильное значение макс. балла
from kks.util.ejudge import EjudgeSession
from kks.util.storage import Cache
s = EjudgeSession()
a = s.api()
problem_ids = [p['id'] for p in s.with_auth(a.contest_status)['problems']]
problems = [a.problem_status(pid)['problem'] for pid in problem_ids]
full_scores = {p['short_name']: p['full_score'] for p in problems}
with Cache('problem_info', True, 2).load() as cache:
cache.set('full', full_scores)
Возможная проблема - для задач из КР во время проведения значение full_score равно 1 (может быть другим?), непонятно, когда появляется настоящее значение - сразу после завершения КР или только после начала тестирования решений. Поэтому, возможно, придётся добавлять дополнительную логику для таких задач
Такая разметка:
<ol>
<li>some text
<pre>first_line
second_line
third_line</pre>
</li>
</ol>
Конвертируется в
1. some text
first_line
second_line
third_line
(похожая проблема возникает при конвертировании условия ku02-4).
Начиная со второй строки, у текста из <pre>
не хватает отступов. Из-за этого эти строки перестают распознаваться как код.
Так происходит, потому что отступ для первой строки используется дважды (1, 2).
Пока непонятно, как это можно исправить без копирования большого количества кода (HTML2Text.o
)
Когда использую kks deadlines, непонятно, есть ли еще не сданные задачи в каком-то контесте.
Не знаю, как это сделать норм, то можно, например, поставить звездочку рядом с тем контестом, в который еще можно что-то заслать.
cc @vvd170501
Сейчас при выполнении kks test
выводится примерно следующее:
Compiling... Successfully compiled binary a.out
All tests passed!
Хочется видеть еще и количество тестов, на которых запускалось решение.
It should be easy: https://click.palletsprojects.com/en/8.1.x/shell-completion/
См. #100 (comment), #100 (comment)
По идее, стоит вынести загрузку дедлайнов из kks.cmd.deadlines
в общий модуль (kks.ejudge
?)
Условие фильтра должно быть примерно таким:
not first_problem.past_deadline() and problem.status in [Status.NOT_SUBMITTED, Status.PARTIAL, Status.REJECTED]
Можно использовать FancyTable
для вывода таблицы (см. #93, kks.cmd.deadlines
)
Идея ещё с прошлого года, но до её реализации я так и не дошёл.
Возможно, заинтересует кого-нибудь из слушателей АКОСа этого года.
Во второй половине курса было много задач, в которых использовались аргументы командной строки и/или предполагалась работа с файловой системой.
kks test
умеет генерировать только входные данные для программы (в теории, с флагом -v
генератор может изменять ФС, но это изначально не предполагалось).
Есть предложение расширить функционал тестирования, чтобы можно было:
В такой реализации gen.py
может выглядеть примерно так:
import os
import sys
import random
imoort typing as t
"""
Sample problem:
1) The program receives a file name `f` in argv[1].
2) An IP is passed via `HOST` environment variable.
3) Input contains a number `n`.
The program must:
1) Read 32-bit integers from `f` (in text mode).
2) Myltiply each by `n`.
3) Send the multiplied integers to `HOST:9999` in binary form (little-endian).
4) Write to stdout the number of processed integers.
"""
def _filename(test: int) -> str:
random.seed(test)
return random.choice(['./a.txt', './b.txt'])
def _multiplier(test: int) -> int:
random.seed(test)
return random.randint(1, 100)
def _data(test: int) -> t.List[int]:
random.seed(test)
return [randint(1, 1000) for i in range(10)]
def gen_input(test: int) -> None:
"""Generates test input.
Test input should be written to stdout.
It will be passed to stdin of your program.
"""
random.seed(test)
print(_multiplier(test))
def args(test: int) -> t.List[str]:
"""Generates command-line arguments for the tested program.
If this function returns ['a', 'b'],
your program will be launched like this: `./a.out a b`.
"""
return [_filename(test)]
def env(test):
"""Generates test environment variables."""
random.seed(test)
env = os.environ.copy()
env['HOST'] = f'127.0.0.{random.randint(1, 254)}'
return env
def external(test):
"""Sets up and cleans external conditions for tests.
Possible examples:
- changing the FS (creating/modifying files),
- changing the working directory
- setting limits (setrlimit, cgroups?)
- rtc.
"""
# ========== Setup ==========
filename = _filename(test)
data = _data(test)
with open(filename, 'w') as f:
f.write(' '.join(data) + '\n')
# ========== Testing ==========
yield
# program is being tested
# checks are performed
# ========== Cleanup ==========
os.unlink(filename)
def check(test):
"""Checks external changes.
If results are incorrect, should raise an error.
Output from the program and solve.py will be compared separately.
"""
# Assuming a server is listening at `HOST:9999`
# and is writing received integers to `/tmp/server_log` in text form.
with open('/tmp/server_log', 'r') as f:
# NOTE Not the most efficient way
last_line = f.readlines()[-1]
data = _data(test)
modified_data = [int(x) for x in last_line.split()]
multiplier = _multiplier(test)
assert modified_data == [x * multiplier for x in data]
# Backwards compatibility
if __name__ == '__main__':
t = int(sys.argv[1])
gen_input(t)
При тестировании часто можно налететь на вот такую ситуацию: в правильном выводе в конце строки должен стоять '\n', но мы по ошибке решили вывести ' '. При этом понять, а что именно, собственно, не так, удаётся не сразу.
Предложение: возможно в таких случаях (ну или всегда) стоит как-то explicitly показывать, что от нас требуется перевод строки, а мы вместо него пихаем пробел?
Импорты requests и bs4 в сумме занимают около 100мс и выполняются даже при запуске локальных команд (например kks run
)
Тестировалось на vvd170501/kks@77f5201
$time kks run --help
import requests 0.051137447357177734
import requests 2.384185791015625e-07
import bs 0.05008339881896973
import h2t 0.002858400344848633
import requests 7.152557373046875e-07
import bs 2.384185791015625e-06
Usage: kks run [OPTIONS] [RUN_ARGS]...
...
real 0m0,192s
user 0m0,164s
sys 0m0,028s
Originally posted by @vvd170501 in #45 (comment)
Можно сделать эти импорты (и/или импорты модулей kks.ejudge
и kks.ejudge_submit
) более локальными (как было сделано с pkg_resources
в 992caf3). Это должно ускорить запуск локальных команд
Failed to send standings to kks api
Failed to receive global standings: HTTPSConnectionPool(host='kks.darkkeks.me', port=443): Max retries exceeded with url: /api/get?year=2021&contest_id=203&login=bpmi203-129 (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)')))
Standings are not available now :(
Хочецца иметь main для отладки и main для контеста, а их не завезли...
При попытке компиляции многопоточного решения (команды build
/ run
/ test
) с использованием опции --no-asan
линковщик выдаёт ошибку (т.к. не производится линковка с libpthread
).
Варианты решения проблемы:
-pthread
в дефолтный таргет. По идее, это не должно влиять на скорость компиляции, если многопоточность не используется./pthread/
(/thread/
).Новые контесты отображаются только у тех групп, которые отправляли на сервер статистику после добавления контеста.
Из-за этого некорректно работает подсчёт максимальных баллов (возможно получить разницу в 500 баллов, которой на самом деле нет).
(например, 306 и 308 строки - без опции --max
у обоих пользователей 0 баллов)
Решение - добавлять новые контесты (с пустыми статусами задач) для всех групп.
Это можно реализовать как на стороне сервера, так и на стороне клиента.
Готов сделать пул-реквест, если вы не против такого изменения.
План такой:
config_directory
в kks/util/common.py
(если существует ~/.kks
, то вернуть ее, иначе вернуть ~/.config/kks`)README.md
, kks/cmd/lint.py
kks/cmd/top.py
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.