Skip to content

Commit ff5b4e2

Browse files
authored
Merge pull request #111 from flypythoncom/fix/review-defects-20261022
chore: align engineering configuration and CI entry points
2 parents 639126d + 39c02aa commit ff5b4e2

21 files changed

Lines changed: 241 additions & 9 deletions

File tree

‎.gitattributes‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Stable LF checkouts keep generated JSON, source checksums and solution hashes
2+
# identical across contributor platforms, independent of core.autocrlf.
3+
* text=auto eol=lf

‎.github/workflows/validate.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Validate
22

33
on:
4+
workflow_dispatch:
45
pull_request:
56
push:
67
branches:
@@ -11,7 +12,8 @@ permissions:
1112

1213
concurrency:
1314
group: validate-${{ github.workflow }}-${{ github.ref }}
14-
cancel-in-progress: true
15+
# Preserve a complete default-branch validation; superseded PR runs can stop.
16+
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
1517

1618
jobs:
1719
# Lowest and latest supported CPython; the universal lock already resolves

‎AGENTS.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ reviewed catalog data, and stable public JSON contracts.
7676
- After merge, verify the immutable raw `catalog.json`. Verify flypython.com only
7777
after a separate, deliberate consumer-version update.
7878

79+
## Engineering entry points
80+
81+
- `make help` lists the existing validation and generation tools.
82+
- `make setup` installs the locked dev environment; use
83+
`make check PYTHON=.venv/bin/python` afterwards.
84+
- `make generated-check` is read-only; `make generate` rewrites derived content
85+
in dependency order. Neither publishes or changes the website content pin.
86+
- Keep agent rules here; `CLAUDE.md` imports this file rather than copying it.
87+
- Engineering configuration rationale is in `docs/ENGINEERING_CONFIG.md`.
88+
7989
## Review priorities
8090

8191
1. Content accuracy and source quality.

‎CLAUDE.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

‎CONTRIBUTING.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ and path folders that ship their own `requirements.txt` must pin exactly the
8484
versions in `requirements-dev.lock.txt` (`tests/test_dependency_pins.py`), so
8585
CI tests the stack learners install.
8686

87+
With `uv` installed, `make setup` is an alternative to the manual setup above:
88+
it uses `.python-version` and synchronizes the exact dev lock into `.venv`.
89+
Then use `make check PYTHON=.venv/bin/python`; Make otherwise defaults to
90+
`python3`. The Make aliases assume a POSIX shell (Windows contributors can use
91+
the direct Python commands below or WSL). Run from this repository or use
92+
`make -C path/to/python`, not `make -f path/to/Makefile` from another directory.
93+
94+
`make generated-check` checks derived content without rewriting it, including
95+
course solution hashes. `make generate` regenerates exports, README indexes,
96+
the content manifest and solution hashes in order; `make all` then runs checks.
97+
Both preserve ordering even when invoked with `make -j`.
98+
8799
After changing catalog sources, regenerate the public export:
88100

89101
```bash
@@ -101,6 +113,7 @@ python tools/validate_catalog.py
101113
python tools/export_catalog.py --check --target both
102114
python tools/render_readmes.py --check
103115
python tools/build_content_manifest.py --check
116+
python tools/build_solution_hashes.py --check
104117
python tools/verify_examples.py
105118
python tools/verify_courses.py
106119
python tools/verify_paths.py

‎Makefile‎

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
.PHONY: help check export render manifest test verify courses paths lint lock lock-check all
1+
# Recipes use repository-relative paths. Like Magpie's Makefile, fail closed
2+
# when invoked with `make -f path/to/Makefile` from an unrelated directory.
3+
ifeq ($(and $(wildcard pyproject.toml),$(wildcard tools/validate_catalog.py),$(wildcard catalog/catalog.yml)),)
4+
$(error run make in the Python repository (make -C path/to/python))
5+
endif
6+
7+
.DEFAULT_GOAL := help
8+
.PHONY: help setup check generated-check generate export render manifest solutions test verify courses paths lint lock lock-check all
29

310
PYTHON ?= python3
411
UV ?= uv
@@ -15,10 +22,14 @@ endef
1522

1623
help:
1724
@echo "FlyPython Development Workflow:"
18-
@echo " make check - Run the same checks as CI: lint, tests, catalog, radar, export, readme, manifest, example, course, and path checks"
25+
@echo " make setup - Create .venv using .python-version and install locked dev dependencies (requires uv)"
26+
@echo " make check - Run CI checks (use PYTHON=.venv/bin/python after setup)"
27+
@echo " make generated-check - Check catalog, exports, READMEs, manifest, and solution hashes without rewriting"
28+
@echo " make generate - Regenerate all derived content in dependency order"
1929
@echo " make export - Regenerate catalog.json and radar.json"
2030
@echo " make render - Regenerate root and catalog README indexes plus the Radar table"
2131
@echo " make manifest - Regenerate content-manifest.json"
32+
@echo " make solutions - Regenerate course-solutions.json"
2233
@echo " make lint - Run ruff"
2334
@echo " make test - Run pytest test suite"
2435
@echo " make verify - Verify all runnable examples"
@@ -28,14 +39,29 @@ help:
2839
@echo " make lock-check - Fail if the lock files no longer match pyproject.toml"
2940
@echo " make all - Regenerate all exports and run all checks and tests"
3041

31-
check: lint test
42+
setup:
43+
$(UV) venv --python "$$(cat .python-version)" .venv
44+
$(UV) pip sync --python .venv/bin/python requirements-dev.lock.txt
45+
46+
check: lint test generated-check
47+
$(PYTHON) tools/verify_examples.py
48+
$(PYTHON) tools/verify_courses.py
49+
$(PYTHON) tools/verify_paths.py
50+
51+
generated-check:
3252
$(PYTHON) tools/validate_catalog.py
3353
$(PYTHON) tools/export_catalog.py --check --target both
3454
$(PYTHON) tools/render_readmes.py --check
3555
$(PYTHON) tools/build_content_manifest.py --check
36-
$(PYTHON) tools/verify_examples.py
37-
$(PYTHON) tools/verify_courses.py
38-
$(PYTHON) tools/verify_paths.py
56+
$(PYTHON) tools/build_solution_hashes.py --check
57+
58+
# Keep writers sequential even under make -j: README/manifest checks must not
59+
# race against a producer. No automatic commit, content-pin update or deploy.
60+
generate:
61+
$(MAKE) export
62+
$(MAKE) render
63+
$(MAKE) manifest
64+
$(MAKE) solutions
3965

4066
export:
4167
$(PYTHON) tools/export_catalog.py --target both
@@ -46,6 +72,9 @@ render:
4672
manifest:
4773
$(PYTHON) tools/build_content_manifest.py
4874

75+
solutions:
76+
$(PYTHON) tools/build_solution_hashes.py
77+
4978
lint:
5079
$(PYTHON) -m ruff check .
5180

@@ -72,4 +101,5 @@ lock-check:
72101
@git diff --exit-code requirements.lock.txt requirements-dev.lock.txt || \
73102
{ echo "lock files drifted from pyproject.toml — commit the regenerated files"; exit 1; }
74103

75-
all: export render manifest check
104+
all: generate
105+
$(MAKE) check

‎course-solutions.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
{
6565
"slug": "mcp-server-in-python",
6666
"course_id": "course-mcp-tools",
67-
"solution_sha256": "e9a0c348e12bd1f04d83783689f299e3ece8884f3f8a5be2f8a40655e211b790"
67+
"solution_sha256": "3f58792fafaf0025f8766ca84ac8cae660e73868193fe55b61bb97548ac2aca7"
6868
},
6969
{
7070
"slug": "secure-ai-generated-code",

‎courses/mcp-server-in-python/TASK.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Change only `starter/mcp_server.py`.
1515
- Supported methods:
1616
- `"tools/list"`: returns `{"result": {"tools": [{"name": ..., "description": ..., "inputSchema": ...}, ...]}}`.
1717
- `"tools/call"`: accepts `params: {"name": ..., "arguments": ..., "inputResponses": {...}?}` and calls the handler as `handler(arguments, inputResponses)`.
18+
- If the tool name is missing or is not a string (including lists, objects, booleans, numbers, and null), return JSON-RPC error `-32602` (Invalid params), preserving the request ID.
1819
- If tool not registered: returns `{"result": {"isError": True, "content": [{"type": "text", "text": "Tool not found"}]}}`.
1920
- If required argument missing: returns `{"result": {"isError": True, "content": [{"type": "text", "text": "Missing required argument: <arg>"}]}}`.
2021
- If the handler raises `InputRequired(requests)`: returns `{"result": {"resultType": "input_required", "requests": <requests>, "content": [{"type": "text", "text": "Additional client input is required before this tool can finish."}]}}`. The client retries the same call with answers in `params.inputResponses`.

‎courses/mcp-server-in-python/TASK_cn.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- 支持的核心方法:
1616
- `"tools/list"`:返回 `{"result": {"tools": [{"name": ..., "description": ..., "inputSchema": ...}, ...]}}`。
1717
- `"tools/call"`:接收 `params: {"name": ..., "arguments": ..., "inputResponses": {...}?}`,并以 `handler(arguments, inputResponses)` 调用工具。
18+
- 工具名缺失或不是字符串(包括列表、对象、布尔值、数字和 null)时,返回 JSON-RPC 错误码 `-32602`(Invalid params),并保留请求 ID。
1819
- 工具未找到:返回 `{"result": {"isError": True, "content": [{"type": "text", "text": "Tool not found"}]}}`。
1920
- 缺少 schema 中声明的必填参数:返回 `{"result": {"isError": True, "content": [{"type": "text", "text": "Missing required argument: <arg>"}]}}`。
2021
- 工具抛出 `InputRequired(requests)`:返回 `{"result": {"resultType": "input_required", "requests": <requests>, "content": [{"type": "text", "text": "Additional client input is required before this tool can finish."}]}}`。客户端携带 `params.inputResponses` 重试同一请求。

‎courses/mcp-server-in-python/solution/mcp_server.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ def handle_request(self, request: Any) -> dict[str, Any]:
108108
}
109109

110110
tool_name = params["name"]
111+
if not isinstance(tool_name, str):
112+
return {
113+
"jsonrpc": "2.0",
114+
"id": req_id,
115+
"error": {
116+
"code": -32602,
117+
"message": "Invalid params: tool name must be a string",
118+
},
119+
}
111120
if tool_name not in self.tools:
112121
return {
113122
"jsonrpc": "2.0",

0 commit comments

Comments
 (0)