depsdev 0.0.1__py3-none-any.whl → 0.0.2__py3-none-any.whl

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.
depsdev/__main__.py CHANGED
@@ -1,14 +1,130 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
4
+ from textwrap import dedent
5
+ from typing import TYPE_CHECKING
3
6
 
4
- def main(argv: list[str] | None = None) -> int:
5
- import argparse
7
+ if TYPE_CHECKING:
8
+ from collections.abc import Callable
6
9
 
7
- parser = argparse.ArgumentParser()
8
- args = parser.parse_args(argv)
9
- print(f"Arguments: {vars(args)=}")
10
- return 0
10
+ from typing_extensions import ParamSpec
11
+ from typing_extensions import TypeVar
12
+
13
+ P = ParamSpec("P")
14
+ R = TypeVar("R")
15
+
16
+
17
+ def to_sync() -> Callable[[Callable[P, R]], Callable[P, R]]:
18
+ """
19
+ Decorator to convert async methods to sync methods.
20
+ """
21
+
22
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
23
+ import functools
24
+
25
+ @functools.wraps(func)
26
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
27
+ try:
28
+ import asyncio
29
+
30
+ from rich import print_json
31
+
32
+ print_json(data=asyncio.run(func(*args, **kwargs))) # type: ignore[arg-type]
33
+ except: # noqa: E722
34
+ raise SystemExit(1) from None
35
+
36
+ raise SystemExit(0)
37
+
38
+ return wrapper
39
+
40
+ return decorator
41
+
42
+
43
+ def main() -> None:
44
+ """
45
+ Main entry point for the CLI.
46
+ """
47
+ import logging
48
+
49
+ logging.basicConfig(
50
+ level=logging.ERROR,
51
+ format="[%(asctime)s] [%(levelname)-7s] [%(name)s] %(message)s",
52
+ )
53
+ logging.getLogger("httpx").setLevel(logging.WARNING)
54
+ logger = logging.getLogger("depsdev")
55
+
56
+ try:
57
+ import typer
58
+ except ImportError:
59
+ msg = (
60
+ "The 'cli' optional dependency is not installed. "
61
+ "Please install it with 'pip install depsdev[cli]'."
62
+ )
63
+ logger.error(msg) # noqa: TRY400
64
+ raise SystemExit(1) from None
65
+
66
+ alpha = os.environ.get("DEPSDEV_V3_ALPHA", "false").lower() in ("true", "1", "yes")
67
+
68
+ app = typer.Typer(
69
+ name="depsdev",
70
+ no_args_is_help=True,
71
+ rich_markup_mode="rich",
72
+ help=dedent(
73
+ """\
74
+ A CLI tool to interact with the https://docs.deps.dev/api/
75
+
76
+ ## Package names
77
+
78
+ In general, the API refers to packages by the names used within their ecosystem, including details such as capitalization.
79
+
80
+ Exceptions:
81
+
82
+ - Maven names are of the form <group ID>:<artifact ID>, for example org.apache.logging.log4j:log4j-core.
83
+ - PyPI names are normalized as per PEP 503.
84
+ - NuGet names are normalized through lowercasing according to the Package Content API request parameter specification. Versions are normalized according to NuGet 3.4+ rules.
85
+
86
+ ## Purl parameters
87
+
88
+ Some methods accept purls, or package URLs, which have their own rules about how components should be encoded. https://github.com/package-url/purl-spec
89
+
90
+ For example, the npm package @colors/colors has the purl pkg:npm/@colors/colors.
91
+
92
+ To enable the alpha features, set the environment variable DEPSDEV_V3_ALPHA to true.
93
+ """, # noqa: E501
94
+ ),
95
+ )
96
+
97
+ from depsdev.v3 import DepsDevClientV3
98
+ from depsdev.v3alpha import DepsDevClientV3Alpha
99
+
100
+ client_v3_alpha = DepsDevClientV3Alpha()
101
+ client_v3 = DepsDevClientV3()
102
+
103
+ client = client_v3 if not alpha else client_v3_alpha
104
+
105
+ app.command(rich_help_panel="v3")(to_sync()(client.get_package))
106
+ app.command(rich_help_panel="v3")(to_sync()(client.get_version))
107
+ app.command(rich_help_panel="v3")(to_sync()(client.get_requirements))
108
+ app.command(rich_help_panel="v3")(to_sync()(client.get_dependencies))
109
+ app.command(rich_help_panel="v3")(to_sync()(client.get_project))
110
+ app.command(rich_help_panel="v3")(to_sync()(client.get_project_package_versions))
111
+ app.command(rich_help_panel="v3")(to_sync()(client.get_advisory))
112
+ app.command(rich_help_panel="v3")(to_sync()(client.query))
113
+
114
+ if alpha:
115
+ # app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.get_version_batch))
116
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.get_dependents))
117
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.get_capabilities))
118
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.get_project_batch))
119
+ app.command(rich_help_panel="v3alpha")(
120
+ to_sync()(client_v3_alpha.get_similarly_named_packages)
121
+ )
122
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.purl_lookup))
123
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.purl_lookup_batch))
124
+ app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.query_container_images))
125
+
126
+ return app()
11
127
 
12
128
 
13
129
  if __name__ == "__main__":
14
- raise SystemExit(main())
130
+ main()
depsdev/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.1'
21
- __version_tuple__ = version_tuple = (0, 0, 1)
20
+ __version__ = version = '0.0.2'
21
+ __version_tuple__ = version_tuple = (0, 0, 2)
depsdev/v3.py ADDED
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+ from dataclasses import field
6
+ from enum import Enum
7
+ from typing import TYPE_CHECKING
8
+ from typing import Optional
9
+ from urllib.parse import quote
10
+
11
+ import httpx
12
+
13
+ if TYPE_CHECKING:
14
+ from httpx._types import QueryParamTypes
15
+ from typing_extensions import Literal
16
+
17
+ logger = logging.getLogger(__name__)
18
+ Incomplete = object
19
+
20
+
21
+ class HashType(str, Enum):
22
+ MD5 = "MD5"
23
+ SHA1 = "SHA1"
24
+ SHA256 = "SHA256"
25
+ SHA512 = "SHA512"
26
+
27
+
28
+ class System(str, Enum):
29
+ GO = "GO"
30
+ RUBYGEMS = "RUBYGEMS"
31
+ NPM = "NPM"
32
+ CARGO = "CARGO"
33
+ MAVEN = "MAVEN"
34
+ PYPI = "PYPI"
35
+ NUGET = "NUGET"
36
+
37
+
38
+ def url_escape(string: str) -> str:
39
+ return quote(string, safe="")
40
+
41
+
42
+ @dataclass
43
+ class DepsDevClientV3:
44
+ client: httpx.AsyncClient = field(init=False)
45
+ timeout: float = 5.0
46
+ base_url: str = "https://api.deps.dev"
47
+
48
+ def __post_init__(self) -> None:
49
+ self.client = httpx.AsyncClient(base_url=self.base_url, timeout=self.timeout)
50
+
51
+ async def _requests(
52
+ self,
53
+ url: str = "",
54
+ method: Literal["GET", "POST"] = "GET",
55
+ params: QueryParamTypes | None = None,
56
+ json: object | None = None,
57
+ ) -> Incomplete:
58
+ response = await self.client.request(method=method, url=url, params=params, json=json)
59
+ if not response.is_success:
60
+ logger.error(
61
+ "Request failed with status code %s: %s", response.status_code, response.text
62
+ )
63
+ response.raise_for_status()
64
+ return response.json()
65
+
66
+ async def get_package(self, system: System, name: str) -> Incomplete:
67
+ """
68
+ GetPackage returns information about a package, including a list of its available versions, with the default version marked if known.
69
+
70
+ GET /v3/systems/{packageKey.system}/packages/{packageKey.name}
71
+ """ # noqa: E501
72
+ return await self._requests(
73
+ method="GET", url=f"/v3/systems/{system}/packages/{url_escape(name)}"
74
+ )
75
+
76
+ async def get_version(self, system: System, name: str, version: str) -> Incomplete:
77
+ """
78
+ GetVersion returns information about a specific package version, including its licenses and any security advisories known to affect it.
79
+
80
+ GET /v3/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}
81
+ """ # noqa: E501
82
+ return await self._requests(
83
+ method="GET",
84
+ url=f"/v3/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}",
85
+ )
86
+
87
+ async def get_requirements(self, system: System, name: str, version: str) -> Incomplete:
88
+ """
89
+ GetRequirements returns the requirements for a given version in a system-specific format. Requirements are currently available for Maven, npm, NuGet and RubyGems.
90
+
91
+ Requirements are the dependency constraints specified by the version.
92
+
93
+ GET /v3/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:requirements
94
+ """ # noqa: E501
95
+ return await self._requests(
96
+ method="GET",
97
+ url=f"/v3/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:requirements",
98
+ )
99
+
100
+ async def get_dependencies(self, system: System, name: str, version: str) -> Incomplete:
101
+ """
102
+ GetDependencies returns a resolved dependency graph for the given package version. Dependencies are currently available for Go, npm, Cargo, Maven and PyPI.
103
+
104
+ Dependencies are the resolution of the requirements (dependency constraints) specified by a version.
105
+
106
+ The dependency graph should be similar to one produced by installing the package version on a generic 64-bit Linux system, with no other dependencies present. The precise meaning of this varies from system to system.
107
+
108
+ GET /v3/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:dependencies
109
+ """ # noqa: E501
110
+ return await self._requests(
111
+ method="GET",
112
+ url=f"/v3/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:dependencies",
113
+ )
114
+
115
+ async def get_project(self, project_id: str) -> Incomplete:
116
+ """
117
+ GetProject returns information about projects hosted by GitHub, GitLab, or BitBucket, when known to us.
118
+
119
+ GET /v3/projects/{projectKey.id}
120
+ """ # noqa: E501
121
+ return await self._requests(method="GET", url=f"/v3/projects/{url_escape(project_id)}")
122
+
123
+ async def get_project_package_versions(self, project_id: str) -> Incomplete:
124
+ """
125
+ GetProjectPackageVersions returns known mappings between the requested project and package versions. At most 1500 package versions are returned. Mappings which were derived from attestations are served first.
126
+
127
+ GET /v3/projects/{projectKey.id}:packageversions
128
+ """ # noqa: E501
129
+ return await self._requests(
130
+ method="GET", url=f"/v3/projects/{url_escape(project_id)}:packageversions"
131
+ )
132
+
133
+ async def get_advisory(self, advisory_id: str) -> Incomplete:
134
+ """
135
+ GetAdvisory returns information about security advisories hosted by OSV.
136
+
137
+ GET /v3/advisories/{advisoryKey.id}
138
+ """
139
+ return await self._requests(method="GET", url=f"/v3/advisories/{url_escape(advisory_id)}")
140
+
141
+ async def query(
142
+ self,
143
+ hash_type: Optional[HashType] = None, # noqa: UP045
144
+ hash_value: Optional[str] = None, # noqa: UP045
145
+ system: Optional[System] = None, # noqa: UP045
146
+ name: Optional[str] = None, # noqa: UP045
147
+ version: Optional[str] = None, # noqa: UP045
148
+ ) -> Incomplete:
149
+ """
150
+ Query returns information about multiple package versions, which can be specified by name, content hash, or both. If a hash was specified in the request, it returns the artifacts that matched the hash.
151
+
152
+ Querying by content hash is currently supported for npm, Cargo, Maven, NuGet, PyPI and RubyGems. It is typical for hash queries to return many results; hashes are matched against multiple release artifacts (such as JAR files) that comprise package versions, and any given artifact may appear in several package versions.
153
+
154
+ GET /v3/query
155
+ """ # noqa: E501
156
+ params = {
157
+ "hash.type": hash_type.value if hash_type else None,
158
+ "hash.value": hash_value,
159
+ "versionKey.system": system.value if system else None,
160
+ "versionKey.name": name,
161
+ "versionKey.version": version,
162
+ }
163
+ params = {k: v for k, v in params.items() if v is not None} # Filter out None values
164
+ return await self._requests(method="GET", url="/v3/query", params=params) # type: ignore[arg-type,unused-ignore]
165
+
166
+
167
+ if __name__ == "__main__":
168
+ import asyncio
169
+
170
+ async def main() -> None:
171
+ client = DepsDevClientV3()
172
+ system = System.NPM
173
+ name = "@colors/colors"
174
+ version = "1.5.0"
175
+ project_id = "github.com/facebook/react"
176
+ advisory_id = "GHSA-2qrg-x229-3v8q"
177
+ print(await client.get_package(system, name))
178
+ print(await client.get_version(system, name, version))
179
+ print(await client.get_requirements(system, name, version))
180
+ print(await client.get_dependencies(system, name, version))
181
+ print(await client.get_project(project_id))
182
+ print(await client.get_project_package_versions(project_id))
183
+ print(await client.get_advisory(advisory_id))
184
+ print(
185
+ await client.query(
186
+ system=System.NPM,
187
+ name="react",
188
+ version="18.2.0",
189
+ )
190
+ )
191
+
192
+ asyncio.run(main())
depsdev/v3alpha.py ADDED
@@ -0,0 +1,307 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+ from typing import Optional
5
+ from typing import Union
6
+
7
+ from depsdev.v3 import DepsDevClientV3
8
+ from depsdev.v3 import HashType
9
+ from depsdev.v3 import Incomplete
10
+ from depsdev.v3 import System
11
+ from depsdev.v3 import url_escape
12
+
13
+ if TYPE_CHECKING:
14
+ from typing_extensions import Literal
15
+ from typing_extensions import TypedDict
16
+
17
+ class PurlDict(TypedDict):
18
+ system: System | SystemLiteral
19
+ name: str
20
+ version: str
21
+
22
+ SystemLiteral = Literal[
23
+ "GO",
24
+ "RUBYGEMS",
25
+ "NPM",
26
+ "CARGO",
27
+ "MAVEN",
28
+ "PYPI",
29
+ "NUGET",
30
+ ]
31
+
32
+ PUrlStr = str
33
+ PUrlWithVersionStr = str
34
+
35
+
36
+ class DepsDevClientV3Alpha(DepsDevClientV3):
37
+ async def get_package(self, system: System, name: str) -> Incomplete:
38
+ """
39
+ GetPackage returns information about a package, including a list of its available versions, with the default version marked if known.
40
+
41
+ GET /v3alpha/systems/{packageKey.system}/packages/{packageKey.name}
42
+ """ # noqa: E501
43
+ return await self._requests(
44
+ method="GET", url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}"
45
+ )
46
+
47
+ async def get_version(self, system: System, name: str, version: str) -> Incomplete:
48
+ """
49
+ GetVersion returns information about a specific package version, including its licenses and any security advisories known to affect it.
50
+
51
+ GET /v3alpha/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}
52
+ """ # noqa: E501
53
+ return await self._requests(
54
+ method="GET",
55
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}",
56
+ )
57
+
58
+ async def get_version_batch(
59
+ self,
60
+ requests: list[PurlDict],
61
+ page_token: Optional[str] = None, # noqa: UP045
62
+ ) -> Incomplete:
63
+ """
64
+ GetVersionBatch performs GetVersion requests for a batch of versions. Large result sets may be paginated.
65
+
66
+ POST /v3alpha/versionbatch
67
+ """ # noqa: E501
68
+ payload = {
69
+ "requests": [{"versionKey": x} for x in requests],
70
+ "pageToken": page_token,
71
+ }
72
+ return await self._requests(method="POST", url="/v3alpha/versionbatch", json=payload)
73
+
74
+ async def get_requirements(self, system: System, name: str, version: str) -> Incomplete:
75
+ """
76
+ GetRequirements returns the requirements for a given version in a system-specific format. Requirements are currently available for Maven, npm, NuGet, and RubyGems.
77
+
78
+ Requirements are the dependency constraints specified by the version.
79
+
80
+ GET /v3alpha/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:requirements
81
+ """ # noqa: E501
82
+ return await self._requests(
83
+ method="GET",
84
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:requirements",
85
+ )
86
+
87
+ async def get_dependencies(self, system: System, name: str, version: str) -> Incomplete:
88
+ """
89
+ GetDependencies returns a resolved dependency graph for the given package version. Dependencies are currently available for Go, npm, Cargo, Maven and PyPI.
90
+
91
+ Dependencies are the resolution of the requirements (dependency constraints) specified by a version.
92
+
93
+ The dependency graph should be similar to one produced by installing the package version on a generic 64-bit Linux system, with no other dependencies present. The precise meaning of this varies from system to system.
94
+
95
+ GET /v3alpha/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:dependencies
96
+ """ # noqa: E501
97
+ return await self._requests(
98
+ method="GET",
99
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:dependencies",
100
+ )
101
+
102
+ async def get_dependents(self, system: System, name: str, version: str) -> Incomplete:
103
+ """
104
+ GetDependents returns information about the number of distinct packages known to depend on the given package version. Dependent counts are currently available for Go, npm, Cargo, Maven and PyPI.
105
+
106
+ Dependent counts are derived from the dependency graphs computed by deps.dev, which means that only public dependents are counted. As such, dependent counts should be treated as indicative of relative popularity rather than precisely accurate.
107
+
108
+ GET /v3alpha/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:dependents
109
+ """ # noqa: E501
110
+ return await self._requests(
111
+ method="GET",
112
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:dependents",
113
+ )
114
+
115
+ async def get_capabilities(self, system: System, name: str, version: str) -> Incomplete:
116
+ """
117
+ GetCapabilityRequest returns counts for direct and indirect calls to Capslock capabilities for a given package version. Currently only available for Go.
118
+
119
+ GET /v3alpha/systems/{versionKey.system}/packages/{versionKey.name}/versions/{versionKey.version}:capabilities
120
+ """ # noqa: E501
121
+ return await self._requests(
122
+ method="GET",
123
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}/versions/{url_escape(version)}:capabilities",
124
+ )
125
+
126
+ async def get_project(self, project_id: str) -> Incomplete:
127
+ """
128
+ GetProject returns information about projects hosted by GitHub, GitLab, or BitBucket, when known to us.
129
+
130
+ GET /v3alpha/projects/{projectKey.id}
131
+ """ # noqa: E501
132
+ return await self._requests(method="GET", url=f"/v3alpha/projects/{url_escape(project_id)}")
133
+
134
+ async def get_project_batch(
135
+ self,
136
+ project_ids: list[str],
137
+ page_token: Optional[str] = None, # noqa: UP045
138
+ ) -> Incomplete:
139
+ """
140
+ GetProjectBatch performs GetProjectBatch requests for a batch of projects. Large result sets may be paginated.
141
+
142
+ POST /v3alpha/projectbatch
143
+ """ # noqa: E501
144
+ payload = {
145
+ "requests": [{"projectKey": {"id": x}} for x in project_ids],
146
+ "pageToken": page_token,
147
+ }
148
+ return await self._requests(method="POST", url="/v3alpha/projectbatch", json=payload)
149
+
150
+ async def get_project_package_versions(self, project_id: str) -> Incomplete:
151
+ """
152
+ GetProjectPackageVersions returns known mappings between the requested project and package versions. At most 1500 package versions are returned. Mappings which were derived from attestations are served first.
153
+
154
+ GET /v3alpha/projects/{projectKey.id}:packageversions
155
+ """ # noqa: E501
156
+ return await self._requests(
157
+ method="GET", url=f"/v3alpha/projects/{url_escape(project_id)}:packageversions"
158
+ )
159
+
160
+ async def get_advisory(self, advisory_id: str) -> Incomplete:
161
+ """
162
+ GetAdvisory returns information about security advisories hosted by OSV.
163
+
164
+ GET /v3alpha/advisories/{advisoryKey.id}
165
+ """
166
+ return await self._requests(
167
+ method="GET", url=f"/v3alpha/advisories/{url_escape(advisory_id)}"
168
+ )
169
+
170
+ async def get_similarly_named_packages(self, system: System, name: str) -> Incomplete:
171
+ """
172
+ GetSimilarlyNamedPackages returns packages with names that are similar to the requested package. This similarity relation is computed by deps.dev.
173
+
174
+ GET /v3alpha/systems/{packageKey.system}/packages/{packageKey.name}:similarlyNamedPackages
175
+ """ # noqa: E501
176
+ return await self._requests(
177
+ method="GET",
178
+ url=f"/v3alpha/systems/{system}/packages/{url_escape(name)}:similarlyNamedPackages",
179
+ )
180
+
181
+ async def query(
182
+ self,
183
+ hash_type: Optional[HashType] = None, # noqa: UP045
184
+ hash_value: Optional[str] = None, # noqa: UP045
185
+ system: Optional[System] = None, # noqa: UP045
186
+ name: Optional[str] = None, # noqa: UP045
187
+ version: Optional[str] = None, # noqa: UP045
188
+ ) -> Incomplete:
189
+ """
190
+ Query returns information about multiple package versions, which can be specified by name, content hash, or both. If a hash was specified in the request, it returns the artifacts that matched the hash.
191
+
192
+ Querying by content hash is currently supported for npm, Cargo, Maven, NuGet, PyPI and RubyGems. It is typical for hash queries to return many results; hashes are matched against multiple release artifacts (such as JAR files) that comprise package versions, and any given artifact may appear in several package versions.
193
+
194
+ GET /v3alpha/query
195
+ """ # noqa: E501
196
+ params = {
197
+ "hash.type": hash_type.value if hash_type else None,
198
+ "hash.value": hash_value,
199
+ "versionKey.system": system.value if system else None,
200
+ "versionKey.name": name,
201
+ "versionKey.version": version,
202
+ }
203
+ params = {k: v for k, v in params.items() if v is not None} # Filter out None values
204
+ return await self._requests(method="GET", url="/v3alpha/query", params=params) # type: ignore[arg-type,unused-ignore]
205
+
206
+ async def purl_lookup(self, purl: Union[PUrlStr, PUrlWithVersionStr]) -> Incomplete: # noqa: UP007
207
+ """
208
+ PurlLookup searches for a package or package version specified via purl, and returns the corresponding result from GetPackage or GetVersion as appropriate.
209
+
210
+ For a package lookup, the purl should be in the form pkg:type/namespace/name for a namespaced package name, or pkg:type/name for a non-namespaced package name.
211
+
212
+ For a package version lookup, the purl should be in the form pkg:type/namespace/name@version, or pkg:type/name@version.
213
+
214
+ Extra fields in the purl must be empty, otherwise the request will fail. In particular, there must be no subpath or qualifiers.
215
+
216
+ Supported values for type are cargo, gem, golang, maven, npm, nuget, and pypi. Further details on types, and how to form purls of each type, can be found in the purl spec.
217
+
218
+ Special characters in purls must be percent-encoded. This is described in detail by the purl spec.
219
+
220
+ GET /v3alpha/purl/{purl}
221
+ """ # noqa: E501
222
+ return await self._requests(method="GET", url=f"/v3alpha/purl/{url_escape(purl)}")
223
+
224
+ async def purl_lookup_batch(
225
+ self,
226
+ purls: list[PUrlWithVersionStr],
227
+ page_token: Optional[str] = None, # noqa: UP045
228
+ ) -> Incomplete:
229
+ """
230
+ PurlLookupBatch performs PurlLookup requests for a batch of purls. This endpoint only supports version lookups. Purls in requests must include a version field.
231
+
232
+ Supported purl forms are pkg:type/namespace/name@version for a namespaced package name, or pkg:type/name@version for a non-namespaced package name.
233
+
234
+ Extra fields in the purl must be empty, otherwise the request will fail. In particular, there must be no subpath or qualifiers.
235
+
236
+ Large result sets may be paginated.
237
+
238
+ POST /v3alpha/purlbatch
239
+ """ # noqa: E501
240
+ payload = {"requests": [{"purl": x} for x in purls], "pageToken": page_token}
241
+ return await self._requests(method="POST", url="/v3alpha/purlbatch", json=payload)
242
+
243
+ async def query_container_images(self, chain_id: str) -> Incomplete:
244
+ """
245
+ QueryContainerImages searches for container image repositories on DockerHub that match the requested OCI Chain ID. At most 1000 image repositories are returned.
246
+
247
+ An image repository is identifier (eg. 'tensorflow') that refers to a collection of images.
248
+
249
+ An OCI Chain ID is a hashed encoding of an ordered sequence of OCI layers. For further details see the OCI Chain ID spec.
250
+
251
+ GET /v3alpha/querycontainerimages/{chainId}
252
+ """ # noqa: E501
253
+ return await self._requests(
254
+ method="GET", url=f"/v3alpha/querycontainerimages/{url_escape(chain_id)}"
255
+ )
256
+
257
+
258
+ if __name__ == "__main__":
259
+ import asyncio
260
+
261
+ async def main() -> None:
262
+ client = DepsDevClientV3Alpha()
263
+ system = System.NPM
264
+ name = "@colors/colors"
265
+ version = "1.5.0"
266
+ project_id = "github.com/facebook/react"
267
+ advisory_id = "GHSA-2qrg-x229-3v8q"
268
+ print(await client.get_package(system, name))
269
+ print(await client.get_version(system, name, version))
270
+ print(await client.get_requirements(system, name, version))
271
+ print(await client.get_dependencies(system, name, version))
272
+ print(await client.get_project(project_id))
273
+ print(await client.get_project_package_versions(project_id))
274
+ print(await client.get_advisory(advisory_id))
275
+
276
+ print(
277
+ await client.query(
278
+ system=System.NPM,
279
+ name="react",
280
+ version="18.2.0",
281
+ )
282
+ )
283
+
284
+ print(
285
+ await client.get_version_batch(
286
+ [
287
+ {"system": "NPM", "name": "@colors/colors", "version": "1.5.0"},
288
+ {"system": "NUGET", "name": "castle.core", "version": "5.1.1"},
289
+ ]
290
+ )
291
+ )
292
+ print(await client.get_dependents(system, name, version))
293
+ # print(await client.get_capabilities(system, name, version))
294
+ print(
295
+ await client.get_project_batch(
296
+ ["github.com/facebook/react", "github.com/angular/angular"]
297
+ )
298
+ )
299
+
300
+ purl1 = "pkg:npm/@colors/colors"
301
+ purl2 = "pkg:npm/@colors/colors@1.5.0"
302
+ print(await client.get_similarly_named_packages(system, name))
303
+ print(await client.purl_lookup(purl1))
304
+ print(await client.purl_lookup_batch([purl2]))
305
+ # print(await client.query_container_images(""))
306
+
307
+ asyncio.run(main())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: depsdev
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: Python wrapper for https://deps.dev/ API
5
5
  Project-URL: Documentation, https://github.com/FlavioAmurrioCS/depsdev#readme
6
6
  Project-URL: Issues, https://github.com/FlavioAmurrioCS/depsdev/issues
@@ -19,16 +19,24 @@ Classifier: Programming Language :: Python :: 3.14
19
19
  Classifier: Programming Language :: Python :: Implementation :: CPython
20
20
  Classifier: Programming Language :: Python :: Implementation :: PyPy
21
21
  Requires-Python: >=3.9
22
+ Requires-Dist: httpx
23
+ Provides-Extra: cli
24
+ Requires-Dist: rich; extra == 'cli'
25
+ Requires-Dist: typer-slim; extra == 'cli'
22
26
  Provides-Extra: tests
23
27
  Requires-Dist: pytest; extra == 'tests'
28
+ Requires-Dist: rich; extra == 'tests'
24
29
  Requires-Dist: tomli; (python_version < '3.11') and extra == 'tests'
30
+ Requires-Dist: typer-slim; extra == 'tests'
25
31
  Provides-Extra: types
26
32
  Requires-Dist: mypy; extra == 'types'
27
33
  Requires-Dist: pyrefly; extra == 'types'
28
34
  Requires-Dist: pyright[nodejs]; extra == 'types'
29
35
  Requires-Dist: pytest; extra == 'types'
36
+ Requires-Dist: rich; extra == 'types'
30
37
  Requires-Dist: tomli; (python_version < '3.11') and extra == 'types'
31
38
  Requires-Dist: ty; extra == 'types'
39
+ Requires-Dist: typer-slim; extra == 'types'
32
40
  Requires-Dist: typing-extensions; extra == 'types'
33
41
  Description-Content-Type: text/markdown
34
42
 
@@ -42,13 +50,19 @@ Description-Content-Type: text/markdown
42
50
 
43
51
  ## Table of Contents
44
52
 
53
+ - [Overview](#overview)
45
54
  - [Installation](#installation)
46
55
  - [License](#license)
47
56
 
57
+ ## Overview
58
+
59
+ Thin Python wrapper (async-first) around the public [deps.dev REST API](https://deps.dev) plus an optional Typer-based CLI. Provides straightforward methods mapping closely to the documented endpoints; responses are returned as decoded JSON (dict / list). Alpha endpoints can be enabled via `DEPSDEV_V3_ALPHA=true` and may change without notice.
60
+
48
61
  ## Installation
49
62
 
50
- ```console
51
- pip install depsdev
63
+ ```bash
64
+ pip install depsdev # library only
65
+ pip install depsdev[cli] # library + CLI
52
66
  ```
53
67
 
54
68
  ## License
@@ -0,0 +1,11 @@
1
+ depsdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ depsdev/__main__.py,sha256=iLGic-dGQX0SdzL3KJOibUdG1J7nFSvighn9E2nP29w,4526
3
+ depsdev/_version.py,sha256=wO7XWlZte1hxA4mMvRc6zhNdGm74Nhhn2bfWRAxaKbI,511
4
+ depsdev/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ depsdev/v3.py,sha256=9MPK2h6QmxKnBz8KNF2GPTRlClOlM7xWO6TbtnRiQbE,7740
6
+ depsdev/v3alpha.py,sha256=KUl8Fq9mLExAfrU5T43vAc1dlRBbugN3H2Eg4Tv5XxE,13908
7
+ depsdev-0.0.2.dist-info/METADATA,sha256=nPf24oXHCDXIfkWGgoElJRiXS8RO7NoE14QByGS9-sw,2902
8
+ depsdev-0.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
+ depsdev-0.0.2.dist-info/entry_points.txt,sha256=yVCFtXda2xhj-7SmKEw7ynA_8QJrmKi9tORDw2uco9Q,50
10
+ depsdev-0.0.2.dist-info/licenses/LICENSE.txt,sha256=jpNC8_qYxlJENCgo7GKooe4rsIx-t_wIWl7ngr03F2k,1131
11
+ depsdev-0.0.2.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- depsdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- depsdev/__main__.py,sha256=IezDkTm-_ae5VyuQJRMmBjc-imTcqEX6picfoiLq0vE,290
3
- depsdev/_version.py,sha256=vgltXBYF55vNcC2regxjGN0_cbebmm8VgcDdQaDapWQ,511
4
- depsdev/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- depsdev-0.0.1.dist-info/METADATA,sha256=AIPgvmTTFPJrr1C2Y4nN_hxrf9CXAGzQgm_xhGO1Id8,2165
6
- depsdev-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- depsdev-0.0.1.dist-info/entry_points.txt,sha256=yVCFtXda2xhj-7SmKEw7ynA_8QJrmKi9tORDw2uco9Q,50
8
- depsdev-0.0.1.dist-info/licenses/LICENSE.txt,sha256=jpNC8_qYxlJENCgo7GKooe4rsIx-t_wIWl7ngr03F2k,1131
9
- depsdev-0.0.1.dist-info/RECORD,,