Skip to content

Commit

Permalink
feat(pypi): Remove isort and use ruff to handle all styling
Browse files Browse the repository at this point in the history
feat(tests): Make formatting tests more robust to API changes
feat(formatter): Fix formatter to remove unecessary list closing tag
delete(requirements): Keep requirements only in pyproject.toml
feat(workflows): Add publishing workflow
  • Loading branch information
johnsutor committed Jan 4, 2025
1 parent 9d422e6 commit 1ee3fea
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 63 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/check-style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Examine formatting with black
python -m pip install -e ".[dev]"
- name: Examine formatting with ruff
run: |
pip install ruff
ruff check .
- name: Examine import ordering with isort
python -m ruff check ./leetcode_study_tool
- name: Check formatting
run: |
pip install isort
isort . --check --profile black
python -m ruff format ./leetcode_study_tool --check
117 changes: 117 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: Publish to PyPi
on:
push:
branches: [ "main" ]

jobs:
build:
name: Build distribution 📦
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

publish-to-pypi:
name: >-
Publish to PyPI
if: startsWith(github.ref, 'refs/tags/')
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/leetcode-study-tool
permissions:
id-token: write

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

github-release:
name: >-
Sign with Sigstore
and upload them to GitHub Release
needs:
- publish-to-pypi
runs-on: ubuntu-latest

permissions:
contents: write
id-token: write

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
run: >-
gh release create
"$GITHUB_REF_NAME"
--repo "$GITHUB_REPOSITORY"
--notes ""
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
run: >-
gh release upload
"$GITHUB_REF_NAME" dist/**
--repo "$GITHUB_REPOSITORY"
publish-to-testpypi:
name: Publish Python 🐍 distribution 📦 to TestPyPI
needs:
- build
runs-on: ubuntu-latest

environment:
name: testpypi
url: https://test.pypi.org/p/<package-name>

permissions:
id-token: write

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
13 changes: 2 additions & 11 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,10 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with ruff
run: |
pip install ruff
ruff . --ignore E501
python -m pip install -e ".[dev]"
- name: Type check with MyPy
run: |
pip install mypy
mypy . --ignore-missing-imports --exclude /build/
- name: Install package
run: |
pip install -e ".[dev]"
python -m mypy ./leetcode_study_tool
- name: Test with pytest, ensuring 75% coverage
run: |
pip install pytest pytest-cov
Expand Down
9 changes: 4 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ all:
$(MAKE) type-check

format:
ruff format .
isort --profile black .
python -m ruff format ./leetcode_study_tool

format-check:
ruff check .
isort --check-only --profile black .
python -m ruff check ./leetcode_study_tool
python -m ruff format ./leetcode_study_tool --check

test:
pytest tests/ --cov --cov-fail-under=85

type-check:
mypy src
python -m mypy ./leetcode_study_tool
19 changes: 8 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![PyPi](https://img.shields.io/pypi/v/leetcode-study-tool)](https://pypi.org/project/leetcode-study-tool/)
![contributions welcome](https://img.shields.io/badge/contributions-welcome-blue.svg?style=flat)

![Leetcode Study Tool Diagram](./static/leetcode_study_tool_diagram.png)
![Leetcode Study Tool Diagram](https://github.com/johnsutor/leetcode-study-tool/raw/main/static/leetcode_study_tool_diagram.png)

This package lets you get grokking as quickly as possible with Leetcode. It provides a command-line tool for interracting with Leetcode to create either an Excel file or Anki flashcards for study. Currently, this tool supports taking in a list of leetcode question slugs or URLs or popular study sets (including the [Blind 75](https://www.teamblind.com/post/New-Year-Gift---Curated-List-of-Top-75-LeetCode-Questions-to-Save-Your-Time-OaM1orEU), [Grind 75](https://www.techinterviewhandbook.org/grind75), and [Neetcode 150](https://neetcode.io/practice)).

Expand All @@ -19,20 +19,16 @@ $ pip install leetcode-study-tool

## 💻 Usage
```shell
usage: leetcode-study-tool [-h]
(--url URL | --file FILE | --preset {blind_75,grind_75,grind_169,neetcode_150,neetcode_all})
[--format {anki,excel}] [--csrf CSRF] [--output OUTPUT]
[--language LANGUAGE]
usage: leetcode-study-tool [-h] (--url URL | --file FILE | --preset {blind_75,grind_75,grind_169,neetcode_150,neetcode_250,neetcode_all}) [--format {anki,excel}]
[--csrf CSRF] [--output OUTPUT] [--language LANGUAGE]

Generates problems from LeetCode questions in a desired format.

options:
-h, --help show this help message and exit
--url URL, -u URL The URL(s) or slug(s) of the LeetCode question(s) to generate
problem(s) for. (default: None)
--file FILE, -f FILE The file containing the URL(s) or slug(s) of the LeetCode question(s)
to generate problem(s) for. (default: None)
--preset {blind_75,grind_75,grind_169,neetcode_150,neetcode_all}, -p {blind_75,grind_75,grind_169,neetcode_150,neetcode_250,neetcode_all}
--url URL, -u URL The URL(s) or slug(s) of the LeetCode question(s) to generate problem(s) for. (default: None)
--file FILE, -f FILE The file containing the URL(s) or slug(s) of the LeetCode question(s) to generate problem(s) for. (default: None)
--preset {blind_75,grind_75,grind_169,neetcode_150,neetcode_250,neetcode_all}, -p {blind_75,grind_75,grind_169,neetcode_150,neetcode_250,neetcode_all}
The preset to use to generate problem(s) for. (default: None)
--format {anki,excel}, -F {anki,excel}
The format to save the Leetcode problem(s) in. (default: anki)
Expand Down Expand Up @@ -78,11 +74,12 @@ When generating an Excel output, the resulting questions are saved in an `.xlsx`
- [X] Add support for exporting to an excel sheet
- [X] Add support for showing neetcode solutions on the back of the card as a
- [X] Add support for getting the difficulty of questions
- [ ] Add support for Jinja templating formatters
- [ ] Add NeetCode shorts
- [ ] Add support for fetching premium questions via authentification
- [ ] Add support for importing cards into Quizlet
- [ ] Add support for fetching questions by topic or tag
link
- [ ] Allow for the definition of custom formatters and outputs (including which fields are included or excluded)
- [ ] Reach 90% test coverage

## 🔎 Other Usefull Stuff
Expand Down
2 changes: 1 addition & 1 deletion leetcode_study_tool/creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,4 @@ def _generate_problem(self, url: str) -> Union[str, None]:

data = {k: self._sanitize(v) for k, v in data.items()}

return FORMAT_MAP[self.format](url, slug, data)
return FORMAT_MAP[self.format](url, slug, data) # type: ignore
2 changes: 1 addition & 1 deletion leetcode_study_tool/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def format_anki(url: str, slug: str, data: dict):
if str(data["id"]) in LEETCODE_TO_NEETCODE:
neetcode = LEETCODE_TO_NEETCODE[str(data["id"])]
problem += "<strong>NeetCode Solution:</strong><br>"
problem += f"<a href=\"{neetcode['url']}\">{neetcode['title']}</a></li><br><br>"
problem += f"<a href=\"{neetcode['url']}\">{neetcode['title']}</a><br><br>"

if data["solutions"]:
problem += format_list_element(
Expand Down
4 changes: 2 additions & 2 deletions leetcode_study_tool/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def query(
requests.exceptions.HTTPError
If the response from the LeetCode GraphQL API is not 200.
"""
assert content in MAPPINGS.keys(), f"Invalid query content: {content}"
assert content in MAPPINGS, f"Invalid query content: {content}"
if not session:
session = generate_session()

Expand All @@ -146,7 +146,7 @@ def query(
},
)
if response.status_code == 200:
return json.loads(response.content.decode("utf-8")).get("data")
return dict(json.loads(response.content.decode("utf-8")).get("data"))
else:
raise requests.exceptions.HTTPError(
f"LeetCode GraphQL API returned {response.status_code}"
Expand Down
33 changes: 19 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
[build-system]
requires = ["setuptools", "wheel"]
requires = ["setuptools>=62.6.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "leetcode-study-tool"
version = "1.3.3"
version = "1.3.4"
description = "A tool for studying Leetcode with Python"
authors = [{name="John Sutor", email="johnsutor3@gmail.com" }]
license = {file = "LICENSE.txt"}
readme = "README.md"

dependencies = ["requests", "XlsxWriter", "p_tqdm"]
keywords = ["leetcode", "leet", "study", "Anki"]
classifiers=[
# Development status
Expand All @@ -36,15 +34,20 @@ classifiers=[
'Topic :: Software Development',
'Topic :: Education',
]
dependencies = [
"requests==2.32.3",
"XlsxWriter==3.2.0",
"p-tqdm==1.4.2"
]

[project.optional-dependencies]
dev = [
"ruff",
"types-requests",
"google-api-python-client",
"isort",
"pytest",
"pytest-cov"
"ruff==0.8.6",
"mypy==1.14.1",
"types-requests>=2.32.0",
"google-api-python-client==2.157.0",
"pytest==8.3.4",
"pytest-cov>=5.0.0"
]

[tool.black]
Expand All @@ -62,15 +65,17 @@ homepage = "https://github.com/johnsutor/leetcode-study-tool"
repository = "https://github.com/johnsutor/leetcode-study-tool"
changelog = "https://github.com/johnsutor/leetcode-study-tool/blob/main/CHANGELOG.md"

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "B", "SIM"]

[tool.mypy]
exclude = [
"build",
"scripts"
]
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = true

[tool.setuptools.packages.find]
include = ["leetcode_study_tool"]

# [project.optional_dependencies]
# scripts = ["google-api-python-client", "google-auth-oauthlib", "google-auth-httplib2"]
include = ["leetcode_study_tool"]
6 changes: 0 additions & 6 deletions requirements.txt

This file was deleted.

Empty file removed requirements/base.txt
Empty file.
Empty file removed requirements/dev.txt
Empty file.
Loading

0 comments on commit 1ee3fea

Please sign in to comment.