prozorro-cli 0.1.0__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.
@@ -0,0 +1,4 @@
1
+ """Command-line client for public Prozorro tender data."""
2
+
3
+ __version__ = "0.1.0"
4
+
@@ -0,0 +1,6 @@
1
+ from prozorro_cli.cli import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ raise SystemExit(main())
6
+
prozorro_cli/cli.py ADDED
@@ -0,0 +1,141 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ import webbrowser
7
+ from collections.abc import Sequence
8
+
9
+ from prozorro_cli.client import (
10
+ ProzorroError,
11
+ download_documents,
12
+ fetch_tender,
13
+ normal_guid,
14
+ public_api_link,
15
+ resolve_guid,
16
+ tender_link,
17
+ )
18
+
19
+
20
+ def configure_windows_streams() -> None:
21
+ for stream in (sys.stdout, sys.stderr):
22
+ reconfigure = getattr(stream, "reconfigure", None)
23
+ if reconfigure is not None:
24
+ reconfigure(encoding="utf-8")
25
+
26
+
27
+ def print_link(url: str, *, open_in_browser: bool) -> None:
28
+ print(url)
29
+ if open_in_browser and not webbrowser.open(url, new=2):
30
+ raise ProzorroError("Не вдалося відкрити посилання у браузері.")
31
+
32
+
33
+ def build_parser() -> argparse.ArgumentParser:
34
+ parser = argparse.ArgumentParser(
35
+ prog="prozorro-cli",
36
+ description="Отримання публічних даних про тендери Prozorro.",
37
+ )
38
+ subparsers = parser.add_subparsers(dest="command", required=True)
39
+
40
+ tender_parser = subparsers.add_parser(
41
+ "tender",
42
+ help="отримати посилання, GUID або повний JSON тендера",
43
+ )
44
+ tender_parser.add_argument(
45
+ "reference",
46
+ metavar="REFERENCE",
47
+ help="UA-ID, GUID, UUID або посилання на тендер Prozorro",
48
+ )
49
+
50
+ output_group = tender_parser.add_mutually_exclusive_group()
51
+ output_group.add_argument(
52
+ "--link",
53
+ action="store_true",
54
+ help="вивести посилання на повний JSON у Public API",
55
+ )
56
+ output_group.add_argument(
57
+ "--link-html",
58
+ "--linkhtml",
59
+ dest="link_html",
60
+ action="store_true",
61
+ help="вивести посилання на HTML-сторінку тендера",
62
+ )
63
+ output_group.add_argument(
64
+ "--guid",
65
+ action="store_true",
66
+ help="вивести внутрішній id Prozorro без дефісів",
67
+ )
68
+ output_group.add_argument(
69
+ "--guid-normal",
70
+ action="store_true",
71
+ help="вивести внутрішній id у стандартному форматі UUID",
72
+ )
73
+ tender_parser.add_argument(
74
+ "--open",
75
+ action="store_true",
76
+ help="відкрити посилання з --link або --link-html у браузері",
77
+ )
78
+
79
+ documents_parser = subparsers.add_parser(
80
+ "documents",
81
+ help="завантажити всі файли з data.documents тендера",
82
+ )
83
+ documents_parser.add_argument(
84
+ "reference",
85
+ metavar="REFERENCE",
86
+ help="UA-ID, GUID, UUID або посилання на тендер Prozorro",
87
+ )
88
+ documents_parser.add_argument(
89
+ "--output",
90
+ required=True,
91
+ metavar="DIRECTORY",
92
+ help="каталог для завантажених документів",
93
+ )
94
+ return parser
95
+
96
+
97
+ def main(argv: Sequence[str] | None = None) -> int:
98
+ configure_windows_streams()
99
+ parser = build_parser()
100
+ args = parser.parse_args(argv)
101
+
102
+ try:
103
+ if args.command == "tender":
104
+ if args.open and not (args.link or args.link_html):
105
+ parser.error("--open потребує --link або --link-html.")
106
+
107
+ if args.link:
108
+ print_link(
109
+ public_api_link(args.reference),
110
+ open_in_browser=args.open,
111
+ )
112
+ return 0
113
+
114
+ if args.link_html:
115
+ print_link(
116
+ tender_link(args.reference),
117
+ open_in_browser=args.open,
118
+ )
119
+ return 0
120
+
121
+ if args.guid or args.guid_normal:
122
+ guid = resolve_guid(args.reference)
123
+ print(normal_guid(guid) if args.guid_normal else guid)
124
+ return 0
125
+
126
+ payload = fetch_tender(args.reference)
127
+ json.dump(payload, sys.stdout, ensure_ascii=False, indent=2)
128
+ sys.stdout.write("\n")
129
+ return 0
130
+
131
+ if args.command == "documents":
132
+ downloaded = download_documents(args.reference, args.output)
133
+ for path in downloaded:
134
+ print(path)
135
+ print(f"Завантажено документів: {len(downloaded)}")
136
+ return 0
137
+ except ProzorroError as error:
138
+ parser.exit(1, f"Помилка: {error}\n")
139
+
140
+ parser.error("Невідома команда.")
141
+ return 2
prozorro_cli/client.py ADDED
@@ -0,0 +1,297 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ import shutil
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+ from urllib.error import HTTPError, URLError
10
+ from urllib.parse import quote, unquote, urlsplit
11
+ from urllib.request import Request, urlopen
12
+
13
+
14
+ SUMMARY_URL = "https://prozorro.gov.ua/api/tenders/{tender_id}/summary"
15
+ PUBLIC_API_URL = "https://public-api.prozorro.gov.ua/api/2.5/tenders/{guid}"
16
+ TENDER_PAGE_URL = "https://prozorro.gov.ua/tender/{tender_id}"
17
+
18
+ TENDER_ID_PATTERN = re.compile(r"^UA-\d{4}-\d{2}-\d{2}-\d{6}-[a-z]$")
19
+ GUID_PATTERN = re.compile(r"^[0-9a-fA-F]{32}$")
20
+ NORMAL_GUID_PATTERN = re.compile(
21
+ r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-"
22
+ r"[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
23
+ )
24
+ SUPPORTED_HOSTS = {
25
+ "prozorro.gov.ua",
26
+ "www.prozorro.gov.ua",
27
+ "public-api.prozorro.gov.ua",
28
+ }
29
+ INVALID_FILENAME_CHARS = re.compile(r'[<>:"/\\|?*\x00-\x1f]')
30
+ WINDOWS_RESERVED_FILENAMES = {
31
+ "CON",
32
+ "PRN",
33
+ "AUX",
34
+ "NUL",
35
+ *(f"COM{number}" for number in range(1, 10)),
36
+ *(f"LPT{number}" for number in range(1, 10)),
37
+ }
38
+
39
+
40
+ class ProzorroError(RuntimeError):
41
+ """A user-facing error returned by Prozorro or the network."""
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class TenderReference:
46
+ tender_id: str | None = None
47
+ guid: str | None = None
48
+
49
+
50
+ def validate_tender_id(tender_id: str) -> str:
51
+ if not TENDER_ID_PATTERN.fullmatch(tender_id):
52
+ raise ProzorroError(
53
+ "Некоректний номер тендера. Очікується формат "
54
+ "UA-YYYY-MM-DD-NNNNNN-x."
55
+ )
56
+ return tender_id
57
+
58
+
59
+ def compact_guid(guid: str) -> str:
60
+ if GUID_PATTERN.fullmatch(guid):
61
+ return guid.lower()
62
+ if NORMAL_GUID_PATTERN.fullmatch(guid):
63
+ return guid.replace("-", "").lower()
64
+ raise ProzorroError("Некоректний внутрішній id Prozorro.")
65
+
66
+
67
+ def parse_tender_reference(value: str) -> TenderReference:
68
+ candidate = value.strip()
69
+ if TENDER_ID_PATTERN.fullmatch(candidate):
70
+ return TenderReference(tender_id=candidate)
71
+ if GUID_PATTERN.fullmatch(candidate) or NORMAL_GUID_PATTERN.fullmatch(candidate):
72
+ return TenderReference(guid=compact_guid(candidate))
73
+
74
+ parsed = urlsplit(candidate)
75
+ if parsed.scheme not in {"http", "https"} or parsed.hostname not in SUPPORTED_HOSTS:
76
+ raise ProzorroError(
77
+ "Очікується UA-ID, GUID, UUID або посилання на тендер Prozorro."
78
+ )
79
+
80
+ parts = [unquote(part) for part in parsed.path.strip("/").split("/") if part]
81
+ if len(parts) == 2 and parts[0] == "tender":
82
+ return TenderReference(tender_id=validate_tender_id(parts[1]))
83
+ if len(parts) == 3 and parts[0] in {"uk", "en"} and parts[1] == "tender":
84
+ return TenderReference(tender_id=validate_tender_id(parts[2]))
85
+ if (
86
+ len(parts) == 4
87
+ and parts[0:2] == ["api", "tenders"]
88
+ and parts[3] == "summary"
89
+ ):
90
+ return TenderReference(tender_id=validate_tender_id(parts[2]))
91
+ if (
92
+ len(parts) == 4
93
+ and parts[0:3] == ["api", "2.5", "tenders"]
94
+ ):
95
+ return TenderReference(guid=compact_guid(parts[3]))
96
+
97
+ raise ProzorroError("Посилання не веде на підтримуваний тендер Prozorro.")
98
+
99
+
100
+ def tender_link(reference: str, *, timeout: float = 30.0) -> str:
101
+ tender_id = resolve_tender_id(reference, timeout=timeout)
102
+ return TENDER_PAGE_URL.format(tender_id=quote(tender_id, safe=""))
103
+
104
+
105
+ def public_api_link(reference: str, *, timeout: float = 30.0) -> str:
106
+ guid = resolve_guid(reference, timeout=timeout)
107
+ return PUBLIC_API_URL.format(guid=guid)
108
+
109
+
110
+ def fetch_json(url: str, *, timeout: float = 30.0) -> dict[str, Any]:
111
+ request = Request(
112
+ url,
113
+ headers={
114
+ "Accept": "application/json",
115
+ "Accept-Language": "uk",
116
+ "User-Agent": "prozorro-cli/0.1 (+https://prozorro.gov.ua)",
117
+ },
118
+ )
119
+
120
+ try:
121
+ with urlopen(request, timeout=timeout) as response:
122
+ payload = json.load(response)
123
+ except HTTPError as error:
124
+ if error.code == 404:
125
+ raise ProzorroError("Тендер не знайдено.") from error
126
+ raise ProzorroError(f"Prozorro повернув HTTP {error.code}.") from error
127
+ except URLError as error:
128
+ reason = getattr(error, "reason", error)
129
+ raise ProzorroError(f"Не вдалося підключитися до Prozorro: {reason}") from error
130
+ except (json.JSONDecodeError, UnicodeDecodeError) as error:
131
+ raise ProzorroError("Prozorro повернув некоректний JSON.") from error
132
+
133
+ if not isinstance(payload, dict):
134
+ raise ProzorroError("Prozorro повернув JSON неочікуваного формату.")
135
+ return payload
136
+
137
+
138
+ def resolve_guid(reference: str, *, timeout: float = 30.0) -> str:
139
+ parsed = parse_tender_reference(reference)
140
+ if parsed.guid is not None:
141
+ return parsed.guid
142
+
143
+ tender_id = parsed.tender_id
144
+ if tender_id is None:
145
+ raise ProzorroError("Не вдалося визначити номер тендера.")
146
+ url = SUMMARY_URL.format(tender_id=quote(tender_id, safe=""))
147
+ summary = fetch_json(url, timeout=timeout)
148
+ guid = summary.get("id")
149
+
150
+ if not isinstance(guid, str) or not GUID_PATTERN.fullmatch(guid):
151
+ raise ProzorroError("У відповіді Prozorro немає коректного внутрішнього id.")
152
+ return guid.lower()
153
+
154
+
155
+ def normal_guid(guid: str) -> str:
156
+ normalized = compact_guid(guid)
157
+ return (
158
+ f"{normalized[0:8]}-{normalized[8:12]}-{normalized[12:16]}-"
159
+ f"{normalized[16:20]}-{normalized[20:32]}"
160
+ )
161
+
162
+
163
+ def fetch_tender(reference: str, *, timeout: float = 30.0) -> dict[str, Any]:
164
+ guid = resolve_guid(reference, timeout=timeout)
165
+ url = PUBLIC_API_URL.format(guid=guid)
166
+ return fetch_json(url, timeout=timeout)
167
+
168
+
169
+ def safe_document_filename(value: str, *, fallback: str) -> str:
170
+ filename = INVALID_FILENAME_CHARS.sub("_", value).strip().rstrip(". ")
171
+ if not filename:
172
+ filename = fallback
173
+
174
+ stem = filename.split(".", 1)[0].upper()
175
+ if stem in WINDOWS_RESERVED_FILENAMES:
176
+ filename = f"_{filename}"
177
+ return filename
178
+
179
+
180
+ def available_path(directory: Path, filename: str) -> Path:
181
+ candidate = directory / filename
182
+ if not candidate.exists():
183
+ return candidate
184
+
185
+ suffix = candidate.suffix
186
+ stem = candidate.name[: -len(suffix)] if suffix else candidate.name
187
+ number = 2
188
+ while True:
189
+ candidate = directory / f"{stem} ({number}){suffix}"
190
+ if not candidate.exists():
191
+ return candidate
192
+ number += 1
193
+
194
+
195
+ def download_document(
196
+ url: str,
197
+ destination: Path,
198
+ *,
199
+ timeout: float = 30.0,
200
+ ) -> None:
201
+ parsed = urlsplit(url)
202
+ if parsed.scheme not in {"http", "https"} or not parsed.hostname:
203
+ raise ProzorroError("Документ містить некоректне посилання.")
204
+
205
+ request = Request(
206
+ url,
207
+ headers={"User-Agent": "prozorro-cli/0.1 (+https://prozorro.gov.ua)"},
208
+ )
209
+ try:
210
+ with urlopen(request, timeout=timeout) as response:
211
+ with destination.open("xb") as output:
212
+ shutil.copyfileobj(response, output)
213
+ except HTTPError as error:
214
+ destination.unlink(missing_ok=True)
215
+ raise ProzorroError(
216
+ f"Не вдалося завантажити документ: HTTP {error.code}."
217
+ ) from error
218
+ except URLError as error:
219
+ destination.unlink(missing_ok=True)
220
+ reason = getattr(error, "reason", error)
221
+ raise ProzorroError(
222
+ f"Не вдалося завантажити документ: {reason}"
223
+ ) from error
224
+ except OSError as error:
225
+ destination.unlink(missing_ok=True)
226
+ raise ProzorroError(
227
+ f"Не вдалося зберегти документ «{destination.name}»: {error}"
228
+ ) from error
229
+
230
+
231
+ def download_documents(
232
+ reference: str,
233
+ output: str | Path,
234
+ *,
235
+ timeout: float = 30.0,
236
+ ) -> list[Path]:
237
+ payload = fetch_tender(reference, timeout=timeout)
238
+ data = payload.get("data")
239
+ documents = data.get("documents") if isinstance(data, dict) else None
240
+ if not isinstance(documents, list):
241
+ raise ProzorroError("У відповіді Prozorro немає масиву data.documents.")
242
+
243
+ output_directory = Path(output).expanduser()
244
+ try:
245
+ output_directory.mkdir(parents=True, exist_ok=True)
246
+ except OSError as error:
247
+ raise ProzorroError(
248
+ f"Не вдалося створити каталог «{output_directory}»: {error}"
249
+ ) from error
250
+ if not output_directory.is_dir():
251
+ raise ProzorroError(f"Шлях «{output_directory}» не є каталогом.")
252
+
253
+ downloaded: list[Path] = []
254
+ for index, document in enumerate(documents, start=1):
255
+ if not isinstance(document, dict):
256
+ raise ProzorroError(
257
+ f"Документ #{index} у data.documents має некоректний формат."
258
+ )
259
+
260
+ url = document.get("url")
261
+ if not isinstance(url, str) or not url.strip():
262
+ raise ProzorroError(
263
+ f"Документ #{index} у data.documents не містить url."
264
+ )
265
+
266
+ document_id = document.get("id")
267
+ fallback = (
268
+ document_id
269
+ if isinstance(document_id, str) and document_id.strip()
270
+ else f"document-{index}"
271
+ )
272
+ title = document.get("title")
273
+ filename = safe_document_filename(
274
+ title if isinstance(title, str) else "",
275
+ fallback=fallback,
276
+ )
277
+ destination = available_path(output_directory, filename)
278
+ download_document(url, destination, timeout=timeout)
279
+ downloaded.append(destination)
280
+
281
+ return downloaded
282
+
283
+
284
+ def resolve_tender_id(reference: str, *, timeout: float = 30.0) -> str:
285
+ parsed = parse_tender_reference(reference)
286
+ if parsed.tender_id is not None:
287
+ return parsed.tender_id
288
+
289
+ guid = parsed.guid
290
+ if guid is None:
291
+ raise ProzorroError("Не вдалося визначити внутрішній id Prozorro.")
292
+ payload = fetch_json(PUBLIC_API_URL.format(guid=guid), timeout=timeout)
293
+ data = payload.get("data")
294
+ tender_id = data.get("tenderID") if isinstance(data, dict) else None
295
+ if not isinstance(tender_id, str):
296
+ raise ProzorroError("У відповіді Prozorro немає номера тендера.")
297
+ return validate_tender_id(tender_id)
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: prozorro-cli
3
+ Version: 0.1.0
4
+ Summary: Small command-line client for public Prozorro tender data
5
+ Author: prozorro-cli contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/radimbig2/prozorro-cli
8
+ Project-URL: Issues, https://github.com/radimbig2/prozorro-cli/issues
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Internet :: WWW/HTTP
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # prozorro-cli
24
+
25
+ Невелика CLI для отримання публічних даних про тендери Prozorro за UA-ID,
26
+ внутрішнім GUID, стандартним UUID або посиланням.
27
+
28
+ ## Встановлення
29
+
30
+ ```powershell
31
+ pip install prozorro-cli
32
+ prozorro-cli --help
33
+ ```
34
+
35
+ Для ізольованого глобального встановлення CLI також можна використати
36
+ `pipx install prozorro-cli`.
37
+
38
+ ## Команди
39
+
40
+ ```powershell
41
+ # Посилання на повний JSON у Public API
42
+ prozorro-cli tender UA-2026-06-15-003439-a --link
43
+
44
+ # Посилання на HTML-сторінку тендера
45
+ prozorro-cli tender UA-2026-06-15-003439-a --link-html
46
+
47
+ # Надрукувати й відкрити JSON Public API у браузері
48
+ prozorro-cli tender UA-2026-06-15-003439-a --link --open
49
+
50
+ # Надрукувати й відкрити HTML-сторінку у браузері
51
+ prozorro-cli tender UA-2026-06-15-003439-a --link-html --open
52
+
53
+ # Скорочений alias для --link-html
54
+ prozorro-cli tender UA-2026-06-15-003439-a --linkhtml --open
55
+
56
+ # Внутрішній id Prozorro
57
+ prozorro-cli tender UA-2026-06-15-003439-a --guid
58
+
59
+ # Той самий id у стандартному форматі UUID
60
+ prozorro-cli tender UA-2026-06-15-003439-a --guid-normal
61
+
62
+ # Повний JSON із public-api.prozorro.gov.ua
63
+ prozorro-cli tender UA-2026-06-15-003439-a
64
+
65
+ # Повний JSON за GUID без дефісів
66
+ prozorro-cli tender 5d2590ef8a1b455f8d09ceeae474b21f
67
+
68
+ # Повний JSON за стандартним UUID
69
+ prozorro-cli tender 5d2590ef-8a1b-455f-8d09-ceeae474b21f
70
+
71
+ # Повний JSON за посиланням на сторінку тендера
72
+ prozorro-cli tender https://prozorro.gov.ua/tender/UA-2026-06-15-003439-a
73
+
74
+ # Повний JSON за посиланням Public API
75
+ prozorro-cli tender https://public-api.prozorro.gov.ua/api/2.5/tenders/5d2590ef8a1b455f8d09ceeae474b21f
76
+
77
+ # Завантажити всі файли з data.documents за посиланням Public API
78
+ prozorro-cli documents https://public-api.prozorro.gov.ua/api/2.5/tenders/5d2590ef8a1b455f8d09ceeae474b21f --output /temp
79
+
80
+ # Те саме за UA-ID
81
+ prozorro-cli documents UA-2026-06-15-003439-a --output /temp
82
+ ```
83
+
84
+ Для UA-ID і посилання на сторінку CLI спочатку отримує внутрішній `id` через
85
+ публічний endpoint `https://prozorro.gov.ua/api/tenders/<UA-ID>/summary`.
86
+ Для GUID, UUID і посилання Public API цей крок пропускається. Повний JSON
87
+ завантажується з `https://public-api.prozorro.gov.ua/api/2.5/tenders/<id>`.
88
+
89
+ Команда `documents` створює каталог із `--output`, якщо його ще немає, і
90
+ завантажує туди всі файли з `data.documents`. Імена беруться з `title`;
91
+ однакові імена не перезаписуються, а отримують суфікси `(2)`, `(3)` тощо.
92
+
93
+ ## Розробка
94
+
95
+ ```powershell
96
+ $env:PYTHONPATH = "$PWD\src"
97
+ python -m unittest discover -s tests -v
98
+ python -m prozorro_cli tender UA-2026-06-15-003439-a --guid
99
+ ```
100
+
101
+ ## Реліз
102
+
103
+ 1. Оновіть `version` у `pyproject.toml` та `__version__` у
104
+ `src/prozorro_cli/__init__.py`.
105
+ 2. Створіть і опублікуйте GitHub Release з тегом тієї ж версії, наприклад
106
+ `v0.1.0`.
107
+ 3. GitHub Actions перевірить тести, збере wheel і sdist, додасть їх до Release
108
+ та опублікує пакет у PyPI.
109
+
110
+ Для публікації потрібен GitHub Actions secret `PYPI_API_TOKEN` з API-токеном
111
+ PyPI. Job публікації запускається в GitHub environment `pypi`.
@@ -0,0 +1,10 @@
1
+ prozorro_cli/__init__.py,sha256=f5nEXYxLx9K2LTCu7O7npVNkD1Zfqjxxp5cAD6Ms5ng,83
2
+ prozorro_cli/__main__.py,sha256=OqX5QqcJXR9KkCRi-aDOVAycnswOmMg2RXBioMVlXsg,93
3
+ prozorro_cli/cli.py,sha256=-oDmywxy0OME6ErnuaXly1ba9zqP5g-kXuyLGhxS2aQ,4534
4
+ prozorro_cli/client.py,sha256=9ryPqD9E9IClDCiTCdKn4JlsbSGUO6UFhTDa9SuEGzw,10651
5
+ prozorro_cli-0.1.0.dist-info/licenses/LICENSE,sha256=hGKdMD9xcC-tN4dm1tdMvQdjvxz6YMJo-H1sCeJukRo,1083
6
+ prozorro_cli-0.1.0.dist-info/METADATA,sha256=KsBwBtA_s2VowYVH5BgABXGzU-57ULB41TsTYcwvhpo,4678
7
+ prozorro_cli-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
8
+ prozorro_cli-0.1.0.dist-info/entry_points.txt,sha256=cXh2mNyxCc2b8lqzDallHiqaMGDdLEPxBatQo1faWk0,55
9
+ prozorro_cli-0.1.0.dist-info/top_level.txt,sha256=OJy-Q0hwUQTUCgd5LW3Fipk1zTIkW4mj_VuvD35pMWQ,13
10
+ prozorro_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ prozorro-cli = prozorro_cli.cli:main
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 prozorro-cli contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1 @@
1
+ prozorro_cli