Skip to content

Commit 54dc49c

Browse files
committed
Update readme and workflow
1 parent c65186c commit 54dc49c

File tree

8 files changed

+84
-33
lines changed

8 files changed

+84
-33
lines changed

.github/workflows/python-app.yml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
# This workflow will install Python dependencies, run tests and lint with a single version of Python
2-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3-
4-
name: Test and Lint
1+
name: Tests
52

63
on:
74
push:
@@ -14,11 +11,11 @@ permissions:
1411

1512
jobs:
1613
build:
17-
18-
runs-on: [ubuntu-latest, windows-latest, macos-latest]
1914
strategy:
2015
matrix:
21-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
16+
os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
17+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
18+
runs-on: ${{ matrix.os }}
2219
steps:
2320
- uses: actions/checkout@v3
2421
- name: Set up Python ${{ matrix.python-version }}
@@ -28,7 +25,7 @@ jobs:
2825
- name: Install dependencies
2926
run: |
3027
python -m pip install --upgrade pip
31-
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28+
pip install -r requirements.txt
3229
- name: Lint with ruff
3330
run: |
3431
pip install ruff
@@ -40,12 +37,12 @@ jobs:
4037
- name: Test with pytest
4138
run: |
4239
pip install pytest pytest-cov
43-
pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
40+
pytest tests/ --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
4441
- name: Examine formatting with black
4542
run: |
4643
pip install black
47-
black . --preview --check
44+
black . --check
4845
- name: Examine import ordering with isort
4946
run: |
5047
pip install isort
51-
isort . --check
48+
isort . --check --profile black

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
# Leetcode Study Tool
2-
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/esta/issues)
2+
![Tests Status](https://github.com/johnsutor/leetcode-study-tool/workflows/Tests/badge.svg)
3+
[![Python Versions](https://img.shields.io/pypi/pyversions/leetcode-study-tool)](https://pypi.org/project/leetcode-study-tool/)
4+
[![PyPi](https://img.shields.io/pypi/v/leetcode-study-tool)](https://pypi.org/project/leetcode-study-tool/)
5+
![contributions welcome](https://img.shields.io/badge/contributions-welcome-blue.svg?style=flat)
36

47
This package provides a command-line tool for interracting with Leetcode to create flashcards for study,
5-
which can then be imported into Anki.
8+
which can then be imported into Anki. Currently, this tool supports taking in a list of URLs and outputting
9+
problems in a format that can be imported to Anki. These cards include three fields:
10+
1. The front of the study card, containing the question ID, Title, URL, and problem description
11+
2. The publicly available solutions (and NeetCode solution, if available)
12+
3. The tags associated with the problem (i.e., if the problem involves a hash map, arrays, etc...)
13+
14+
## Installation
15+
```shell
16+
$ pip install leetcode-study-tool
17+
```
618

719
## Usage
820
```shell
@@ -22,6 +34,16 @@ options:
2234
The language to generate problem(s) for. (default: None)
2335
```
2436

37+
## Example
38+
In a directory with a file named `questions.txt`, where each line is either a Leetcode problem URL or slug (or a combination of both), we can run the command
39+
```shell
40+
$ leetcode-study-tool -f questions.txt
41+
```
42+
which will generate the file `output.txt`. We can then open Anki to import these problems as demonstrated below, *ensuring to select semicolon as a field separator*.
43+
44+
![anki demo](static/anki-demo.gif)
45+
46+
2547
## Roadmap
2648
- [ ] Add support for fetching premium questions via authentification
2749
- [ ] Add support for importing cards into Quizlet

leetcode_study_tool/cli.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import re
44
from functools import partial
55
from multiprocessing import Pool
6-
from typing import List
6+
from typing import List, Union
77

88
from .constants.leetcode_to_neetcode import LEETCODE_TO_NEETCODE
99
from .queries import get_data, get_slug, get_url
1010

1111

12-
def sanitize(input: str | list | None) -> str | list:
12+
def sanitize(input: Union[str, list, None]) -> Union[str, list]:
1313
"""
1414
Sanitize the given input to be Anki-compatible. This includes
1515
removing delimeters with the desired Anki delimeter chosen
@@ -56,7 +56,7 @@ def generate_solution_link(slug: str, solution_id: str) -> str:
5656

5757

5858
def save_output(
59-
problems: List[str | None], file: str, format: str = "cards"
59+
problems: List[Union[str, None]], file: str, format: str = "cards"
6060
) -> None:
6161
with open(file, "w") as f:
6262
for problem in problems:
@@ -65,8 +65,8 @@ def save_output(
6565

6666

6767
def generate_problem(
68-
url: str, language: str | None = None, format: str = "cards"
69-
) -> str | None:
68+
url: str, language: Union[str, None] = None, format: str = "cards"
69+
) -> Union[str, None]:
7070
"""
7171
Generates a problem strings for the given URL in the requested format
7272
@@ -112,9 +112,7 @@ def generate_problem(
112112
if str(data["id"]) in LEETCODE_TO_NEETCODE:
113113
neetcode = LEETCODE_TO_NEETCODE[str(data["id"])]
114114
problem += "<strong>NeetCode Solution:</strong><br>"
115-
problem += (
116-
f"<a href=\"{neetcode['url']}\">{neetcode['title']}</a></li><br><br>"
117-
)
115+
problem += f"<a href=\"{neetcode['url']}\">{neetcode['title']}</a></li><br><br>"
118116

119117
problem += "<strong>LeetCode User Solutions:</strong><br>"
120118

leetcode_study_tool/queries.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import json
22
import re
3-
from functools import cache
3+
from functools import lru_cache
4+
from typing import Union
45
from urllib.parse import urlparse
56

67
import requests
78

8-
from .constants.graphql import (BASE_URL, COMMUNITY_SOLUTIONS,
9-
QUESTION_CONTENT, QUESTION_DETAIL_COMPANY_TAGS,
10-
QUESTION_TITLE, SINGLE_QUESTION_TOPIC_TAGS)
9+
from .constants.graphql import (
10+
BASE_URL,
11+
COMMUNITY_SOLUTIONS,
12+
QUESTION_CONTENT,
13+
QUESTION_DETAIL_COMPANY_TAGS,
14+
QUESTION_TITLE,
15+
SINGLE_QUESTION_TOPIC_TAGS,
16+
)
1117

1218
MAPPINGS = {
1319
"content": QUESTION_CONTENT,
@@ -77,7 +83,7 @@ def get_url(input: str, type: str = "problem") -> str:
7783
return f"https://leetcode.com/tag/{input}/"
7884

7985

80-
@cache
86+
@lru_cache(maxsize=None)
8187
def query(content: str, slug: str, **kwargs) -> dict:
8288
"""
8389
Query the LeetCode GraphQL API for the given content.
@@ -117,7 +123,7 @@ def query(content: str, slug: str, **kwargs) -> dict:
117123
)
118124

119125

120-
def get_data(slug: str, language: str | None = None) -> dict:
126+
def get_data(slug: str, language: Union[str, None] = None) -> dict:
121127
"""
122128
Get the relevant data for constructing the Anki card for the given URL.
123129

pyproject.toml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,40 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "leetcode-study-tool"
7-
version = "1.0.0"
7+
version = "1.0.1"
88
description = "A tool for studying Leetcode with Python"
99
authors = [{name="John Sutor", email="johnsutor3@gmail.com" }]
1010
license = {file = "LICENSE.txt"}
1111
readme = "README.md"
1212
dependencies = ["requests"]
1313
keywords = ["leetcode", "leet", "study", "Anki"]
14+
classifiers=[
15+
# Development status
16+
'Development Status :: 4 - Beta',
17+
18+
# Supported OS
19+
'Operating System :: Microsoft :: Windows',
20+
'Operating System :: MacOS',
21+
'Operating System :: POSIX :: Linux',
22+
23+
# Supported Python versions
24+
'Programming Language :: Python :: 3.7',
25+
'Programming Language :: Python :: 3.8',
26+
'Programming Language :: Python :: 3.9',
27+
'Programming Language :: Python :: 3.10',
28+
'Programming Language :: Python :: 3.11',
29+
30+
# License
31+
'License :: OSI Approved :: MIT License',
32+
33+
# Topic
34+
'Topic :: Software Development',
35+
'Topic :: Education',
36+
]
1437

1538
[tool.black]
1639
line-length = 80
17-
target-version = ["py38", "py39", "py310", "py311"]
40+
target-version = ["py37", "py38", "py39", "py310", "py311"]
1841

1942
[options]
2043
python_requires = ">=3.6"
@@ -31,5 +54,8 @@ exclude = [
3154
]
3255
ignore_missing_imports = true
3356

57+
[tool.setuptools.packages.find]
58+
include = ["leetcode_study_tool"]
59+
3460
# [project.optional_dependencies]
3561
# scripts = ["google-api-python-client", "google-auth-oauthlib", "google-auth-httplib2"]

requirements.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
setuptools=68.0.0
2-
wheel=0.38.4
3-
requests=2.31.0
1+
setuptools==68.0.0
2+
wheel==0.38.4
3+
requests==2.31.0
4+
types-requests==2.31

scripts/neetcode.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
import os
1010
import re
1111
import sys
12+
from typing import Union
1213

1314
import googleapiclient.discovery
1415
import googleapiclient.errors
1516

1617
scopes = ["https://www.googleapis.com/auth/youtube.readonly"]
1718

1819

19-
def main(youtube_api_key: str | None = None):
20+
def main(youtube_api_key: Union[str, None] = None):
2021
# Disable OAuthlib's HTTPS verification when running locally.
2122
# *DO NOT* leave this option enabled in production.
2223
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

static/anki-demo.gif

15.4 MB
Loading

0 commit comments

Comments
 (0)