README: доставка на виртуалку, check/запуск/launchd, журнал и prune, поведение с командами, известные ограничения (prune при работе агента, Ctrl-C во время паузы, https без CA, спринты закрытых спринтов, refresh, сравнение описания, 429/503 без потолка). CLAUDE.md и ARCHITECTURE.md заполнены по src/agent.py. tests/test_py39.py: разбор с feature_version=(3, 9) и разрешённый список импортов (только stdlib). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Typ5sXWNMFirr2va2uL8o
27 lines
927 B
Python
27 lines
927 B
Python
import ast
|
|
import os
|
|
import unittest
|
|
|
|
from _common import SRC
|
|
|
|
|
|
class Py39Test(unittest.TestCase):
|
|
def test_agent_parses_as_python_39(self):
|
|
with open(os.path.join(SRC, "agent.py"), encoding="utf-8") as f:
|
|
ast.parse(f.read(), feature_version=(3, 9))
|
|
|
|
def test_no_third_party_imports(self):
|
|
with open(os.path.join(SRC, "agent.py"), encoding="utf-8") as f:
|
|
tree = ast.parse(f.read())
|
|
allowed = {"argparse", "base64", "json", "os", "signal", "ssl", "sys", "time", "urllib", "datetime", "typing"}
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Import):
|
|
for a in node.names:
|
|
self.assertIn(a.name.split(".")[0], allowed, a.name)
|
|
elif isinstance(node, ast.ImportFrom):
|
|
self.assertIn((node.module or "").split(".")[0], allowed, node.module)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|