Skip to content

Commit

Permalink
Add 'pep next' command to find the next available number
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk committed Sep 19, 2023
1 parent 68c1fde commit cd7acff
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ https://pep-previews--2440.org.readthedocs.build

<!-- [[[end]]] -->

### Find the next available PEP number

Check published PEPs and [open PRs](https://github.com/python/peps/pulls) to find the
next available PEP number.

<!-- [[[cog run("pep next") ]]] -->

```console
$ pep next
Next available PEP: 729
```

<!-- [[[end]]] -->

### Open a BPO issue in the browser

Issues from [bugs.python.org](https://bugs.python.org/) have been migrated to
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dynamic = [
"version",
]
dependencies = [
"ghapi",
"platformdirs",
"python-slugify",
"thefuzz",
Expand Down
65 changes: 59 additions & 6 deletions src/pepotron/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import importlib.metadata
import logging
import warnings
from itertools import pairwise
from pathlib import Path

from pepotron import _cache
from . import _cache

__version__ = importlib.metadata.version(__name__)

Expand Down Expand Up @@ -70,22 +71,71 @@ def _download_peps_json(json_url: str = BASE_URL + JSON_PATH) -> Path:
return cache_file


def word_search(search: str | None) -> int:
def _get_peps() -> _cache.PepData:
import json

peps_file = _download_peps_json()

with open(peps_file) as f:
peps: _cache.PepData = json.load(f)

return peps


def _get_published_peps() -> set[int]:
peps = _get_peps()
numbers = {int(number) for number, details in peps.items()}
return numbers


def _next_available_pep() -> int:
published = _get_published_peps()
proposed = _get_pr_peps()
combined = published | proposed
numbers = sorted(combined)

start = 400
next_pep = -1
for x, y in pairwise(numbers):
if x < start:
continue
if x + 1 != y:
next_pep = x + 1
break

return next_pep


def _get_pr_peps() -> set[int]:
import re

from ghapi.all import GhApi # type: ignore

api = GhApi(owner="python", repo="peps", authenticate=False)
prs = api.pulls.list()

pr_title_regex = re.compile(r"^PEP (\d+): .*")

numbers = set()
for pr in prs:
if match := re.search(pr_title_regex, pr.title):
number = match[1]
numbers.add(int(number))

return numbers


def word_search(search: str | None) -> int:
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=UserWarning)
from thefuzz import process # type: ignore

with open(peps_file) as f:
peps = json.load(f)
peps = _get_peps()

# We only want to search titles
peps = ((number, details["title"]) for number, details in peps.items())
numbers_titles = ((number, details["title"]) for number, details in peps.items())

result: list[tuple[tuple[str, str], int]] = process.extract(search, peps)
result: list[tuple[tuple[str, str], int]] = process.extract(search, numbers_titles)
print("Score\tResult")
for match, score in result:
print(f"{score}\tPEP {match[0]}: {match[1]}")
Expand All @@ -111,6 +161,9 @@ def pep_url(search: str | None, base_url: str = BASE_URL, pr: int | None = None)
if search.lower() in TOPICS:
return result + f"/topic/{search}/"

if search.lower() == "next":
return f"Next available PEP: {_next_available_pep()}"

try:
# pep 8
number = int(search)
Expand Down
2 changes: 1 addition & 1 deletion src/pepotron/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import atexit
import logging

from pepotron import BASE_URL, __version__, _cache, open_bpo, open_pep
from . import BASE_URL, __version__, _cache, open_bpo, open_pep

atexit.register(_cache.clear)

Expand Down

0 comments on commit cd7acff

Please sign in to comment.