Skip to content

Commit 0b1a695

Browse files
authored
Reduce requirements (#141)
Make `requests` and `click` optional requirements
1 parent 1ca7fa5 commit 0b1a695

File tree

7 files changed

+55
-64
lines changed

7 files changed

+55
-64
lines changed

.readthedocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ build:
2424
- asdf install uv latest
2525
- asdf global uv latest
2626
- uv venv $READTHEDOCS_VIRTUALENV_PATH
27-
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH uv pip install .[docs,rdf,pandas,xml,aws,yaml,pydantic]
27+
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH uv pip install .[docs,rdf,pandas,xml,aws,yaml,pydantic,requests,cli]
2828
- python -m sphinx -T -b html -d docs/_build/doctrees -D language=en docs/source $READTHEDOCS_OUTPUT/html

pyproject.toml

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ classifiers = [
2020
"Development Status :: 5 - Production/Stable",
2121
"Environment :: Console",
2222
"Intended Audience :: Developers",
23-
"License :: OSI Approved :: MIT License",
2423
"Operating System :: OS Independent",
2524
"Framework :: Pytest",
2625
"Framework :: tox",
@@ -44,14 +43,10 @@ keywords = [
4443

4544
# License Information.
4645
# See PEP-639 at https://peps.python.org/pep-0639/#add-license-files-key
47-
license-files = [
48-
"LICENSE",
49-
]
46+
license = { file = "LICENSE" }
5047

5148
requires-python = ">=3.10"
5249
dependencies = [
53-
"click",
54-
"requests",
5550
"tqdm",
5651
"typing-extensions",
5752
]
@@ -60,7 +55,7 @@ dependencies = [
6055
tests = [
6156
"pytest",
6257
"coverage[toml]",
63-
"requests_file",
58+
"requests-file",
6459
]
6560
typing = [
6661
"mypy",
@@ -69,39 +64,24 @@ typing = [
6964
"types-ratelimit",
7065
"types-PyYAML",
7166
]
72-
73-
[project.optional-dependencies]
74-
tests = [
75-
"pytest",
76-
"coverage[toml]",
77-
"requests_file",
78-
]
7967
docs = [
8068
"sphinx>=8",
8169
"sphinx-rtd-theme>=3.0",
82-
"sphinx-click",
83-
"sphinx_automodapi",
84-
]
85-
rdf = [
86-
"rdflib",
87-
]
88-
xml = [
89-
"lxml",
90-
]
91-
pandas = [
92-
"pandas",
93-
]
94-
aws = [
95-
"boto3",
96-
]
97-
ratelimit = [
98-
"ratelimit",
99-
]
100-
bs4 = [
101-
"bs4",
70+
"sphinx-click",
71+
"sphinx-automodapi",
10272
]
73+
74+
[project.optional-dependencies]
75+
rdf = ["rdflib"]
76+
xml = ["lxml"]
77+
pandas = ["pandas"]
78+
aws = ["boto3"]
79+
ratelimit = ["ratelimit", "requests"]
80+
bs4 = ["bs4"]
10381
yaml = ["pyyaml"]
10482
pydantic = ["pydantic"]
83+
cli = ["click"]
84+
requests = ["requests"]
10585

10686
# See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#urls
10787
# and also https://packaging.python.org/en/latest/specifications/well-known-project-urls/

src/pystow/cli.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
# -*- coding: utf-8 -*-
2-
# flake8: noqa
3-
# type: ignore
4-
51
"""Command line interface for PyStow."""
62

73
from __future__ import annotations
84

95
import os
10-
from typing import Optional, Sequence
6+
from collections.abc import Sequence
7+
from pathlib import Path
118

129
import click
1310

@@ -20,7 +17,7 @@ def main() -> None:
2017
@main.command()
2118
@click.argument("keys", nargs=-1)
2219
@click.option("--name")
23-
def join(keys: Sequence[str], name: Optional[str]):
20+
def join(keys: Sequence[str], name: str | None) -> None:
2421
"""List a directory."""
2522
from . import api
2623

@@ -29,7 +26,7 @@ def join(keys: Sequence[str], name: Optional[str]):
2926

3027
@main.command()
3128
@click.argument("keys", nargs=-1)
32-
def ls(keys: Sequence[str]):
29+
def ls(keys: Sequence[str]) -> None:
3330
"""List a directory."""
3431
from . import api
3532

@@ -42,15 +39,15 @@ def ls(keys: Sequence[str]):
4239
@click.option("--url", required=True)
4340
@click.option("--name")
4441
@click.option("--force", is_flag=True)
45-
def ensure(keys: Sequence[str], url: str, name: Optional[str], force: bool):
42+
def ensure(keys: Sequence[str], url: str, name: str | None, force: bool) -> None:
4643
"""Ensure a file is downloaded."""
4744
from . import api
4845

4946
path = api.ensure(*keys, url=url, name=name, force=force)
5047
_ls(path.parent)
5148

5249

53-
def _ls(directory):
50+
def _ls(directory: Path) -> None:
5451
command = f"ls -al {directory}"
5552
click.secho(f"[pystow] {command}", fg="cyan", bold=True)
5653
os.system(command) # noqa:S605
@@ -60,7 +57,7 @@ def _ls(directory):
6057
@click.argument("module")
6158
@click.argument("key")
6259
@click.argument("value")
63-
def set_config(module: str, key: str, value: str):
60+
def set_config(module: str, key: str, value: str) -> None:
6461
"""Set a configuration value."""
6562
from .config_api import write_config
6663

src/pystow/github.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
from collections.abc import Iterable
66
from functools import partial
7-
from typing import Any, Literal, cast
7+
from typing import TYPE_CHECKING, Any, Literal, cast
88

9-
import requests
109
from ratelimit import rate_limited
1110
from tqdm import tqdm
1211

1312
from .config_api import get_config
1413
from .constants import TimeoutHint
1514

15+
if TYPE_CHECKING:
16+
import requests
17+
1618
__all__ = [
1719
"MAXIMUM_SEARCH_PAGE_SIZE",
1820
"delete_branch",
@@ -81,6 +83,8 @@ def _request_github(
8183
**kwargs: Any,
8284
) -> requests.Response:
8385
"""Make a POST request to the GitHub API."""
86+
import requests
87+
8488
path = path.lstrip("/")
8589
url = f"https://api.github.com/{path}"
8690
headers = get_headers(token=token, raise_on_missing=require_token, preview=preview)

src/pystow/utils/download.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from typing import TYPE_CHECKING, Any, Literal, TypeAlias, TypedDict
1212
from urllib.request import urlretrieve
1313

14-
import requests
1514
from tqdm import tqdm
1615
from typing_extensions import NotRequired, Unpack
1716

@@ -20,6 +19,8 @@
2019

2120
if TYPE_CHECKING:
2221
import botocore.client
22+
import requests
23+
import requests.exceptions
2324

2425
__all__ = [
2526
"DownloadBackend",
@@ -158,6 +159,9 @@ def download( # noqa:C901
158159
except urllib.error.URLError as e:
159160
raise DownloadError(backend, url, path, e) from e
160161
elif backend == "requests":
162+
import requests
163+
import requests.exceptions
164+
161165
kwargs.setdefault("stream", True)
162166
try:
163167
# see https://requests.readthedocs.io/en/master/user/quickstart/#raw-response-content
@@ -266,6 +270,8 @@ def download_from_google(
266270
:raises KeyboardInterrupt: If a keyboard interrupt is thrown during download
267271
:raises UnexpectedDirectory: If a directory is given for the ``path`` argument
268272
"""
273+
import requests
274+
269275
path = Path(path).resolve()
270276

271277
if path.is_dir():

src/pystow/utils/hashing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
from collections.abc import Collection, Iterable, Mapping
88
from pathlib import Path
99
from typing import NamedTuple, TypeAlias
10-
11-
import requests
10+
from urllib.request import urlopen
1211

1312
__all__ = [
1413
"Hash",
@@ -43,7 +42,8 @@ def get_hexdigests_remote(
4342
"""
4443
rv = {}
4544
for key, url in (hexdigests_remote or {}).items():
46-
text = requests.get(url, timeout=15).text
45+
with urlopen(url) as response: # noqa:S310
46+
text = response.read().decode("utf-8")
4747
if not hexdigests_strict and "=" in text:
4848
text = text.rsplit("=", 1)[-1].strip()
4949
rv[key] = text

tox.ini

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,19 @@ commands =
3737
coverage run -p -m pytest --durations=20 {posargs:tests}
3838
coverage combine
3939
coverage xml
40-
extras =
41-
# See the [project.optional-dependencies] entry in pyproject.toml for "tests"
40+
dependency_groups =
4241
tests
42+
extras =
43+
# See the [project.optional-dependencies] entry in pyproject.toml
4344
pandas
4445
rdf
4546
xml
4647
ratelimit
4748
bs4
4849
yaml
4950
pydantic
51+
requests
52+
cli
5053

5154
[testenv:coverage-clean]
5255
description = Remove testing coverage artifacts.
@@ -113,6 +116,7 @@ commands =
113116

114117
[testenv:pyroma]
115118
deps =
119+
uv-build
116120
pygments
117121
pyroma
118122
skip_install = true
@@ -121,17 +125,19 @@ description = Run the pyroma tool to check the package friendliness of the proje
121125

122126
[testenv:mypy]
123127
description = Run the mypy tool to check static typing on the project. Installs the package to make sure all type stubs get recognized.
124-
deps =
125-
mypy
126-
pydantic
127-
types-requests
128-
types-ratelimit
129-
types-PyYAML
128+
dependency_groups =
129+
typing
130130
extras =
131+
# See the [project.optional-dependencies] entry in pyproject.toml
131132
pandas
132133
rdf
133134
xml
134135
ratelimit
136+
bs4
137+
yaml
138+
pydantic
139+
requests
140+
cli
135141
commands = mypy --install-types --non-interactive --ignore-missing-imports --strict src/ tests/
136142

137143
[testenv:doc8]
@@ -154,18 +160,16 @@ commands =
154160

155161
[testenv:docs]
156162
description = Build the documentation locally, allowing warnings.
157-
extras =
158-
# See the [project.optional-dependencies] entry in pyproject.toml for "docs"
163+
dependency_groups =
159164
docs
160-
# You might need to add additional extras if your documentation covers it
161165
commands =
162166
python -m sphinx -b html -d docs/build/doctrees docs/source docs/build/html
163167

164168
[testenv:docs-test]
165169
description = Test building the documentation in an isolated environment. Warnings are considered as errors via -W.
166170
changedir = docs
167-
extras =
168-
{[testenv:docs]extras}
171+
dependency_groups =
172+
{[testenv:docs]dependency_groups}
169173
commands =
170174
mkdir -p {envtmpdir}
171175
cp -r source {envtmpdir}/source

0 commit comments

Comments
 (0)