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 +123 -7
- depsdev/_version.py +2 -2
- depsdev/v3.py +192 -0
- depsdev/v3alpha.py +307 -0
- {depsdev-0.0.1.dist-info → depsdev-0.0.2.dist-info}/METADATA +17 -3
- depsdev-0.0.2.dist-info/RECORD +11 -0
- depsdev-0.0.1.dist-info/RECORD +0 -9
- {depsdev-0.0.1.dist-info → depsdev-0.0.2.dist-info}/WHEEL +0 -0
- {depsdev-0.0.1.dist-info → depsdev-0.0.2.dist-info}/entry_points.txt +0 -0
- {depsdev-0.0.1.dist-info → depsdev-0.0.2.dist-info}/licenses/LICENSE.txt +0 -0
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
|
-
|
5
|
-
import
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
from collections.abc import Callable
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
130
|
+
main()
|
depsdev/_version.py
CHANGED
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.
|
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
|
-
```
|
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,,
|
depsdev-0.0.1.dist-info/RECORD
DELETED
@@ -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,,
|
File without changes
|
File without changes
|
File without changes
|