Skip to content

Commit 7924cbc

Browse files
committed
Initial Commit
0 parents  commit 7924cbc

302 files changed

Lines changed: 113886 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
name: Ask a Question
3+
about: Ask questions related to the book
4+
title: ''
5+
labels: [question]
6+
assignees: rasbt
7+
8+
---
9+
10+
If you have a question that is not a bug, please consider asking it in this GitHub repository's [discussion forum](https://github.com/rasbt/LLMs-from-scratch/discussions).
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Bug Report
2+
description: Report errors related to the book content or code
3+
title: "Description"
4+
labels: [bug]
5+
assignees: rasbt
6+
body:
7+
- type: markdown
8+
attributes:
9+
value: |
10+
Thank you for taking the time to report an issue. Please fill out the details below to help resolve it.
11+
12+
- type: textarea
13+
id: bug_description
14+
attributes:
15+
label: Bug description
16+
description: A description of the issue.
17+
placeholder: |
18+
Please provide a description of what the bug or issue is.
19+
validations:
20+
required: true
21+
22+
- type: dropdown
23+
id: operating_system
24+
attributes:
25+
label: What operating system are you using?
26+
description: If applicable, please select the operating system where you experienced this issue.
27+
options:
28+
- "Unknown"
29+
- "macOS"
30+
- "Linux"
31+
- "Windows"
32+
validations:
33+
required: False
34+
35+
- type: dropdown
36+
id: compute_environment
37+
attributes:
38+
label: Where do you run your code?
39+
description: Please select the computing environment where you ran this code.
40+
options:
41+
- "Local (laptop, desktop)"
42+
- "Lightning AI Studio"
43+
- "Google Colab"
44+
- "Other cloud environment (AWS, Azure, GCP)"
45+
validations:
46+
required: False
47+
48+
- type: textarea
49+
id: environment
50+
attributes:
51+
label: Environment
52+
description: |
53+
Please provide details about your Python environment via the environment collection script or notebook located at
54+
https://github.com/rasbt/LLMs-from-scratch/tree/main/setup/02_installing-python-libraries.
55+
For your convenience, you can download and run the script from your terminal as follows:
56+
57+
```bash
58+
curl --ssl-no-revoke -O https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/setup/02_installing-python-libraries/python_environment_check.py \
59+
-O https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/requirements.txt
60+
61+
python python_environment_check.py
62+
```
63+
64+
The script will print your Python environment information in the following format
65+
```console
66+
[OK] Your Python version is 3.11.4
67+
[OK] torch 2.3.1
68+
[OK] jupyterlab 4.2.2
69+
[OK] tiktoken 0.7.0
70+
[OK] matplotlib 3.9.0
71+
[OK] numpy 1.26.4
72+
[OK] tensorflow 2.16.1
73+
[OK] tqdm 4.66.4
74+
[OK] pandas 2.2.2
75+
[OK] psutil 5.9.8
76+
```
77+
You can simply copy and paste the outputs of this script below.
78+
value: |
79+
```
80+
81+
82+
83+
```
84+
validations:
85+
required: false
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Copyright (c) Sebastian Raschka under Apache License 2.0 (see LICENSE.txt)
2+
# Source for "Build a Reasoning Model (From Scratch)": https://mng.bz/lZ5B
3+
# Code repository: https://github.com/rasbt/reasoning-from-scratch
4+
5+
# Verify that Python source files (and optionally notebooks) use double quotes for strings.
6+
7+
import argparse
8+
import ast
9+
import io
10+
import json
11+
import sys
12+
import tokenize
13+
from pathlib import Path
14+
15+
EXCLUDED_DIRS = {
16+
".git",
17+
".hg",
18+
".mypy_cache",
19+
".pytest_cache",
20+
".ruff_cache",
21+
".svn",
22+
".tox",
23+
".venv",
24+
"__pycache__",
25+
"build",
26+
"dist",
27+
"node_modules",
28+
}
29+
30+
PREFIX_CHARS = {"r", "u", "f", "b"}
31+
SINGLE_QUOTE = "'"
32+
DOUBLE_QUOTE = "\""
33+
TRIPLE_SINGLE = SINGLE_QUOTE * 3
34+
TRIPLE_DOUBLE = DOUBLE_QUOTE * 3
35+
36+
37+
def should_skip(path):
38+
parts = set(path.parts)
39+
return bool(EXCLUDED_DIRS & parts)
40+
41+
42+
def collect_fstring_expr_string_positions(source):
43+
"""
44+
Return set of (lineno, col_offset) for string literals that appear inside
45+
formatted expressions of f-strings. These should be exempt from the double
46+
quote check, since enforcing double quotes there is unnecessarily strict.
47+
"""
48+
try:
49+
tree = ast.parse(source)
50+
except SyntaxError:
51+
return set()
52+
53+
positions = set()
54+
55+
class Collector(ast.NodeVisitor):
56+
def visit_JoinedStr(self, node):
57+
for value in node.values:
58+
if isinstance(value, ast.FormattedValue):
59+
self._collect_from_expr(value.value)
60+
# Continue walking to catch nested f-strings within expressions
61+
self.generic_visit(node)
62+
63+
def _collect_from_expr(self, node):
64+
if isinstance(node, ast.Constant) and isinstance(node.value, str):
65+
positions.add((node.lineno, node.col_offset))
66+
elif isinstance(node, ast.Str): # Python <3.8 compatibility
67+
positions.add((node.lineno, node.col_offset))
68+
else:
69+
for child in ast.iter_child_nodes(node):
70+
self._collect_from_expr(child)
71+
72+
Collector().visit(tree)
73+
return positions
74+
75+
76+
def check_quotes_in_source(source, path):
77+
violations = []
78+
ignored_positions = collect_fstring_expr_string_positions(source)
79+
tokens = tokenize.generate_tokens(io.StringIO(source).readline)
80+
for tok_type, tok_str, start, _, _ in tokens:
81+
if tok_type == tokenize.STRING:
82+
if start in ignored_positions:
83+
continue
84+
lowered = tok_str.lower()
85+
# ignore triple-quoted strings
86+
if lowered.startswith((TRIPLE_DOUBLE, TRIPLE_SINGLE)):
87+
continue
88+
89+
# find the prefix and quote type
90+
# prefix = ""
91+
for c in PREFIX_CHARS:
92+
if lowered.startswith(c):
93+
# prefix = c
94+
lowered = lowered[1:]
95+
break
96+
97+
# report if not using double quotes
98+
if lowered.startswith(SINGLE_QUOTE):
99+
line, col = start
100+
violations.append(f"{path}:{line}:{col}: uses single quotes")
101+
return violations
102+
103+
104+
def check_file(path):
105+
try:
106+
if path.suffix == ".ipynb":
107+
return check_notebook(path)
108+
else:
109+
text = path.read_text(encoding="utf-8")
110+
return check_quotes_in_source(text, path)
111+
except Exception as e:
112+
return [f"{path}: failed to check ({e})"]
113+
114+
115+
def check_notebook(path):
116+
violations = []
117+
with open(path, encoding="utf-8") as f:
118+
nb = json.load(f)
119+
for cell in nb.get("cells", []):
120+
if cell.get("cell_type") == "code":
121+
src = "".join(cell.get("source", []))
122+
violations.extend(check_quotes_in_source(src, path))
123+
return violations
124+
125+
126+
def parse_args():
127+
parser = argparse.ArgumentParser(description="Verify double-quoted string literals.")
128+
parser.add_argument(
129+
"--include-notebooks",
130+
action="store_true",
131+
help="Also scan Jupyter notebooks (.ipynb files) for single-quoted strings.",
132+
)
133+
return parser.parse_args()
134+
135+
136+
def main():
137+
args = parse_args()
138+
project_root = Path(".").resolve()
139+
py_files = sorted(project_root.rglob("*.py"))
140+
notebook_files = sorted(project_root.rglob("*.ipynb")) if args.include_notebooks else []
141+
142+
violations = []
143+
for path in py_files + notebook_files:
144+
if should_skip(path):
145+
continue
146+
violations.extend(check_file(path))
147+
148+
if violations:
149+
print("\n".join(violations))
150+
print(f"\n{len(violations)} violations found.")
151+
return 1
152+
153+
print("All files use double quotes correctly.")
154+
return 0
155+
156+
157+
if __name__ == "__main__":
158+
sys.exit(main())
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Test latest PyTorch-compatible Python version
2+
on:
3+
push:
4+
branches: [ main ]
5+
paths:
6+
- '**/*.py' # Run workflow for changes in Python files
7+
- '**/*.ipynb'
8+
- '**/*.yaml'
9+
- '**/*.yml'
10+
- '**/*.sh'
11+
pull_request:
12+
branches: [ main ]
13+
paths:
14+
- '**/*.py'
15+
- '**/*.ipynb'
16+
- '**/*.yaml'
17+
- '**/*.yml'
18+
- '**/*.sh'
19+
20+
jobs:
21+
test:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- uses: actions/checkout@v6
26+
27+
- name: Set up Python
28+
uses: actions/setup-python@v6
29+
with:
30+
python-version: "3.13"
31+
32+
- name: Install dependencies
33+
run: |
34+
curl -LsSf https://astral.sh/uv/install.sh | sh
35+
uv sync --dev --python=3.13
36+
uv add pytest-ruff nbval
37+
38+
- name: Test Selected Python Scripts
39+
run: |
40+
source .venv/bin/activate
41+
pytest setup/02_installing-python-libraries/tests.py
42+
pytest ch04/01_main-chapter-code/tests.py
43+
pytest ch05/01_main-chapter-code/tests.py
44+
pytest ch06/01_main-chapter-code/tests.py
45+
46+
- name: Validate Selected Jupyter Notebooks
47+
run: |
48+
source .venv/bin/activate
49+
pytest --nbval ch02/01_main-chapter-code/dataloader.ipynb
50+
pytest --nbval ch03/01_main-chapter-code/multihead-attention.ipynb
51+
pytest --nbval ch02/04_bonus_dataloader-intuition/dataloader-intuition.ipynb
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Code tests Linux
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths:
7+
- '**/*.py'
8+
- '**/*.ipynb'
9+
- '**/*.yaml'
10+
- '**/*.yml'
11+
- '**/*.sh'
12+
pull_request:
13+
branches: [ main ]
14+
paths:
15+
- '**/*.py'
16+
- '**/*.ipynb'
17+
- '**/*.yaml'
18+
- '**/*.yml'
19+
- '**/*.sh'
20+
workflow_dispatch:
21+
22+
concurrency:
23+
group: ${{ github.workflow }}-${{ github.ref }}
24+
cancel-in-progress: true
25+
26+
jobs:
27+
uv-tests:
28+
name: Code tests (Linux)
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@v6
32+
33+
- name: Set up Python (uv)
34+
uses: actions/setup-python@v6
35+
with:
36+
python-version: "3.13"
37+
38+
- name: Install uv and dependencies
39+
shell: bash
40+
run: |
41+
curl -LsSf https://astral.sh/uv/install.sh | sh
42+
uv sync --dev # tests for backwards compatibility
43+
uv pip install -r ch05/07_gpt_to_llama/tests/test-requirements-extra.txt
44+
uv add pytest-ruff nbval
45+
46+
- name: Test Selected Python Scripts (uv)
47+
shell: bash
48+
run: |
49+
source .venv/bin/activate
50+
pytest setup/02_installing-python-libraries/tests.py
51+
pytest ch03/02_bonus_efficient-multihead-attention/tests/test_mha_implementations.py
52+
pytest ch04/01_main-chapter-code/tests.py
53+
pytest ch04/03_kv-cache/tests.py
54+
pytest ch05/01_main-chapter-code/tests.py
55+
pytest ch05/07_gpt_to_llama/tests/tests_rope_and_parts.py
56+
pytest ch05/07_gpt_to_llama/tests/test_llama32_nb.py
57+
pytest ch05/11_qwen3/tests/test_qwen3_nb.py
58+
pytest ch05/12_gemma3/tests/test_gemma3_nb.py
59+
pytest ch05/12_gemma3/tests/test_gemma3_kv_nb.py
60+
pytest ch05/13_olmo3/tests/test_olmo3_nb.py
61+
pytest ch05/13_olmo3/tests/test_olmo3_kvcache_nb.py
62+
pytest ch06/01_main-chapter-code/tests.py
63+
64+
- name: Validate Selected Jupyter Notebooks (uv)
65+
shell: bash
66+
run: |
67+
source .venv/bin/activate
68+
pytest --nbval ch02/01_main-chapter-code/dataloader.ipynb
69+
pytest --nbval ch03/01_main-chapter-code/multihead-attention.ipynb
70+
pytest --nbval ch02/04_bonus_dataloader-intuition/dataloader-intuition.ipynb
71+
72+
- name: Test Selected Bonus Materials
73+
shell: bash
74+
run: |
75+
source .venv/bin/activate
76+
pytest ch02/05_bpe-from-scratch/tests.py
77+
78+
- name: Test Selected Bonus Materials
79+
shell: bash
80+
run: |
81+
source .venv/bin/activate
82+
pytest pkg/llms_from_scratch/tests/

0 commit comments

Comments
 (0)