Skip to content

Commit 0ec8f6b

Browse files
committed
Remove click, requests. Add jsonargparse, httpx, loguru
1 parent 2660852 commit 0ec8f6b

File tree

8 files changed

+1171
-489
lines changed

8 files changed

+1171
-489
lines changed

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.11.1
1+
3.12.2

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# hypermodern-python
22
Modern python environment
33

4-
poetry, pyenv, pytest, pytest-cov, pytest-mock, nox, flake8 (and plugins), black, safety, pre-commit, mypy, pytype (or pyre, pyright), desert, marshmallow, yypeguard,
4+
poetry, pyenv, pytest, pytest-cov, pytest-mock, nox, flake8 (and plugins), black, safety, pre-commit, mypy, pytype (or pyre, pyright), desert, marshmallow, typeguard,
55
sphinx, sphinx-autodoc-typehints, git actions, codecov.
66

7-
And important, run in python v3.11
7+
And important, run in python v3.12

poetry.lock

Lines changed: 1016 additions & 454 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "hypermodern-python"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "My python modern config"
55
authors = ["Duk <[email protected]>"]
66
license = "MIT"
@@ -11,12 +11,14 @@ documentation = "https://hypermodern-python.readthedocs.io"
1111

1212

1313
[tool.poetry.dependencies]
14-
python = "^3.11"
15-
click = "^8.1.3"
16-
requests = "^2.28.2"
14+
python = "^3.12"
1715
safety-db = "^2021.7.17"
1816
desert = "^2022.9.22"
1917
marshmallow = "^3.19.0"
18+
codecov = "^2.1.13"
19+
httpx = "^0.27.0"
20+
jsonargparse = {extras = ["all"], version = "^4.32.0"}
21+
loguru = "^0.7.2"
2022

2123

2224
[tool.poetry.group.dev.dependencies]

src/hypermodern_python/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
"""The hypermodern Python project."""
2-
__version__ = "0.1.0"
2+
3+
__version__ = "0.2.0"

src/hypermodern_python/console.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
"""Command-line interface."""
2+
23
import textwrap
34

4-
import click
5+
from prettier import cprint
6+
7+
from . import wikipedia
8+
9+
10+
def cmd():
11+
from jsonargparse import CLI
512

6-
from . import __version__, wikipedia
13+
CLI(wikipedia.Fetcher)
714

815

9-
@click.command()
10-
@click.option(
11-
"--language",
12-
"-l",
13-
default="en",
14-
help="Language edition of Wikipedia",
15-
metavar="LANG",
16-
show_default=True,
17-
)
18-
@click.version_option(version=__version__)
1916
def main(language: str) -> None:
2017
"""The hypermodern Python project."""
2118
page = wikipedia.random_page(language=language)
22-
click.secho(page.title, fg="green")
23-
click.echo(textwrap.fill(page.extract))
19+
cprint(page.title, fg="g")
20+
cprint(textwrap.fill(page.extract))

src/hypermodern_python/prettier.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import os
2+
3+
# System call
4+
os.system("")
5+
6+
7+
def cprint(fmt, fg=None, bg=None, style=None):
8+
"""
9+
Colour-printer.
10+
cprint( 'Hello!' ) # normal
11+
cprint( 'Hello!', fg='g' ) # green
12+
cprint( 'Hello!', fg='r', bg='w', style='bx' ) # bold red blinking on white
13+
List of colours (for fg and bg):
14+
k black
15+
r red
16+
g green
17+
y yellow
18+
b blue
19+
m magenta
20+
c cyan
21+
w white
22+
List of styles:
23+
b bold
24+
i italic
25+
u underline
26+
s strikethrough
27+
x blinking
28+
r reverse
29+
y fast blinking
30+
f faint
31+
h hide
32+
"""
33+
34+
COLCODE = {
35+
"k": 0, # black
36+
"r": 1, # red
37+
"g": 2, # green
38+
"y": 3, # yellow
39+
"b": 4, # blue
40+
"m": 5, # magenta
41+
"c": 6, # cyan
42+
"w": 7, # white
43+
}
44+
45+
FMTCODE = {
46+
"b": 1, # bold
47+
"f": 2, # faint
48+
"i": 3, # italic
49+
"u": 4, # underline
50+
"x": 5, # blinking
51+
"y": 6, # fast blinking
52+
"r": 7, # reverse
53+
"h": 8, # hide
54+
"s": 9, # strikethrough
55+
}
56+
57+
# properties
58+
props = []
59+
if isinstance(style, str):
60+
props = [FMTCODE[s] for s in style]
61+
if isinstance(fg, str):
62+
props.append(30 + COLCODE[fg])
63+
if isinstance(bg, str):
64+
props.append(40 + COLCODE[bg])
65+
66+
# display
67+
props = ";".join([str(x) for x in props])
68+
if props:
69+
print("\x1b[%sm%s\x1b[0m" % (props, fmt))
70+
else:
71+
print(fmt)

src/hypermodern_python/wikipedia.py

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
"""Client for the Wikipedia REST API, version 1."""
2-
import click
32

4-
import requests
5-
6-
from dataclasses import dataclass
3+
import asyncio
4+
from dataclasses import dataclass, field
75

86
import desert
9-
7+
import httpx
108
import marshmallow
9+
from loguru import logger
1110

12-
API_URL: str = "https://{language}.wikipedia.org/api/rest_v1/page/random/summary"
11+
API_URL: str = (
12+
"https://{language}.wikipedia.org/api/rest_v1/page/random/summary"
13+
)
1314

1415

1516
@dataclass
@@ -28,7 +29,40 @@ class Page:
2829
schema = desert.schema(Page, meta={"unknown": marshmallow.EXCLUDE})
2930

3031

31-
def random_page(language: str = "en") -> Page:
32+
@dataclass(slots=True)
33+
class Fetcher:
34+
url: str
35+
timeout: float | None = None
36+
37+
# These two are marked 'init=False' so they do not show up in the constructor # noqa: E501
38+
# logic because the user doesn't need the ability to initialize these values since # noqa: E501
39+
# they a.) have defaults and b.) are internal implementation details.
40+
client: httpx.Client = field(default_factory=httpx.Client, init=False)
41+
results: list[str] = field(default_factory=list, init=False)
42+
43+
def __post_init__(self) -> None:
44+
# Attach our timeout to our instance httpx client
45+
# (note how we need to do this in __post_init__ since we can't access
46+
# peer instance variables in the `field()` defaults above because there's # noqa: E501
47+
# no `self` existing there yet)
48+
self.client.timeout = self.timeout
49+
50+
def fetch(self) -> None:
51+
logger.info("[{}] Fetching with timeout {}", self.url, self.timeout)
52+
53+
self.results.append(self.client.get(self.url))
54+
55+
logger.info(
56+
"[{} :: {}] Found results: {}",
57+
self.url,
58+
len(self.results),
59+
self.results,
60+
)
61+
62+
63+
async def random_page(
64+
client: httpx.AsyncClient(), language: str = "en"
65+
) -> Page:
3266
"""Return a random page.
3367
3468
Performs a GET request to the /page/random/summary endpoint.
@@ -52,10 +86,25 @@ def random_page(language: str = "en") -> Page:
5286
url = API_URL.format(language=language)
5387

5488
try:
55-
with requests.get(url) as response:
56-
response.raise_for_status()
57-
data = response.json()
58-
return schema.load(data)
59-
except (requests.RequestException, marshmallow.ValidationError) as error:
89+
response = await client.get(url)
90+
data = response.json()
91+
return schema.load(data)
92+
except marshmallow.ValidationError as error:
6093
message = str(error)
61-
raise click.ClickException(message)
94+
raise message
95+
96+
97+
async def main() -> None:
98+
async with httpx.AsyncClient() as client:
99+
tasks = []
100+
for number in range(1, 10):
101+
tasks.append(
102+
asyncio.ensure_future(random_page(client, language="en"))
103+
)
104+
105+
original_page = await asyncio.gather(*tasks)
106+
for page in original_page:
107+
print(page)
108+
109+
110+
asyncio.run(main())

0 commit comments

Comments
 (0)