leet2local 0.1.0__tar.gz
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.
- leet2local-0.1.0/.gitignore +29 -0
- leet2local-0.1.0/CHANGELOG.md +23 -0
- leet2local-0.1.0/LICENSE +21 -0
- leet2local-0.1.0/PKG-INFO +318 -0
- leet2local-0.1.0/README.md +279 -0
- leet2local-0.1.0/leet2local/__init__.py +1 -0
- leet2local-0.1.0/leet2local/auth.py +197 -0
- leet2local-0.1.0/leet2local/cli.py +365 -0
- leet2local-0.1.0/leet2local/config.py +119 -0
- leet2local-0.1.0/leet2local/data/.gitkeep +0 -0
- leet2local-0.1.0/leet2local/data/slug_map.json +3964 -0
- leet2local-0.1.0/leet2local/fetcher.py +318 -0
- leet2local-0.1.0/leet2local/html_parser.py +50 -0
- leet2local-0.1.0/leet2local/models.py +71 -0
- leet2local-0.1.0/leet2local/queries.py +39 -0
- leet2local-0.1.0/leet2local/rate_limiter.py +29 -0
- leet2local-0.1.0/leet2local/runner.py +71 -0
- leet2local-0.1.0/leet2local/runners/__init__.py +0 -0
- leet2local-0.1.0/leet2local/runners/base.py +106 -0
- leet2local-0.1.0/leet2local/runners/cpp_runner.py +122 -0
- leet2local-0.1.0/leet2local/runners/java_runner.py +129 -0
- leet2local-0.1.0/leet2local/runners/javascript_runner.py +66 -0
- leet2local-0.1.0/leet2local/runners/python_runner.py +104 -0
- leet2local-0.1.0/leet2local/submitter.py +117 -0
- leet2local-0.1.0/leet2local/templates/__init__.py +0 -0
- leet2local-0.1.0/leet2local/templates/test_runner.cpp.j2 +28 -0
- leet2local-0.1.0/leet2local/templates/test_runner.java.j2 +30 -0
- leet2local-0.1.0/leet2local/templates/test_runner.js.j2 +19 -0
- leet2local-0.1.0/leet2local/templates/test_runner.py.j2 +84 -0
- leet2local-0.1.0/pyproject.toml +91 -0
- leet2local-0.1.0/templates/test_runner.cpp.j2 +28 -0
- leet2local-0.1.0/templates/test_runner.java.j2 +30 -0
- leet2local-0.1.0/templates/test_runner.js.j2 +19 -0
- leet2local-0.1.0/templates/test_runner.py.j2 +84 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated problem directories
|
|
2
|
+
leetcode/
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.pyo
|
|
8
|
+
*.pyd
|
|
9
|
+
.Python
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Config (may contain paths; credentials are in keyring, not here)
|
|
18
|
+
.leet2local.toml
|
|
19
|
+
|
|
20
|
+
# Temp harness files
|
|
21
|
+
/tmp/
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.vscode/settings.json
|
|
25
|
+
.idea/
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2024-06-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `lc fetch <number>` — fetch any LeetCode problem by number; creates a local directory
|
|
12
|
+
with `question.md`, `solution.<ext>`, `test_cases.json`, and `.meta.json`
|
|
13
|
+
- `lc run <number>` — run solution locally against sample test cases using a Jinja2
|
|
14
|
+
test harness subprocess; supports Python, JavaScript, C++, and Java
|
|
15
|
+
- `lc submit <number>` — submit solution to LeetCode and poll for full results including
|
|
16
|
+
runtime percentile, memory percentile, and hidden test count
|
|
17
|
+
- `lc login` — store LeetCode session credentials securely in the OS native keychain
|
|
18
|
+
(Windows Credential Manager / macOS Keychain / libsecret on Linux)
|
|
19
|
+
- `lc config` — view and update TOML configuration; generate `.vscode/tasks.json`
|
|
20
|
+
- Bundled slug fallback map (3963 entries) for offline problem-number-to-slug resolution
|
|
21
|
+
- Multi-language support: Python 3, JavaScript (Node.js), C++ (g++), Java (JDK)
|
|
22
|
+
- Exponential backoff retry on LeetCode rate-limit responses (HTTP 429)
|
|
23
|
+
- Rate limiter with configurable max retries via `.leet2local.toml`
|
leet2local-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dhinesh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: leet2local
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Solve LeetCode problems in your local IDE
|
|
5
|
+
Project-URL: Homepage, https://github.com/dhineshtheprogrammer/leet2local
|
|
6
|
+
Project-URL: Repository, https://github.com/dhineshtheprogrammer/leet2local.git
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/dhineshtheprogrammer/leet2local/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/dhineshtheprogrammer/leet2local/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Dhinesh <dhineshpro33@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,coding-challenges,competitive-programming,interview-prep,leetcode
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
26
|
+
Requires-Dist: httpx>=0.28
|
|
27
|
+
Requires-Dist: jinja2>=3.1
|
|
28
|
+
Requires-Dist: keyring>=25.0
|
|
29
|
+
Requires-Dist: markdownify>=0.13
|
|
30
|
+
Requires-Dist: pydantic>=2.7
|
|
31
|
+
Requires-Dist: tenacity>=8.3
|
|
32
|
+
Requires-Dist: tomli-w>=1.0
|
|
33
|
+
Requires-Dist: typer[all]>=0.12
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.2; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# Leet2Local
|
|
41
|
+
|
|
42
|
+
[](https://pypi.org/project/leet2local/)
|
|
43
|
+
[](https://pypi.org/project/leet2local/)
|
|
44
|
+
[](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
|
|
47
|
+
A CLI tool that brings LeetCode problems into your local IDE. Fetch problem descriptions, solve in your editor, run tests locally, and submit directly to LeetCode — all from the terminal.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
lc fetch 1 --lang python
|
|
51
|
+
lc run 1
|
|
52
|
+
lc submit 1
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- **Fetch any problem** by number — creates a local directory with the description, code stub, and sample test cases
|
|
60
|
+
- **Run locally** — executes your solution against sample test cases without touching LeetCode servers
|
|
61
|
+
- **Submit remotely** — sends your code to LeetCode and polls for full results including hidden test cases, runtime, and memory percentile
|
|
62
|
+
- **Multi-language** — Python, JavaScript, C++, and Java
|
|
63
|
+
- **VS Code integration** — generates `tasks.json` for keyboard-shortcut access to all commands
|
|
64
|
+
- **Secure auth** — session cookies stored in OS native keychain (Windows Credential Manager / macOS Keychain)
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
**Requirements:** Python 3.11+
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install leet2local
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Or install from source:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git clone https://github.com/dhineshtheprogrammer/leet2local.git
|
|
80
|
+
cd Leet2Local
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For development (includes pytest and ruff):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install -e ".[dev]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Quick Start
|
|
93
|
+
|
|
94
|
+
### 1. Log in
|
|
95
|
+
|
|
96
|
+
Get your session cookies from your browser after logging in to leetcode.com:
|
|
97
|
+
|
|
98
|
+
1. Open DevTools → Application → Cookies → `leetcode.com`
|
|
99
|
+
2. Copy `LEETCODE_SESSION` and `csrftoken`
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
lc login
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. Fetch a problem
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
lc fetch 1 # Two Sum, defaults to Python
|
|
109
|
+
lc fetch 42 --lang cpp # Trapping Rain Water in C++
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This creates:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
./leetcode/1-two-sum/
|
|
116
|
+
├── question.md # Problem description in Markdown
|
|
117
|
+
├── solution.py # Code stub from LeetCode
|
|
118
|
+
└── test_cases.json # Sample inputs and expected outputs
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Write your solution
|
|
122
|
+
|
|
123
|
+
Open `solution.py` in your editor and implement the function.
|
|
124
|
+
|
|
125
|
+
### 4. Run locally
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
lc run 1
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
┌─ Test Results ──────────────────────────────────┐
|
|
133
|
+
│ # │ Status │ Details │
|
|
134
|
+
│ 0 │ PASS │ │
|
|
135
|
+
│ 1 │ PASS │ │
|
|
136
|
+
│ 2 │ FAIL │ got: [] expected: [0, 1] │
|
|
137
|
+
└────────────────────────────────────────────────-┘
|
|
138
|
+
✗ 1/3 test(s) failed
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. Submit to LeetCode
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
lc submit 1
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
┌─ Accepted ──────────────────────────────────────┐
|
|
149
|
+
│ Runtime: 52 ms (beats 87.3%) │
|
|
150
|
+
│ Memory: 16.4 MB (beats 62.1%) │
|
|
151
|
+
│ Tests: 54/54 │
|
|
152
|
+
└─────────────────────────────────────────────────┘
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Commands
|
|
158
|
+
|
|
159
|
+
| Command | Description |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `lc login` | Store LeetCode session cookies securely |
|
|
162
|
+
| `lc fetch <number> [--lang]` | Fetch problem and create local files |
|
|
163
|
+
| `lc run <number>` | Run solution against sample test cases |
|
|
164
|
+
| `lc submit <number>` | Submit to LeetCode and get full results |
|
|
165
|
+
| `lc config` | Show current configuration |
|
|
166
|
+
| `lc config --set key=value` | Update a config value |
|
|
167
|
+
| `lc config --vscode-init` | Generate `.vscode/tasks.json` |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Language Support
|
|
172
|
+
|
|
173
|
+
| Language | Flag | Runtime Required |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| Python 3 | `--lang python` | `python` |
|
|
176
|
+
| JavaScript | `--lang javascript` | `node` |
|
|
177
|
+
| C++ | `--lang cpp` | `g++` |
|
|
178
|
+
| Java | `--lang java` | `javac`, `java` |
|
|
179
|
+
|
|
180
|
+
Set your default language so you don't need `--lang` on every fetch:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
lc config --set settings.default_language=javascript
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Configuration
|
|
189
|
+
|
|
190
|
+
On first run, create `.leet2local.toml` in your project root:
|
|
191
|
+
|
|
192
|
+
```toml
|
|
193
|
+
[settings]
|
|
194
|
+
default_language = "python" # python | javascript | cpp | java
|
|
195
|
+
problems_dir = "./leetcode" # where problem directories are created
|
|
196
|
+
run_mode = "local" # local | remote
|
|
197
|
+
|
|
198
|
+
[api]
|
|
199
|
+
graphql_endpoint = "https://leetcode.com/graphql"
|
|
200
|
+
request_timeout = 30
|
|
201
|
+
max_retries = 5
|
|
202
|
+
|
|
203
|
+
[runtime]
|
|
204
|
+
python_cmd = "python"
|
|
205
|
+
node_cmd = "node"
|
|
206
|
+
java_cmd = "java"
|
|
207
|
+
javac_cmd = "javac"
|
|
208
|
+
cpp_compiler = "g++"
|
|
209
|
+
runner_timeout = 10 # seconds per test execution
|
|
210
|
+
|
|
211
|
+
[display]
|
|
212
|
+
show_difficulty = true
|
|
213
|
+
show_tags = false # hide tags to avoid spoilers
|
|
214
|
+
syntax_highlight = true
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Config is loaded from the nearest `.leet2local.toml` walking up from the current directory, falling back to `~/.config/leet2local/config.toml`.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## VS Code Integration
|
|
222
|
+
|
|
223
|
+
Generate keyboard-shortcut tasks:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
lc config --vscode-init
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
This creates `.vscode/tasks.json` with three tasks. Add to your `keybindings.json`:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
[
|
|
233
|
+
{ "key": "ctrl+shift+r", "command": "workbench.action.tasks.runTask", "args": "LC: Run Local" },
|
|
234
|
+
{ "key": "ctrl+shift+s", "command": "workbench.action.tasks.runTask", "args": "LC: Submit" }
|
|
235
|
+
]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## How It Works
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
lc fetch 1
|
|
244
|
+
└─ GraphQL: questionList (slug resolution)
|
|
245
|
+
└─ GraphQL: questionData (description, stub, test cases)
|
|
246
|
+
└─ HTML → Markdown (BeautifulSoup + markdownify)
|
|
247
|
+
└─ Write question.md, solution.py, test_cases.json
|
|
248
|
+
|
|
249
|
+
lc run 1
|
|
250
|
+
└─ Read test_cases.json
|
|
251
|
+
└─ Render Jinja2 test harness template
|
|
252
|
+
└─ subprocess → python harness.py
|
|
253
|
+
└─ Parse LEET_PASS / LEET_FAIL / LEET_ERROR output lines
|
|
254
|
+
|
|
255
|
+
lc submit 1
|
|
256
|
+
└─ GraphQL: submitCode mutation → submission_id
|
|
257
|
+
└─ Poll: checkSubmission every 2s
|
|
258
|
+
└─ Display Rich result table
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Project Structure
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
Leet2Local/
|
|
267
|
+
├── leet2local/
|
|
268
|
+
│ ├── cli.py # Typer CLI entry point
|
|
269
|
+
│ ├── auth.py # Login, keyring credential storage
|
|
270
|
+
│ ├── fetcher.py # GraphQL client, file creation
|
|
271
|
+
│ ├── runner.py # Local runner dispatcher
|
|
272
|
+
│ ├── submitter.py # Remote submission + polling
|
|
273
|
+
│ ├── html_parser.py # HTML → Markdown conversion
|
|
274
|
+
│ ├── models.py # Pydantic data models
|
|
275
|
+
│ ├── config.py # TOML config management
|
|
276
|
+
│ ├── queries.py # GraphQL query strings
|
|
277
|
+
│ ├── rate_limiter.py # Tenacity retry decorator
|
|
278
|
+
│ └── runners/
|
|
279
|
+
│ ├── base.py # Abstract Runner base class
|
|
280
|
+
│ ├── python_runner.py
|
|
281
|
+
│ ├── javascript_runner.py
|
|
282
|
+
│ ├── cpp_runner.py
|
|
283
|
+
│ └── java_runner.py
|
|
284
|
+
├── templates/ # Jinja2 test harness templates
|
|
285
|
+
├── scripts/
|
|
286
|
+
│ └── generate_slug_map.py # Build slug fallback map
|
|
287
|
+
└── tests/
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Limitations
|
|
293
|
+
|
|
294
|
+
- **Sample test cases only** for local runs — hidden test cases require `lc submit`
|
|
295
|
+
- LeetCode's API is unofficial and undocumented; field names may change
|
|
296
|
+
- C++ and Java require the respective compilers installed and on PATH
|
|
297
|
+
- `lc submit` requires a valid session cookie (obtained via `lc login`)
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Development
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Run tests
|
|
305
|
+
pytest
|
|
306
|
+
|
|
307
|
+
# Lint
|
|
308
|
+
ruff check .
|
|
309
|
+
|
|
310
|
+
# Regenerate slug fallback map (run once, requires internet)
|
|
311
|
+
python scripts/generate_slug_map.py
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
MIT
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Leet2Local
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/leet2local/)
|
|
4
|
+
[](https://pypi.org/project/leet2local/)
|
|
5
|
+
[](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
A CLI tool that brings LeetCode problems into your local IDE. Fetch problem descriptions, solve in your editor, run tests locally, and submit directly to LeetCode — all from the terminal.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
lc fetch 1 --lang python
|
|
12
|
+
lc run 1
|
|
13
|
+
lc submit 1
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Fetch any problem** by number — creates a local directory with the description, code stub, and sample test cases
|
|
21
|
+
- **Run locally** — executes your solution against sample test cases without touching LeetCode servers
|
|
22
|
+
- **Submit remotely** — sends your code to LeetCode and polls for full results including hidden test cases, runtime, and memory percentile
|
|
23
|
+
- **Multi-language** — Python, JavaScript, C++, and Java
|
|
24
|
+
- **VS Code integration** — generates `tasks.json` for keyboard-shortcut access to all commands
|
|
25
|
+
- **Secure auth** — session cookies stored in OS native keychain (Windows Credential Manager / macOS Keychain)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
**Requirements:** Python 3.11+
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install leet2local
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or install from source:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/dhineshtheprogrammer/leet2local.git
|
|
41
|
+
cd Leet2Local
|
|
42
|
+
pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For development (includes pytest and ruff):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install -e ".[dev]"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Log in
|
|
56
|
+
|
|
57
|
+
Get your session cookies from your browser after logging in to leetcode.com:
|
|
58
|
+
|
|
59
|
+
1. Open DevTools → Application → Cookies → `leetcode.com`
|
|
60
|
+
2. Copy `LEETCODE_SESSION` and `csrftoken`
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
lc login
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. Fetch a problem
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
lc fetch 1 # Two Sum, defaults to Python
|
|
70
|
+
lc fetch 42 --lang cpp # Trapping Rain Water in C++
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This creates:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
./leetcode/1-two-sum/
|
|
77
|
+
├── question.md # Problem description in Markdown
|
|
78
|
+
├── solution.py # Code stub from LeetCode
|
|
79
|
+
└── test_cases.json # Sample inputs and expected outputs
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 3. Write your solution
|
|
83
|
+
|
|
84
|
+
Open `solution.py` in your editor and implement the function.
|
|
85
|
+
|
|
86
|
+
### 4. Run locally
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
lc run 1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
┌─ Test Results ──────────────────────────────────┐
|
|
94
|
+
│ # │ Status │ Details │
|
|
95
|
+
│ 0 │ PASS │ │
|
|
96
|
+
│ 1 │ PASS │ │
|
|
97
|
+
│ 2 │ FAIL │ got: [] expected: [0, 1] │
|
|
98
|
+
└────────────────────────────────────────────────-┘
|
|
99
|
+
✗ 1/3 test(s) failed
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 5. Submit to LeetCode
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
lc submit 1
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
┌─ Accepted ──────────────────────────────────────┐
|
|
110
|
+
│ Runtime: 52 ms (beats 87.3%) │
|
|
111
|
+
│ Memory: 16.4 MB (beats 62.1%) │
|
|
112
|
+
│ Tests: 54/54 │
|
|
113
|
+
└─────────────────────────────────────────────────┘
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Commands
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `lc login` | Store LeetCode session cookies securely |
|
|
123
|
+
| `lc fetch <number> [--lang]` | Fetch problem and create local files |
|
|
124
|
+
| `lc run <number>` | Run solution against sample test cases |
|
|
125
|
+
| `lc submit <number>` | Submit to LeetCode and get full results |
|
|
126
|
+
| `lc config` | Show current configuration |
|
|
127
|
+
| `lc config --set key=value` | Update a config value |
|
|
128
|
+
| `lc config --vscode-init` | Generate `.vscode/tasks.json` |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Language Support
|
|
133
|
+
|
|
134
|
+
| Language | Flag | Runtime Required |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| Python 3 | `--lang python` | `python` |
|
|
137
|
+
| JavaScript | `--lang javascript` | `node` |
|
|
138
|
+
| C++ | `--lang cpp` | `g++` |
|
|
139
|
+
| Java | `--lang java` | `javac`, `java` |
|
|
140
|
+
|
|
141
|
+
Set your default language so you don't need `--lang` on every fetch:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
lc config --set settings.default_language=javascript
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Configuration
|
|
150
|
+
|
|
151
|
+
On first run, create `.leet2local.toml` in your project root:
|
|
152
|
+
|
|
153
|
+
```toml
|
|
154
|
+
[settings]
|
|
155
|
+
default_language = "python" # python | javascript | cpp | java
|
|
156
|
+
problems_dir = "./leetcode" # where problem directories are created
|
|
157
|
+
run_mode = "local" # local | remote
|
|
158
|
+
|
|
159
|
+
[api]
|
|
160
|
+
graphql_endpoint = "https://leetcode.com/graphql"
|
|
161
|
+
request_timeout = 30
|
|
162
|
+
max_retries = 5
|
|
163
|
+
|
|
164
|
+
[runtime]
|
|
165
|
+
python_cmd = "python"
|
|
166
|
+
node_cmd = "node"
|
|
167
|
+
java_cmd = "java"
|
|
168
|
+
javac_cmd = "javac"
|
|
169
|
+
cpp_compiler = "g++"
|
|
170
|
+
runner_timeout = 10 # seconds per test execution
|
|
171
|
+
|
|
172
|
+
[display]
|
|
173
|
+
show_difficulty = true
|
|
174
|
+
show_tags = false # hide tags to avoid spoilers
|
|
175
|
+
syntax_highlight = true
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Config is loaded from the nearest `.leet2local.toml` walking up from the current directory, falling back to `~/.config/leet2local/config.toml`.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## VS Code Integration
|
|
183
|
+
|
|
184
|
+
Generate keyboard-shortcut tasks:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
lc config --vscode-init
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This creates `.vscode/tasks.json` with three tasks. Add to your `keybindings.json`:
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
[
|
|
194
|
+
{ "key": "ctrl+shift+r", "command": "workbench.action.tasks.runTask", "args": "LC: Run Local" },
|
|
195
|
+
{ "key": "ctrl+shift+s", "command": "workbench.action.tasks.runTask", "args": "LC: Submit" }
|
|
196
|
+
]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## How It Works
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
lc fetch 1
|
|
205
|
+
└─ GraphQL: questionList (slug resolution)
|
|
206
|
+
└─ GraphQL: questionData (description, stub, test cases)
|
|
207
|
+
└─ HTML → Markdown (BeautifulSoup + markdownify)
|
|
208
|
+
└─ Write question.md, solution.py, test_cases.json
|
|
209
|
+
|
|
210
|
+
lc run 1
|
|
211
|
+
└─ Read test_cases.json
|
|
212
|
+
└─ Render Jinja2 test harness template
|
|
213
|
+
└─ subprocess → python harness.py
|
|
214
|
+
└─ Parse LEET_PASS / LEET_FAIL / LEET_ERROR output lines
|
|
215
|
+
|
|
216
|
+
lc submit 1
|
|
217
|
+
└─ GraphQL: submitCode mutation → submission_id
|
|
218
|
+
└─ Poll: checkSubmission every 2s
|
|
219
|
+
└─ Display Rich result table
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Project Structure
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
Leet2Local/
|
|
228
|
+
├── leet2local/
|
|
229
|
+
│ ├── cli.py # Typer CLI entry point
|
|
230
|
+
│ ├── auth.py # Login, keyring credential storage
|
|
231
|
+
│ ├── fetcher.py # GraphQL client, file creation
|
|
232
|
+
│ ├── runner.py # Local runner dispatcher
|
|
233
|
+
│ ├── submitter.py # Remote submission + polling
|
|
234
|
+
│ ├── html_parser.py # HTML → Markdown conversion
|
|
235
|
+
│ ├── models.py # Pydantic data models
|
|
236
|
+
│ ├── config.py # TOML config management
|
|
237
|
+
│ ├── queries.py # GraphQL query strings
|
|
238
|
+
│ ├── rate_limiter.py # Tenacity retry decorator
|
|
239
|
+
│ └── runners/
|
|
240
|
+
│ ├── base.py # Abstract Runner base class
|
|
241
|
+
│ ├── python_runner.py
|
|
242
|
+
│ ├── javascript_runner.py
|
|
243
|
+
│ ├── cpp_runner.py
|
|
244
|
+
│ └── java_runner.py
|
|
245
|
+
├── templates/ # Jinja2 test harness templates
|
|
246
|
+
├── scripts/
|
|
247
|
+
│ └── generate_slug_map.py # Build slug fallback map
|
|
248
|
+
└── tests/
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Limitations
|
|
254
|
+
|
|
255
|
+
- **Sample test cases only** for local runs — hidden test cases require `lc submit`
|
|
256
|
+
- LeetCode's API is unofficial and undocumented; field names may change
|
|
257
|
+
- C++ and Java require the respective compilers installed and on PATH
|
|
258
|
+
- `lc submit` requires a valid session cookie (obtained via `lc login`)
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Development
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Run tests
|
|
266
|
+
pytest
|
|
267
|
+
|
|
268
|
+
# Lint
|
|
269
|
+
ruff check .
|
|
270
|
+
|
|
271
|
+
# Regenerate slug fallback map (run once, requires internet)
|
|
272
|
+
python scripts/generate_slug_map.py
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|