vinted-api-kit 1.0.1__tar.gz → 1.1.0__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 (54) hide show
  1. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/PKG-INFO +3 -20
  2. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/README.md +2 -19
  3. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/pyproject.toml +4 -1
  4. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/__init__.py +3 -1
  5. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/api/catalog.py +20 -16
  6. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/api/items.py +8 -23
  7. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/client.py +3 -4
  8. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/exceptions.py +4 -0
  9. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/models/item.py +29 -7
  10. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/session.py +5 -2
  11. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/utils.py +6 -1
  12. vinted_api_kit-1.0.1/.editorconfig +0 -22
  13. vinted_api_kit-1.0.1/.github/workflows/ci.yaml +0 -35
  14. vinted_api_kit-1.0.1/.github/workflows/coverage.yaml +0 -31
  15. vinted_api_kit-1.0.1/.pre-commit-config.yaml +0 -27
  16. vinted_api_kit-1.0.1/CHANGELOG.md +0 -78
  17. vinted_api_kit-1.0.1/Makefile +0 -91
  18. vinted_api_kit-1.0.1/TECHNICAL_BACKLOG.md +0 -242
  19. vinted_api_kit-1.0.1/assets/logo.png +0 -0
  20. vinted_api_kit-1.0.1/examples/base_usage.py +0 -32
  21. vinted_api_kit-1.0.1/examples/raw_data.py +0 -23
  22. vinted_api_kit-1.0.1/examples/with_proxy.py +0 -29
  23. vinted_api_kit-1.0.1/test_library_request.py +0 -31
  24. vinted_api_kit-1.0.1/tests/__init__.py +0 -0
  25. vinted_api_kit-1.0.1/tests/api/__init__.py +0 -0
  26. vinted_api_kit-1.0.1/tests/api/test_catalog.py +0 -131
  27. vinted_api_kit-1.0.1/tests/api/test_items.py +0 -82
  28. vinted_api_kit-1.0.1/tests/conftest.py +0 -74
  29. vinted_api_kit-1.0.1/tests/models/__init__.py +0 -0
  30. vinted_api_kit-1.0.1/tests/models/test_catalog_item.py +0 -54
  31. vinted_api_kit-1.0.1/tests/models/test_config.py +0 -56
  32. vinted_api_kit-1.0.1/tests/models/test_detailed_item.py +0 -41
  33. vinted_api_kit-1.0.1/tests/storage/__init__.py +0 -0
  34. vinted_api_kit-1.0.1/tests/storage/test_json.py +0 -95
  35. vinted_api_kit-1.0.1/tests/storage/test_mozilla.py +0 -49
  36. vinted_api_kit-1.0.1/tests/storage/test_pickle.py +0 -59
  37. vinted_api_kit-1.0.1/tests/test_auth.py +0 -62
  38. vinted_api_kit-1.0.1/tests/test_client.py +0 -53
  39. vinted_api_kit-1.0.1/tests/test_session.py +0 -272
  40. vinted_api_kit-1.0.1/tests/test_utils.py +0 -33
  41. vinted_api_kit-1.0.1/tox.ini +0 -11
  42. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/.gitignore +0 -0
  43. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/LICENSE +0 -0
  44. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/api/__init__.py +0 -0
  45. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/api/base.py +0 -0
  46. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/auth.py +0 -0
  47. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/constants.py +0 -0
  48. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/models/__init__.py +0 -0
  49. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/models/config.py +0 -0
  50. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/storage/__init__.py +0 -0
  51. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/storage/base.py +0 -0
  52. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/storage/json.py +0 -0
  53. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/storage/mozilla.py +0 -0
  54. {vinted_api_kit-1.0.1 → vinted_api_kit-1.1.0}/vinted/storage/pickle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vinted-api-kit
3
- Version: 1.0.1
3
+ Version: 1.1.0
4
4
  Summary: Lightweight asynchronous Python client library for accessing Vinted API and scraping item data.
5
5
  Project-URL: Homepage, https://github.com/vlymar1/vinted-api-kit
6
6
  Project-URL: Documentation, https://github.com/vlymar1/vinted-api-kit
@@ -50,7 +50,6 @@ Description-Content-Type: text/markdown
50
50
  - 🚀 **Asynchronous** - Built with asyncio for high performance
51
51
  - 🌍 **Auto-locale Detection** - Automatically detects locale from URL
52
52
  - 🔍 **Item Search** - Search catalog with filters, sorting and pagination
53
- - 📦 **Item Details** - Get complete item information with rich metadata
54
53
  - 🍪 **Cookie Persistence** - Automatic session management with multiple storage formats
55
54
  - 🔐 **Proxy Support** - Simple string-based proxy configuration
56
55
  - 📊 **Type Hints** - Full typing support with Literal types for better IDE experience
@@ -165,22 +164,7 @@ raw_items = await client.search_items(
165
164
 
166
165
  ### Item Details
167
166
 
168
- > Fetch detailed information about a specific item:
169
- ```python
170
- item = await client.item_details(
171
- url="https://www.vinted.com/items/1234567890"
172
- )
173
-
174
- print(f"Title: {item.title}")
175
- print(f"Brand: {item.brand_title}")
176
- print(f"Size: {item.size_title}")
177
- print(f"Price: {item.price} {item.currency}")
178
- print(f"Total: {item.total_item_price}")
179
- print(f"Description: {item.description}")
180
-
181
- # Or get raw JSON
182
- raw_item = await client.item_details(url, raw_data=True)
183
- ```
167
+ > ⚠️ **Deprecated since 1.1.0.** Vinted removed the item details API, so `item_details()` raises `VintedDeprecatedError`.
184
168
 
185
169
  ### Parameters
186
170
 
@@ -352,8 +336,7 @@ vinted-api-kit/
352
336
  │ ├── constants.py # Constants and type definitions
353
337
  │ ├── exceptions.py # Custom exceptions
354
338
  │ └── utils.py # Utility functions
355
- ├── tests/ # Test suite
356
- └── examples/ # Usage examples
339
+ └── tests/ # Test suite
357
340
  ```
358
341
 
359
342
  ### Testing
@@ -18,7 +18,6 @@
18
18
  - 🚀 **Asynchronous** - Built with asyncio for high performance
19
19
  - 🌍 **Auto-locale Detection** - Automatically detects locale from URL
20
20
  - 🔍 **Item Search** - Search catalog with filters, sorting and pagination
21
- - 📦 **Item Details** - Get complete item information with rich metadata
22
21
  - 🍪 **Cookie Persistence** - Automatic session management with multiple storage formats
23
22
  - 🔐 **Proxy Support** - Simple string-based proxy configuration
24
23
  - 📊 **Type Hints** - Full typing support with Literal types for better IDE experience
@@ -133,22 +132,7 @@ raw_items = await client.search_items(
133
132
 
134
133
  ### Item Details
135
134
 
136
- > Fetch detailed information about a specific item:
137
- ```python
138
- item = await client.item_details(
139
- url="https://www.vinted.com/items/1234567890"
140
- )
141
-
142
- print(f"Title: {item.title}")
143
- print(f"Brand: {item.brand_title}")
144
- print(f"Size: {item.size_title}")
145
- print(f"Price: {item.price} {item.currency}")
146
- print(f"Total: {item.total_item_price}")
147
- print(f"Description: {item.description}")
148
-
149
- # Or get raw JSON
150
- raw_item = await client.item_details(url, raw_data=True)
151
- ```
135
+ > ⚠️ **Deprecated since 1.1.0.** Vinted removed the item details API, so `item_details()` raises `VintedDeprecatedError`.
152
136
 
153
137
  ### Parameters
154
138
 
@@ -320,8 +304,7 @@ vinted-api-kit/
320
304
  │ ├── constants.py # Constants and type definitions
321
305
  │ ├── exceptions.py # Custom exceptions
322
306
  │ └── utils.py # Utility functions
323
- ├── tests/ # Test suite
324
- └── examples/ # Usage examples
307
+ └── tests/ # Test suite
325
308
  ```
326
309
 
327
310
  ### Testing
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vinted-api-kit"
7
- version = "1.0.1"
7
+ version = "1.1.0"
8
8
  description = "Lightweight asynchronous Python client library for accessing Vinted API and scraping item data."
9
9
  authors = [
10
10
  {name = "Lymar Volodymyr",email = "volodymyr.lymar1@gmail.com"},
@@ -71,6 +71,9 @@ all = ["format", "lint", "type-check", "test-cov"]
71
71
  [tool.hatch.build.targets.wheel]
72
72
  packages = ["vinted"]
73
73
 
74
+ [tool.hatch.build.targets.sdist]
75
+ include = ["vinted", "README.md", "LICENSE"]
76
+
74
77
  [tool.ruff]
75
78
  exclude = [
76
79
  ".git",
@@ -4,6 +4,7 @@ from vinted.exceptions import (
4
4
  VintedAPIError,
5
5
  VintedAuthError,
6
6
  VintedConfigError,
7
+ VintedDeprecatedError,
7
8
  VintedError,
8
9
  VintedNetworkError,
9
10
  VintedRateLimitError,
@@ -11,7 +12,7 @@ from vinted.exceptions import (
11
12
  )
12
13
  from vinted.models.item import CatalogItem, DetailedItem
13
14
 
14
- __version__ = "1.0.1"
15
+ __version__ = "1.1.0"
15
16
 
16
17
  __all__ = [
17
18
  "VintedClient",
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "VintedNetworkError",
25
26
  "VintedConfigError",
26
27
  "VintedValidationError",
28
+ "VintedDeprecatedError",
27
29
  "SortOrder",
28
30
  "StorageFormat",
29
31
  ]
@@ -8,7 +8,7 @@ and returns either raw JSON items or parsed `CatalogItem` instances.
8
8
  import logging
9
9
  import time
10
10
  from typing import Any, Union
11
- from urllib.parse import parse_qsl, urlparse
11
+ from urllib.parse import parse_qsl, urljoin, urlparse
12
12
 
13
13
  from vinted.exceptions import VintedValidationError
14
14
 
@@ -50,7 +50,7 @@ class CatalogAPI(BaseAPI):
50
50
  """
51
51
  self._validate_catalog_url(url)
52
52
  self.session.configure_from_url(url)
53
- api_url = f"{self.base_url}/api/v2/catalog/items"
53
+ api_url = f"{self.base_url}/web/gateway/svc-catalogue/items"
54
54
 
55
55
  params = self._build_params(url, per_page, page)
56
56
  params["time"] = timestamp or int(time.time())
@@ -69,7 +69,11 @@ class CatalogAPI(BaseAPI):
69
69
  if raw_data:
70
70
  return items
71
71
 
72
- return [CatalogItem(raw_data=item) for item in items]
72
+ catalog_items = [CatalogItem(raw_data=item) for item in items]
73
+ for catalog_item in catalog_items:
74
+ catalog_item.url = urljoin(f"{self.base_url}/", catalog_item.url)
75
+
76
+ return catalog_items
73
77
 
74
78
  def _build_params(self, url: str, per_page: int, page: int) -> dict:
75
79
  """Build API query params from a public catalog URL.
@@ -83,17 +87,19 @@ class CatalogAPI(BaseAPI):
83
87
  catalog_id = self._extract_catalog_id(parsed.path)
84
88
  catalog_ids_query = self._join_values(query_params, "catalog[]")
85
89
 
90
+ status_ids = self._extract_values(query_params, "status_ids[]") + self._extract_values(
91
+ query_params, "status[]"
92
+ )
93
+
86
94
  params = {
87
95
  "search_text": "+".join(self._extract_values(query_params, "search_text")),
88
- "catalog_ids": str(catalog_id) if catalog_id else catalog_ids_query,
89
- "color_ids": self._join_values(query_params, "color_ids[]"),
90
- "brand_ids": self._join_values(query_params, "brand_ids[]"),
91
- "size_ids": self._join_values(query_params, "size_ids[]"),
92
- "material_ids": self._join_values(query_params, "material_ids[]"),
93
- "status_ids": self._join_values(query_params, "status[]"),
94
- "country_ids": self._join_values(query_params, "country_ids[]"),
95
- "city_ids": self._join_values(query_params, "city_ids[]"),
96
- "is_for_swap": ",".join("1" for _ in self._extract_values(query_params, "disposal[]")),
96
+ "attribute_ids[catalog]": str(catalog_id) if catalog_id else catalog_ids_query,
97
+ "attribute_ids[color]": self._join_values(query_params, "color_ids[]"),
98
+ "attribute_ids[brand]": self._join_values(query_params, "brand_ids[]"),
99
+ "attribute_ids[size]": self._join_values(query_params, "size_ids[]"),
100
+ "attribute_ids[material]": self._join_values(query_params, "material_ids[]"),
101
+ "attribute_ids[status]": ",".join(status_ids),
102
+ "attribute_ids[patterns]": self._join_values(query_params, "patterns_ids[]"),
97
103
  "currency": self._join_values(query_params, "currency"),
98
104
  "price_to": self._join_values(query_params, "price_to"),
99
105
  "price_from": self._join_values(query_params, "price_from"),
@@ -113,10 +119,8 @@ class CatalogAPI(BaseAPI):
113
119
  raise VintedValidationError("Invalid catalog URL: expected an absolute HTTP(S) URL")
114
120
 
115
121
  path = parsed.path.rstrip("/")
116
- if path and not (path.startswith("/catalog") or path == "/api/v2/catalog/items"):
117
- raise VintedValidationError(
118
- "Invalid catalog URL: expected path '/catalog' or '/api/v2/catalog/items'"
119
- )
122
+ if path and not path.startswith("/catalog"):
123
+ raise VintedValidationError("Invalid catalog URL: expected path '/catalog'")
120
124
 
121
125
  @staticmethod
122
126
  def _extract_catalog_id(path: str) -> int | None:
@@ -6,10 +6,10 @@ URL and returns either a parsed `DetailedItem` or raw JSON.
6
6
  """
7
7
 
8
8
  import logging
9
- from typing import Any, Union
9
+ from typing import Union
10
10
  from urllib.parse import urlparse
11
11
 
12
- from vinted.exceptions import VintedValidationError
12
+ from vinted.exceptions import VintedDeprecatedError, VintedValidationError
13
13
 
14
14
  from ..models import DetailedItem
15
15
  from .base import BaseAPI
@@ -29,33 +29,18 @@ class ItemsAPI(BaseAPI):
29
29
  url: str,
30
30
  raw_data: bool = False,
31
31
  ) -> Union[DetailedItem, dict]:
32
- """Fetch item details.
32
+ """Deprecated: always raises `VintedDeprecatedError`.
33
+
34
+ Vinted removed the item details API endpoint.
33
35
 
34
36
  Args:
35
37
  url: Public Vinted item URL.
36
38
  raw_data: If True, return raw JSON dictionary instead of
37
39
  a `DetailedItem` instance.
38
-
39
- Returns:
40
- `DetailedItem` or raw dict depending on `raw_data`.
41
40
  """
42
- self.session.configure_from_url(url)
43
-
44
- product_id = self._extract_product_id(url)
45
- api_url = f"{self.base_url}/api/v2/items/{product_id}/details"
46
-
47
- logger.debug("Fetching item details: %s", api_url)
48
-
49
- response = await self.session.request(api_url)
50
- data = response.json()
51
- item_data: dict[Any, Any] = data.get("item", {})
52
-
53
- logger.debug("Item details fetched successfully")
54
-
55
- if raw_data:
56
- return item_data
57
-
58
- return DetailedItem(raw_data=item_data)
41
+ raise VintedDeprecatedError(
42
+ "item_details() no longer works: Vinted removed the item details API"
43
+ )
59
44
 
60
45
  @staticmethod
61
46
  def _extract_product_id(url: str) -> str:
@@ -163,14 +163,13 @@ class VintedClient:
163
163
  url: str,
164
164
  raw_data: bool = False,
165
165
  ) -> Union[DetailedItem, dict]:
166
- """Fetch item details by URL.
166
+ """Deprecated: always raises `VintedDeprecatedError`.
167
+
168
+ Vinted removed the item details API endpoint.
167
169
 
168
170
  Args:
169
171
  url: Item page URL or API endpoint.
170
172
  raw_data: When True returns raw dict instead of `DetailedItem`.
171
-
172
- Returns:
173
- `DetailedItem` or raw dict when `raw_data` is True.
174
173
  """
175
174
  return await self._items.get_details(url=url, raw_data=raw_data)
176
175
 
@@ -59,3 +59,7 @@ class VintedConfigError(VintedError):
59
59
 
60
60
  class VintedValidationError(VintedError):
61
61
  """Raised when input validation fails."""
62
+
63
+
64
+ class VintedDeprecatedError(VintedError):
65
+ """Raised when a deprecated feature no longer works with the Vinted API."""
@@ -8,6 +8,8 @@ from dataclasses import dataclass, field
8
8
  from datetime import datetime, timezone
9
9
  from typing import Any
10
10
 
11
+ from ..exceptions import VintedDeprecatedError
12
+
11
13
 
12
14
  @dataclass
13
15
  class CatalogItem:
@@ -15,7 +17,12 @@ class CatalogItem:
15
17
 
16
18
  The class stores the original `raw_data` (hidden from the repr)
17
19
  and extracts commonly-used fields like `id`, `title`, `price` and
18
- `photo` for convenience.
20
+ `photo` for convenience. Brand, size and condition come from
21
+ `item_box` in the language of the Vinted domain.
22
+
23
+ `created_at_ts` and `raw_timestamp` are deprecated: the catalog API
24
+ no longer returns the photo timestamp, so they always hold epoch
25
+ and 0. They will be removed in the next major release.
19
26
  """
20
27
 
21
28
  raw_data: dict[str, Any] = field(repr=False)
@@ -23,8 +30,10 @@ class CatalogItem:
23
30
  title: str = field(init=False)
24
31
  brand_title: str = field(init=False)
25
32
  size_title: str = field(init=False)
33
+ condition: str = field(init=False)
26
34
  currency: str = field(init=False)
27
35
  price: float = field(init=False)
36
+ total_item_price: float = field(init=False)
28
37
  photo: str = field(init=False)
29
38
  url: str = field(init=False)
30
39
  created_at_ts: datetime = field(init=False)
@@ -33,12 +42,19 @@ class CatalogItem:
33
42
  def __post_init__(self):
34
43
  self.id = self.raw_data.get("id", 0)
35
44
  self.title = self.raw_data.get("title", "")
36
- self.brand_title = self.raw_data.get("brand_title", "")
37
- self.size_title = self.raw_data.get("size_title", "")
45
+
46
+ item_box = self.raw_data.get("item_box") or {}
47
+ self.brand_title = item_box.get("first_line", "")
48
+ # second_line is "<size> · <condition>", the size part is optional
49
+ *sizes, self.condition = item_box.get("second_line", "").split(" · ")
50
+ self.size_title = sizes[0] if sizes else ""
38
51
 
39
52
  price = self.raw_data.get("price") or {}
40
53
  self.currency = price.get("currency_code", "")
41
- self.price = price.get("amount", 0.0)
54
+ self.price = float(price.get("amount") or 0.0)
55
+
56
+ total_item_price = self.raw_data.get("total_item_price") or {}
57
+ self.total_item_price = float(total_item_price.get("amount") or 0.0)
42
58
 
43
59
  photo = self.raw_data.get("photo") or {}
44
60
  self.photo = photo.get("url", "")
@@ -69,13 +85,19 @@ class CatalogItem:
69
85
  return hash(self.id)
70
86
 
71
87
  def is_new_item(self, minutes: int = 1) -> bool:
72
- """Return True when the item was created within `minutes`.
88
+ """Deprecated: always raises `VintedDeprecatedError`.
89
+
90
+ The check compared `created_at_ts` with the current time, but the
91
+ catalog API no longer returns the photo timestamp. The method will
92
+ be removed in the next major release.
73
93
 
74
94
  Args:
75
95
  minutes: Age threshold in minutes (default: 1).
76
96
  """
77
- delta = datetime.now(timezone.utc) - self.created_at_ts
78
- return delta.total_seconds() < minutes * 60
97
+ raise VintedDeprecatedError(
98
+ "CatalogItem.is_new_item() no longer works: the Vinted catalog API "
99
+ "does not return item timestamps anymore"
100
+ )
79
101
 
80
102
 
81
103
  @dataclass
@@ -28,7 +28,7 @@ from .constants import (
28
28
  HTTP_STATUS_UNAUTHORIZED,
29
29
  )
30
30
  from .storage import CookieStorage
31
- from .utils import format_proxy_for_log, get_accept_language
31
+ from .utils import format_proxy_for_log, get_accept_language, get_locale_code
32
32
 
33
33
  logger = logging.getLogger(__name__)
34
34
 
@@ -93,7 +93,10 @@ class HttpSession:
93
93
  if host.startswith("vinted."):
94
94
  self.locale = host[len("vinted.") :]
95
95
  accept_language = get_accept_language(self.locale)
96
- self.session.headers.update({"Accept-Language": accept_language})
96
+ # `locale` selects the marketplace whose items the catalog returns
97
+ self.session.headers.update(
98
+ {"Accept-Language": accept_language, "locale": get_locale_code(self.locale)}
99
+ )
97
100
 
98
101
  self.session.headers.update({"Referer": self.base_url})
99
102
  logger.debug("Configured: base_url=%s, locale=%s", self.base_url, self.locale)
@@ -28,12 +28,17 @@ def format_proxy_for_log(proxy: str | None) -> str:
28
28
  return proxy
29
29
 
30
30
 
31
+ def get_locale_code(locale: str) -> str:
32
+ """Return the full locale code for `locale` (e.g. "sk" -> "sk-SK")."""
33
+ return LOCALE_TO_ACCEPT_LANGUAGE.get(locale, "en-US")
34
+
35
+
31
36
  def get_accept_language(locale: str) -> str:
32
37
  """Return an Accept-Language header value for `locale`.
33
38
 
34
39
  The returned value contains the full locale code and a fallback
35
40
  language prefix with a lower q-value.
36
41
  """
37
- locale_code = LOCALE_TO_ACCEPT_LANGUAGE.get(locale, "en-US")
42
+ locale_code = get_locale_code(locale)
38
43
  lang_prefix = locale_code.split("-")[0]
39
44
  return "%s,%s;q=0.9" % (locale_code, lang_prefix)
@@ -1,22 +0,0 @@
1
- root = true
2
-
3
- [**]
4
- charset = utf-8
5
- end_of_line = lf
6
- indent_size = 4
7
- indent_style = space
8
- insert_final_newline = true
9
- trim_trailing_whitespace = true
10
- max_line_length = 99
11
-
12
- [**.{yml,yaml,json,conf}]
13
- indent_size = 2
14
-
15
- [**.{md,txt,rst}]
16
- trim_trailing_whitespace = false
17
-
18
- [**.rst]
19
- indent_size = 2
20
-
21
- [Makefile]
22
- indent_style = tab
@@ -1,35 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- pull_request:
6
-
7
- jobs:
8
- lint-and-test:
9
- runs-on: ubuntu-latest
10
- strategy:
11
- matrix:
12
- python-version: ["3.10", "3.11", "3.12", "3.13"]
13
- name: Lint, Type Check & Test (Python ${{ matrix.python-version }})
14
- steps:
15
- - name: Checkout code
16
- uses: actions/checkout@v4
17
-
18
- - name: Set up Python
19
- uses: actions/setup-python@v5
20
- with:
21
- python-version: ${{ matrix.python-version }}
22
-
23
- - name: Install hatch and create env
24
- run: |
25
- python -m pip install --upgrade pip
26
- pip install hatch
27
-
28
- - name: Run linting
29
- run: hatch run lint
30
-
31
- - name: Run type check
32
- run: hatch run type-check
33
-
34
- - name: Run tests (no coverage)
35
- run: hatch run test
@@ -1,31 +0,0 @@
1
- name: Coverage
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
-
8
- jobs:
9
- coverage:
10
- runs-on: ubuntu-latest
11
- steps:
12
- - name: Checkout code
13
- uses: actions/checkout@v4
14
-
15
- - name: Set up Python
16
- uses: actions/setup-python@v5
17
- with:
18
- python-version: "3.12"
19
-
20
- - name: Install dependencies
21
- run: |
22
- python -m pip install --upgrade pip
23
- pip install hatch
24
-
25
- - name: Run tests with coverage
26
- run: hatch run pytest --cov=vinted --cov-branch --cov-report=xml
27
-
28
- - name: Upload results to Codecov
29
- uses: codecov/codecov-action@v5
30
- with:
31
- token: ${{ secrets.CODECOV_TOKEN }}
@@ -1,27 +0,0 @@
1
- repos:
2
- - repo: https://github.com/pre-commit/pre-commit-hooks
3
- rev: v5.0.0
4
- hooks:
5
- - id: trailing-whitespace
6
- - id: end-of-file-fixer
7
- - id: check-yaml
8
- - id: check-toml
9
- - id: check-case-conflict
10
- - id: detect-private-key
11
- - id: check-added-large-files
12
- args: [--maxkb=500]
13
-
14
- - repo: https://github.com/astral-sh/ruff-pre-commit
15
- rev: v0.12.5
16
- hooks:
17
- - id: ruff
18
- args:
19
- - --fix
20
- - id: ruff-format
21
- types: [python]
22
-
23
- - repo: https://github.com/pre-commit/mirrors-mypy
24
- rev: v1.13.0
25
- hooks:
26
- - id: mypy
27
- additional_dependencies: [curl-cffi]
@@ -1,78 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
-
12
-
13
- ### Changed
14
-
15
-
16
- ### Fixed
17
-
18
-
19
- ## [1.0.1] - 2026-06-06
20
-
21
- ### Fixed
22
-
23
- - Locale detection now correctly handles multi-part Vinted domains such as `vinted.co.uk` and sets the expected `Accept-Language` header
24
- - Cookie refresh no longer deletes persisted session cookies before a successful refresh and save completes
25
- - Runtime exceptions now match the documented public contract for configuration, validation, rate-limit, authentication, and cookie save failures
26
-
27
-
28
- ## [1.0.0] - 2026-01-05
29
-
30
- ### Added
31
- - Multiple cookie storage backends: `json`, `mozilla`, and `pickle`
32
- - Dataclass-based models (`CatalogItem`, `DetailedItem`) for performance and clarity
33
- - Custom exception hierarchy to surface network, auth, and validation errors distinctly
34
- - Automatic locale detection from target Vinted URLs
35
- - `SortOrder` and `StorageFormat` type literals for improved typing
36
-
37
- ### Changed
38
- - Refactored architecture: separated `api/`, `storage/`, and `models/` layers for better maintainability
39
- - Default cookie storage format changed to `json` for security hardening
40
- - SSL verification enabled by default for all HTTP requests
41
- - Proxy configuration simplified to a single string parameter (`proxy="user:pass@host:port"`)
42
- - Cookie persistence now uses strategy pattern
43
-
44
- ### Fixed
45
- - JWT token expiration parsing (base64url padding handling)
46
- - Retry/logging behavior for authentication failures
47
- - Cookie persistence reliability
48
- - Proxy handling edge cases
49
- - Token expiration detection accuracy
50
-
51
- ## [0.1.0.post1] - 2025-08-07
52
-
53
- ### Fixed
54
- - Logo display compatibility for PyPI
55
- - Added project badges to README.md for better presentation
56
- - Corrected CHANGELOG formatting and metadata
57
-
58
- ## [0.1.0] - 2025-08-07
59
-
60
- ### Added
61
- - Asynchronous HTTP client for Vinted API with cookie management
62
- - `VintedApi.search_items()` method for item searching with filters
63
- - `VintedApi.item_details()` method for detailed item information
64
- - Support for multiple Vinted domains (fr, de, sk, pl, it, etc.)
65
- - Proxy support for web scraping
66
- - Automatic authentication and session handling
67
- - Cookie persistence between requests
68
- - JWT token expiration detection and refresh
69
- - Comprehensive error handling with retry logic
70
- - Full typing support and async/await patterns
71
- - CI/CD pipeline with GitHub Actions
72
- - 80%+ test coverage
73
-
74
- [Unreleased]: https://github.com/vlymar1/vinted-api-kit/compare/v1.0.1...HEAD
75
- [1.0.1]: https://github.com/vlymar1/vinted-api-kit/compare/v1.0.0...v1.0.1
76
- [1.0.0]: https://github.com/vlymar1/vinted-api-kit/compare/v0.1.0...v1.0.0
77
- [0.1.0.post1]: https://github.com/vlymar1/vinted-api-kit/compare/v0.1.0...v0.1.0.post1
78
- [0.1.0]: https://github.com/vlymar1/vinted-api-kit/releases/tag/v0.1.0