PyLinks 0.0.0.dev23__tar.gz → 0.0.0.dev24__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/PKG-INFO +2 -2
  2. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/pyproject.toml +2 -2
  3. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/PKG-INFO +2 -2
  4. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/SOURCES.txt +1 -0
  5. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/__init__.py +2 -4
  6. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/api/doi.py +6 -6
  7. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/api/github.py +8 -14
  8. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/api/orcid.py +2 -2
  9. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/http.py +9 -9
  10. pylinks-0.0.0.dev24/src/pylinks/site/__init__.py +1 -0
  11. pylinks-0.0.0.dev24/src/pylinks/site/binder.py +185 -0
  12. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/site/conda.py +4 -5
  13. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/site/github.py +32 -20
  14. pylinks-0.0.0.dev24/src/pylinks/site/lib_io.py +67 -0
  15. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/site/pypi.py +4 -5
  16. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/site/readthedocs.py +7 -8
  17. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/url.py +2 -2
  18. PyLinks-0.0.0.dev23/src/pylinks/site/__init__.py +0 -1
  19. PyLinks-0.0.0.dev23/src/pylinks/site/binder.py +0 -2
  20. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/setup.cfg +0 -0
  21. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/dependency_links.txt +0 -0
  22. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/not-zip-safe +0 -0
  23. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/requires.txt +0 -0
  24. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/PyLinks.egg-info/top_level.txt +0 -0
  25. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/_settings.py +0 -0
  26. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/api/__init__.py +0 -0
  27. {PyLinks-0.0.0.dev23 → pylinks-0.0.0.dev24}/src/pylinks/exceptions.py +0 -0
@@ -1,5 +1,5 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyLinks
3
- Version: 0.0.0.dev23
4
- Requires-Python: >=3.9
3
+ Version: 0.0.0.dev24
4
+ Requires-Python: >=3.10
5
5
  Requires-Dist: requests<3,>=2.31.0
@@ -17,10 +17,10 @@ namespaces = true
17
17
  # ----------------------------------------- Project Metadata -------------------------------------
18
18
  #
19
19
  [project]
20
- version = "0.0.0.dev23"
20
+ version = "0.0.0.dev24"
21
21
  name = "PyLinks"
22
22
  dependencies = [
23
23
  "requests >= 2.31.0, < 3",
24
24
  ]
25
- requires-python = ">=3.9"
25
+ requires-python = ">=3.10"
26
26
 
@@ -1,5 +1,5 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyLinks
3
- Version: 0.0.0.dev23
4
- Requires-Python: >=3.9
3
+ Version: 0.0.0.dev24
4
+ Requires-Python: >=3.10
5
5
  Requires-Dist: requests<3,>=2.31.0
@@ -18,5 +18,6 @@ src/pylinks/site/__init__.py
18
18
  src/pylinks/site/binder.py
19
19
  src/pylinks/site/conda.py
20
20
  src/pylinks/site/github.py
21
+ src/pylinks/site/lib_io.py
21
22
  src/pylinks/site/pypi.py
22
23
  src/pylinks/site/readthedocs.py
@@ -11,7 +11,5 @@ but can be used directly from the root. It returns a URL object, also defined in
11
11
  Other available modules offer shortcuts for creating useful URLs for popular online services.
12
12
  """
13
13
 
14
- from ._settings import settings
15
- from .url import url
16
- from .http import request, download, graphql_query
17
- from . import api, site
14
+ from pylinks._settings import settings
15
+ from pylinks import url, http, api, site, exceptions
@@ -5,7 +5,7 @@ import datetime
5
5
  from typing import Optional
6
6
 
7
7
  # Non-standard libraries
8
- from pylinks.http import request as _request
8
+ import pylinks as _pylinks
9
9
 
10
10
 
11
11
  class DOI:
@@ -58,13 +58,13 @@ class DOI:
58
58
  accept += f"; style={style}"
59
59
  if locale:
60
60
  accept += f"; locale={locale}"
61
- return _request(
61
+ return _pylinks.http.request(
62
62
  self.url, headers={"accept": accept}, encoding="utf-8", response_type="str"
63
63
  )
64
64
 
65
65
  @property
66
66
  def bibtex(self) -> str:
67
- return _request(
67
+ return _pylinks.http.request(
68
68
  self.url,
69
69
  headers={"accept": "application/x-bibtex"},
70
70
  encoding="utf-8",
@@ -73,7 +73,7 @@ class DOI:
73
73
 
74
74
  @property
75
75
  def ris(self) -> str:
76
- return _request(
76
+ return _pylinks.http.request(
77
77
  self.url,
78
78
  headers={"accept": "application/x-research-info-systems"},
79
79
  encoding="utf-8",
@@ -85,7 +85,7 @@ class DOI:
85
85
  """
86
86
  Citation data as a dictionary with Citeproc JSON schema.
87
87
  """
88
- return _request(
88
+ return _pylinks.http.request(
89
89
  self.url,
90
90
  headers={"accept": "application/citeproc+json"},
91
91
  encoding="utf-8",
@@ -98,7 +98,7 @@ class DOI:
98
98
  journal = data["container-title"] or None
99
99
  journal_abbr = (
100
100
  (
101
- data.get("container-title-short") or _request(
101
+ data.get("container-title-short") or _pylinks.http.request(
102
102
  f"https://abbreviso.toolforge.org/abbreviso/a/{journal}",
103
103
  response_type="str",
104
104
  ).title()
@@ -5,16 +5,15 @@ import re
5
5
  import mimetypes
6
6
 
7
7
  # Non-standard libraries
8
- import pylinks
9
- from pylinks import request, url, graphql_query
8
+ import pylinks as _pylinks
10
9
 
11
10
 
12
11
  class GitHub:
13
12
 
14
13
  def __init__(self, token: Optional[str] = None):
15
14
  self._endpoint = {
16
- "api": url("https://api.github.com"),
17
- "upload": url("https://uploads.github.com"),
15
+ "api": _pylinks.url.create("https://api.github.com"),
16
+ "upload": _pylinks.url.create("https://uploads.github.com"),
18
17
  }
19
18
  self._token = token
20
19
  self._headers = {"X-GitHub-Api-Version": "2022-11-28"}
@@ -31,7 +30,7 @@ class GitHub:
31
30
  extra_headers: dict | None = None,
32
31
  ) -> dict:
33
32
  headers = self._headers | extra_headers if extra_headers else self._headers
34
- response = graphql_query(
33
+ response = _pylinks.http.graphql_query(
35
34
  url=self._endpoint["api"] / "graphql",
36
35
  query=f"{{{query}}}",
37
36
  headers=headers,
@@ -50,7 +49,7 @@ class GitHub:
50
49
  f'mutation($mutationInput:{mutation_input_name}!) '
51
50
  f'{{{mutation_name}(input:$mutationInput) {{{mutation_payload}}}}}'
52
51
  )
53
- response = graphql_query(
52
+ response = _pylinks.http.graphql_query(
54
53
  url=self._endpoint["api"] / "graphql",
55
54
  query=query,
56
55
  variables={"mutationInput": mutation_input},
@@ -69,7 +68,7 @@ class GitHub:
69
68
  endpoint: Literal['api', 'upload'] = "api"
70
69
  ):
71
70
  headers = self._headers | extra_headers if extra_headers else self._headers
72
- return request(
71
+ return _pylinks.http.request(
73
72
  verb=verb,
74
73
  url=self._endpoint[endpoint] / query,
75
74
  headers=headers,
@@ -328,7 +327,7 @@ class Repo:
328
327
  if entry["type"] == "file":
329
328
  filename = Path(entry["path"]).name
330
329
  full_download_path = download_path / filename
331
- pylinks.download(
330
+ _pylinks.http.download(
332
331
  url=entry["download_url"], filepath=full_download_path, create_dirs=create_dirs
333
332
  )
334
333
  final_download_paths.append(full_download_path)
@@ -362,7 +361,7 @@ class Repo:
362
361
  full_download_path = download_path / download_filename
363
362
  else:
364
363
  full_download_path = download_path / Path(content["path"]).name
365
- pylinks.download(
364
+ _pylinks.http.download(
366
365
  url=content["download_url"],
367
366
  filepath=full_download_path,
368
367
  create_dirs=create_dirs,
@@ -391,11 +390,6 @@ class Repo:
391
390
  def discussion_categories(self) -> list[dict[str, str]]:
392
391
  """Get discussion categories for a repository.
393
392
 
394
- Parameters
395
- ----------
396
- access_token : str
397
- GitHub access token.
398
-
399
393
  Returns
400
394
  -------
401
395
  A list of discussion categories as dictionaries with keys "name", "slug", and "id".
@@ -3,7 +3,7 @@ import re
3
3
  import warnings
4
4
 
5
5
  # Non-standard libraries
6
- import pylinks
6
+ import pylinks as _pylinks
7
7
 
8
8
 
9
9
  class Orcid:
@@ -20,7 +20,7 @@ class Orcid:
20
20
  @property
21
21
  def records(self) -> dict:
22
22
  if not self._data:
23
- self._data = pylinks.request(
23
+ self._data = _pylinks.http.request(
24
24
  url=f"https://pub.orcid.org/v3.0/{self.id}",
25
25
  headers={"Accept": "application/json"},
26
26
  response_type="json",
@@ -20,7 +20,7 @@ import time
20
20
  from functools import wraps
21
21
  from pathlib import Path
22
22
  import requests
23
- from pylinks import exceptions
23
+ import pylinks as _pylinks
24
24
 
25
25
 
26
26
  class RetryConfig(NamedTuple):
@@ -73,7 +73,7 @@ class HTTPRequestRetryConfig(NamedTuple):
73
73
 
74
74
 
75
75
  def request(
76
- url: str,
76
+ url: str | _pylinks.url.URL,
77
77
  verb: Union[str, Literal["GET", "POST", "PUT", "PATCH", "OPTIONS", "DELETE"]] = "GET",
78
78
  params: Optional[Union[dict, List[tuple], bytes]] = None,
79
79
  data: Optional[Union[dict, List[tuple], bytes]] = None,
@@ -189,7 +189,7 @@ def request(
189
189
  else _retry_on_exception(
190
190
  get_response,
191
191
  config=retry_config.config_status,
192
- catch=exceptions.WebAPITemporaryStatusCodeError,
192
+ catch=_pylinks.exceptions.WebAPITemporaryStatusCodeError,
193
193
  )
194
194
  )
195
195
  # Call the (decorated or non-decorated) response function.
@@ -212,7 +212,7 @@ def request(
212
212
  if response_verifier is None or response_verifier(response_value):
213
213
  return response_value
214
214
  # otherwise raise
215
- raise exceptions.WebAPIValueError(response_value=response_value, response_verifier=response_verifier)
215
+ raise _pylinks.exceptions.WebAPIValueError(response_value=response_value, response_verifier=response_verifier)
216
216
 
217
217
  # Depending on specifications in argument `retry_config`, either decorate `get_response_value`
218
218
  # with `retry_on_exception`, or leave it as is.
@@ -226,7 +226,7 @@ def request(
226
226
  else _retry_on_exception(
227
227
  get_response_value,
228
228
  config=retry_config.config_response,
229
- catch=exceptions.WebAPIValueError,
229
+ catch=_pylinks.exceptions.WebAPIValueError,
230
230
  )
231
231
  )
232
232
  # Call the (decorated or non-decorated) response-value function and return.
@@ -266,9 +266,9 @@ def graphql_query(
266
266
  response = request(**args)
267
267
  if isinstance(response, dict):
268
268
  if "errors" in response:
269
- raise exceptions.WebAPIError(response)
269
+ raise _pylinks.exceptions.WebAPIError(response)
270
270
  elif "data" not in response:
271
- raise exceptions.WebAPIError(response)
271
+ raise _pylinks.exceptions.WebAPIError(response)
272
272
  else:
273
273
  response = response["data"]
274
274
  return response
@@ -352,9 +352,9 @@ def _raise_for_status_code(
352
352
  temporary_error_status_codes is not None
353
353
  and response.status_code in temporary_error_status_codes
354
354
  ):
355
- raise exceptions.WebAPITemporaryStatusCodeError(response)
355
+ raise _pylinks.exceptions.WebAPITemporaryStatusCodeError(response)
356
356
  if error_status_code_range[0] <= response.status_code <= error_status_code_range[1]:
357
- raise exceptions.WebAPIPersistentStatusCodeError(response)
357
+ raise _pylinks.exceptions.WebAPIPersistentStatusCodeError(response)
358
358
  return
359
359
 
360
360
 
@@ -0,0 +1 @@
1
+ from pylinks.site import binder, conda, github, pypi, readthedocs, lib_io
@@ -0,0 +1,185 @@
1
+ """URLs for Binder images.
2
+
3
+ References
4
+ ----------
5
+ - [Binder](https://mybinder.org/)
6
+ """
7
+
8
+
9
+ import pylinks as _pylinks
10
+
11
+
12
+ _BASE_URL = _pylinks.url.create(url="https://mybinder.org/v2")
13
+
14
+
15
+ def github(
16
+ user: str,
17
+ repo: str,
18
+ ref: str = "HEAD",
19
+ notebook_path: str | None = None,
20
+ ) -> _pylinks.url.URL:
21
+ """Create a Binder URL for a GitHub repository.
22
+
23
+ Parameters
24
+ ----------
25
+ user : str
26
+ GitHub username.
27
+ repo : str
28
+ GitHub repository name.
29
+ ref : str, default: "HEAD"
30
+ Branch, tag, or commit hash to use.
31
+ notebook_path : str, optional
32
+ Path to a Jupyter notebook file to open.
33
+ """
34
+ url = _BASE_URL / "gh" / user / repo / ref
35
+ if notebook_path is not None:
36
+ url.queries["labpath"] = notebook_path
37
+ return url
38
+
39
+
40
+ def gist(
41
+ user: str,
42
+ gist_id: str,
43
+ ref: str = "HEAD",
44
+ notebook_path: str | None = None,
45
+ ) -> _pylinks.url.URL:
46
+ """Create a Binder URL for a GitHub Gist.
47
+
48
+ Parameters
49
+ ----------
50
+ user : str
51
+ GitHub username.
52
+ gist_id : str
53
+ GitHub Gist ID.
54
+ ref : str, default: "HEAD"
55
+ Commit hash to use.
56
+ notebook_path : str, optional
57
+ Path to a Jupyter notebook file to open.
58
+ """
59
+ url = _BASE_URL / "gist" / user / gist_id / ref
60
+ if notebook_path is not None:
61
+ url.queries["labpath"] = notebook_path
62
+ return url
63
+
64
+
65
+ def git(
66
+ url: str,
67
+ ref: str = "HEAD",
68
+ notebook_path: str | None = None,
69
+ ) -> _pylinks.url.URL:
70
+ """Create a Binder URL for a Git repository.
71
+
72
+ Parameters
73
+ ----------
74
+ url : str
75
+ URL of the Git repository.
76
+ ref : str, default: "HEAD"
77
+ Branch, tag, or commit hash to use.
78
+ notebook_path : str, optional
79
+ Path to a Jupyter notebook file to open.
80
+ """
81
+ url = _BASE_URL / "git" / url / ref
82
+ if notebook_path is not None:
83
+ url.queries["labpath"] = notebook_path
84
+ return url
85
+
86
+
87
+ def gitlab(
88
+ user: str,
89
+ repo: str,
90
+ ref: str = "HEAD",
91
+ notebook_path: str | None = None,
92
+ ) -> _pylinks.url.URL:
93
+ """Create a Binder URL for a GitLab repository.
94
+
95
+ Parameters
96
+ ----------
97
+ user : str
98
+ GitLab username.
99
+ project : str
100
+ GitLab repository name.
101
+ ref : str, default: "HEAD"
102
+ Branch, tag, or commit hash to use.
103
+ notebook_path : str, optional
104
+ Path to a Jupyter notebook file to open.
105
+ """
106
+ url = _BASE_URL / "gl" / user / repo / ref
107
+ if notebook_path is not None:
108
+ url.queries["labpath"] = notebook_path
109
+ return url
110
+
111
+
112
+ def zenodo(
113
+ doi: str,
114
+ notebook_path: str | None = None,
115
+ ) -> _pylinks.url.URL:
116
+ """Create a Binder URL for a Zenodo repository.
117
+
118
+ Parameters
119
+ ----------
120
+ doi : str
121
+ Zenodo DOI.
122
+ notebook_path : str, optional
123
+ Path to a Jupyter notebook file to open.
124
+ """
125
+ url = _BASE_URL / "zenodo" / doi
126
+ if notebook_path is not None:
127
+ url.queries["labpath"] = notebook_path
128
+ return url
129
+
130
+
131
+ def figshare(
132
+ doi: str,
133
+ notebook_path: str | None = None,
134
+ ) -> _pylinks.url.URL:
135
+ """Create a Binder URL for a Figshare repository.
136
+
137
+ Parameters
138
+ ----------
139
+ doi : str
140
+ Figshare DOI.
141
+ notebook_path : str, optional
142
+ Path to a Jupyter notebook file to open.
143
+ """
144
+ url = _BASE_URL / "figshare" / doi
145
+ if notebook_path is not None:
146
+ url.queries["labpath"] = notebook_path
147
+ return url
148
+
149
+
150
+ def hydroshare(
151
+ resource_id: str,
152
+ notebook_path: str | None = None,
153
+ ) -> _pylinks.url.URL:
154
+ """Create a Binder URL for a HydroShare resource.
155
+
156
+ Parameters
157
+ ----------
158
+ resource_id : str
159
+ HydroShare resource ID.
160
+ notebook_path : str, optional
161
+ Path to a Jupyter notebook file to open.
162
+ """
163
+ url = _BASE_URL / "hydroshare" / resource_id
164
+ if notebook_path is not None:
165
+ url.queries["labpath"] = notebook_path
166
+ return url
167
+
168
+
169
+ def dataverse(
170
+ doi: str,
171
+ notebook_path: str | None = None,
172
+ ) -> _pylinks.url.URL:
173
+ """Create a Binder URL for a Dataverse repository.
174
+
175
+ Parameters
176
+ ----------
177
+ doi : str
178
+ Dataverse DOI.
179
+ notebook_path : str, optional
180
+ Path to a Jupyter notebook file to open.
181
+ """
182
+ url = _BASE_URL / "dataverse" / doi
183
+ if notebook_path is not None:
184
+ url.queries["labpath"] = notebook_path
185
+ return url
@@ -7,11 +7,10 @@ from typing import Optional
7
7
 
8
8
  # Non-standard libraries
9
9
  import requests
10
- from pylinks import settings, url
11
- from pylinks.url import URL
10
+ import pylinks as _pylinks
12
11
 
13
12
 
14
- BASE_URL = url(url="https://anaconda.org")
13
+ BASE_URL = _pylinks.url.create(url="https://anaconda.org")
15
14
 
16
15
 
17
16
  class Package:
@@ -37,7 +36,7 @@ class Package:
37
36
  )
38
37
  self._name = name
39
38
  self._channel = channel
40
- if validate is True or (validate is None and not settings.offline_mode):
39
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
41
40
  requests.get(str(self.homepage)).raise_for_status()
42
41
 
43
42
  def __repr__(self):
@@ -57,7 +56,7 @@ class Package:
57
56
  return self._channel
58
57
 
59
58
  @property
60
- def homepage(self) -> URL:
59
+ def homepage(self) -> _pylinks.url.URL:
61
60
  """URL of the package homepage."""
62
61
  return BASE_URL / self.channel / self.name
63
62
 
@@ -7,11 +7,10 @@ from typing import Literal, Optional
7
7
 
8
8
  # Non-standard libraries
9
9
  import requests
10
- from pylinks import settings, url
11
- from pylinks.url import URL
10
+ import pylinks as _pylinks
12
11
 
13
12
 
14
- BASE_URL = url(url="https://github.com")
13
+ BASE_URL = _pylinks.url.create(url="https://github.com")
15
14
 
16
15
 
17
16
  class User:
@@ -33,7 +32,7 @@ class User:
33
32
  "GitHub usernames can only contain alphanumeric characters and dashes."
34
33
  )
35
34
  self._name = name
36
- if validate is True or (validate is None and not settings.offline_mode):
35
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
37
36
  requests.get(str(self.homepage)).raise_for_status()
38
37
  return
39
38
 
@@ -49,7 +48,7 @@ class User:
49
48
  return self._name
50
49
 
51
50
  @property
52
- def homepage(self) -> URL:
51
+ def homepage(self) -> _pylinks.url.URL:
53
52
  """URL of the GitHub user's homepage."""
54
53
  return BASE_URL / self.name
55
54
 
@@ -88,7 +87,7 @@ class Repo:
88
87
  raise ValueError(
89
88
  'GitHub repository names can only contain "_", "-", ".", and alphanumeric characters.'
90
89
  )
91
- if validate is True or (validate is None and not settings.offline_mode):
90
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
92
91
  requests.get(str(self.homepage)).raise_for_status()
93
92
  return
94
93
 
@@ -109,11 +108,11 @@ class Repo:
109
108
  return self._name
110
109
 
111
110
  @property
112
- def homepage(self) -> URL:
111
+ def homepage(self) -> _pylinks.url.URL:
113
112
  """URL of the repository's homepage."""
114
113
  return self.user.homepage / self.name
115
114
 
116
- def workflow(self, filename: str) -> URL:
115
+ def workflow(self, filename: str) -> _pylinks.url.URL:
117
116
  """
118
117
  URL of a GitHub Actions workflow in the repository.
119
118
 
@@ -124,7 +123,7 @@ class Repo:
124
123
  """
125
124
  return self.homepage / "actions/workflows" / filename
126
125
 
127
- def workflow_run(self, run_id: str) -> URL:
126
+ def workflow_run(self, run_id: str) -> _pylinks.url.URL:
128
127
  """
129
128
  URL of the summary page of a specific GitHub Actions workflow run in the repository.
130
129
 
@@ -137,7 +136,7 @@ class Repo:
137
136
 
138
137
  def pr_issues(
139
138
  self, pr: bool = True, closed: Optional[bool] = None, label: Optional[str] = None
140
- ) -> URL:
139
+ ) -> _pylinks.url.URL:
141
140
  """
142
141
  URL of pull requests or issues in the repository.
143
142
 
@@ -162,11 +161,11 @@ class Repo:
162
161
  url.queries["q"] += f"+label:{label}"
163
162
  return url
164
163
 
165
- def commit(self, commit_hash: str) -> URL:
164
+ def commit(self, commit_hash: str) -> _pylinks.url.URL:
166
165
  """URL of a specific commit in the repository."""
167
166
  return self.homepage / "commit" / commit_hash
168
167
 
169
- def releases(self, tag: Optional[str | Literal["latest"]] = None) -> URL:
168
+ def releases(self, tag: Optional[str | Literal["latest"]] = None) -> _pylinks.url.URL:
170
169
  """
171
170
  URL of the releases overview page, or a specific release.
172
171
 
@@ -186,11 +185,24 @@ class Repo:
186
185
  return base_url / "tag" / tag
187
186
 
188
187
  @property
189
- def commits(self) -> URL:
188
+ def commits(self) -> _pylinks.url.URL:
190
189
  """URL of commits page."""
191
190
  return self.homepage / "commits"
192
191
 
193
- def discussions(self, category: Optional[str] = None) -> URL:
192
+ def compare(self, base: str, head: str) -> _pylinks.url.URL:
193
+ """
194
+ URL of a comparison between two references, i.e., branches, tags, or hashes.
195
+
196
+ Parameters
197
+ ----------
198
+ base : str
199
+ The base reference.
200
+ head : str
201
+ The head reference.
202
+ """
203
+ return self.homepage / "compare" / f"{base}...{head}"
204
+
205
+ def discussions(self, category: Optional[str] = None) -> _pylinks.url.URL:
194
206
  """
195
207
  URL of discussions page, or a specific discussion category page.
196
208
 
@@ -248,7 +260,7 @@ class Branch:
248
260
  raise ValueError(
249
261
  'GitHub branch names can only contain "_", "-", ".", "/", and alphanumeric characters.'
250
262
  )
251
- if validate is True or (validate is None and not settings.offline_mode):
263
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
252
264
  requests.get(str(self.homepage)).raise_for_status()
253
265
  return
254
266
 
@@ -258,7 +270,7 @@ class Branch:
258
270
  return self._repo
259
271
 
260
272
  @property
261
- def homepage(self) -> URL:
273
+ def homepage(self) -> _pylinks.url.URL:
262
274
  """URL of the branch's homepage."""
263
275
  return self.repo.homepage / "tree" / self.name
264
276
 
@@ -267,7 +279,7 @@ class Branch:
267
279
  """Name of the branch."""
268
280
  return self._name
269
281
 
270
- def workflow(self, filename: str) -> URL:
282
+ def workflow(self, filename: str) -> _pylinks.url.URL:
271
283
  """
272
284
  URL of a GitHub Actions workflow for this specific branch.
273
285
 
@@ -280,11 +292,11 @@ class Branch:
280
292
  url.queries = {"query": f"branch:{self.name}"}
281
293
  return url
282
294
 
283
- def file(self, filename: str, raw: bool = False) -> URL:
295
+ def file(self, filename: str, raw: bool = False) -> _pylinks.url.URL:
284
296
  """URL of a specific file in the branch."""
285
297
  if raw:
286
298
  return (
287
- url("https://raw.githubusercontent.com")
299
+ _pylinks.url.create("https://raw.githubusercontent.com")
288
300
  / self.repo.user.name
289
301
  / self.repo.name
290
302
  / self.name
@@ -293,7 +305,7 @@ class Branch:
293
305
  return self.homepage / filename
294
306
 
295
307
  @property
296
- def commits(self) -> URL:
308
+ def commits(self) -> _pylinks.url.URL:
297
309
  """URL of commits page for this branch."""
298
310
  return self.repo.homepage / "commits" / self.name
299
311
 
@@ -0,0 +1,67 @@
1
+ """URLs for the Libraries.io website."""
2
+
3
+
4
+ # Non-standard libraries
5
+ import requests
6
+ import pylinks as _pylinks
7
+
8
+
9
+ BASE_URL = _pylinks.url.create(url="https://libraries.io")
10
+
11
+
12
+ class Package:
13
+ """A Libraries.IO package site."""
14
+
15
+ def __init__(self, platform: str, package: str, validate: bool | None = None):
16
+ """
17
+ Parameters
18
+ ----------
19
+ platform : str
20
+ Name of the platform where the package is distributed, e.g. 'pypi', 'npm', etc.
21
+ package : str
22
+ Name of the package.
23
+ validate : bool, default: None
24
+ Whether to validate the URL online (requires an active internet connection).
25
+ If set to None (default), the global default value defined in `pylinks.OFFLINE_MODE` is used.
26
+ """
27
+ if not isinstance(platform, str):
28
+ raise TypeError(f"`platform` must be a string, not {type(platform)}.")
29
+ if not isinstance(package, str):
30
+ raise TypeError(f"`package` must be a string, not {type(package)}.")
31
+ self._platform = platform
32
+ self._package = package
33
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
34
+ requests.get(str(self.homepage)).raise_for_status()
35
+ return
36
+
37
+ @property
38
+ def platform(self) -> str:
39
+ """Name of the platform."""
40
+ return self._platform
41
+
42
+ @property
43
+ def package(self) -> str:
44
+ """Name of the package."""
45
+ return self._package
46
+
47
+ @property
48
+ def homepage(self) -> _pylinks.url.URL:
49
+ """URL of the package's homepage."""
50
+ return BASE_URL / self._platform / self._package
51
+
52
+ def dependencies(self, version: str) -> _pylinks.url.URL:
53
+ """URL of the webpage showing the dependencies of the package."""
54
+ return self.homepage / version / "tree"
55
+
56
+ @property
57
+ def source_rank(self) -> _pylinks.url.URL:
58
+ """URL of the webpage showing the source rank of the package."""
59
+ return self.homepage / "sourcerank"
60
+
61
+
62
+ def package(
63
+ platform: str,
64
+ package: str,
65
+ validate: bool | None = None,
66
+ ):
67
+ return Package(platform=platform, package=package, validate=validate)
@@ -7,11 +7,10 @@ from typing import Optional
7
7
 
8
8
  # Non-standard libraries
9
9
  import requests
10
- from pylinks import settings, url
11
- from pylinks.url import URL
10
+ import pylinks as _pylinks
12
11
 
13
12
 
14
- BASE_URL = url("https://pypi.org")
13
+ BASE_URL = _pylinks.url.create("https://pypi.org")
15
14
 
16
15
 
17
16
  class Package:
@@ -34,7 +33,7 @@ class Package:
34
33
  "Distribution name is invalid; see https://peps.python.org/pep-0508/#names."
35
34
  )
36
35
  self._name = name
37
- if validate is True or (validate is None and not settings.offline_mode):
36
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
38
37
  requests.get(str(self.homepage)).raise_for_status()
39
38
 
40
39
  @property
@@ -43,7 +42,7 @@ class Package:
43
42
  return self._name
44
43
 
45
44
  @property
46
- def homepage(self) -> URL:
45
+ def homepage(self) -> _pylinks.url.URL:
47
46
  """URL of the package homepage."""
48
47
  return BASE_URL / "project" / self.name
49
48
 
@@ -6,11 +6,10 @@ from typing import Optional
6
6
 
7
7
  # Non-standard libraries
8
8
  import requests
9
- from pylinks import settings, url
10
- from pylinks.url import URL
9
+ import pylinks as _pylinks
11
10
 
12
11
 
13
- BASE_URL = url(url="https://readthedocs.org")
12
+ BASE_URL = _pylinks.url.create(url="https://readthedocs.org")
14
13
 
15
14
 
16
15
  class Project:
@@ -29,7 +28,7 @@ class Project:
29
28
  if not isinstance(name, str):
30
29
  raise TypeError(f"`name` must be a string, not {type(name)}.")
31
30
  self._name = name
32
- if validate is True or (validate is None and not settings.offline_mode):
31
+ if validate is True or (validate is None and not _pylinks.settings.offline_mode):
33
32
  requests.get(str(self.project_home)).raise_for_status()
34
33
  return
35
34
 
@@ -39,19 +38,19 @@ class Project:
39
38
  return self._name
40
39
 
41
40
  @property
42
- def project_home(self) -> URL:
41
+ def project_home(self) -> _pylinks.url.URL:
43
42
  """URL of the project's homepage. This is not the homepage of the website."""
44
43
  return BASE_URL / "projects" / self.name
45
44
 
46
45
  @property
47
- def build_status(self) -> URL:
46
+ def build_status(self) -> _pylinks.url.URL:
48
47
  """URL of the webpage showing an overview of the website's build status."""
49
48
  return self.project_home / "builds"
50
49
 
51
50
  @property
52
- def homepage(self) -> URL:
51
+ def homepage(self) -> _pylinks.url.URL:
53
52
  """URL of the website's homepage."""
54
- return url(f"https://{self.name}.readthedocs.io")
53
+ return _pylinks.url.create(f"https://{self.name}.readthedocs.io")
55
54
 
56
55
 
57
56
  def project(
@@ -14,7 +14,7 @@ class URL:
14
14
  def __init__(
15
15
  self,
16
16
  base: str,
17
- queries: Optional[dict[str, str | bytes | None]] = None,
17
+ queries: Optional[dict[str, str | bytes | bool | None]] = None,
18
18
  fragment: Optional[str] = None,
19
19
  quote_safe: Optional[str] = "",
20
20
  query_delimiter: str = "&",
@@ -142,7 +142,7 @@ class URL:
142
142
  webbrowser.open(url=str(self), new=new, autoraise=autoraise)
143
143
 
144
144
 
145
- def url(
145
+ def create(
146
146
  url: str,
147
147
  queries: Optional[dict[str, str | bytes | None]] = None,
148
148
  fragment: Optional[str] = None,
@@ -1 +0,0 @@
1
- from . import binder, conda, github, pypi, readthedocs
@@ -1,2 +0,0 @@
1
- def launch():
2
- return "https://mybinder.org/v2/gh/Armin-Ariamajd/duq/main"
File without changes