walla-cli 0.1.8__tar.gz → 0.1.10__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.
- {walla_cli-0.1.8 → walla_cli-0.1.10}/PKG-INFO +14 -5
- {walla_cli-0.1.8 → walla_cli-0.1.10}/README.md +13 -4
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/WIRE.md +4 -1
- walla_cli-0.1.10/docs/assets/walla-demo-poster.jpg +0 -0
- walla_cli-0.1.10/docs/assets/walla-demo-preview.gif +0 -0
- walla_cli-0.1.10/docs/assets/walla-demo.mp4 +0 -0
- walla_cli-0.1.10/fixtures/categories.json +59 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/pyproject.toml +1 -1
- {walla_cli-0.1.8 → walla_cli-0.1.10}/skills/walla-sell/SKILL.md +5 -4
- walla_cli-0.1.10/tests/test_categories_find.py +58 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_parsers.py +2 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_sell.py +28 -0
- walla_cli-0.1.10/uv.lock +2644 -0
- walla_cli-0.1.10/walla/__init__.py +7 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/sell.py +31 -3
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/sell_wire.py +5 -2
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/banner.py +12 -8
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/cmd_look.py +27 -1
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/cmd_sell.py +36 -10
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/main.py +2 -3
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/instruct.py +2 -1
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/mcp/server.py +26 -4
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/models/profile.py +1 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/search/__init__.py +12 -0
- walla_cli-0.1.10/walla/search/category_find.py +98 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/search/parse.py +17 -13
- walla_cli-0.1.10/walla/search/pick_category.py +47 -0
- walla_cli-0.1.8/fixtures/categories.json +0 -49
- walla_cli-0.1.8/walla/__init__.py +0 -7
- {walla_cli-0.1.8 → walla_cli-0.1.10}/.cursor/rules/quality.mdc +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/.github/workflows/ci.yml +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/.gitignore +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/AGENTS.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/LICENSE +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/assets/walla-github-banner.jpg +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/code_quality.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/data_engineering_standards.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/mcp.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/objective_function.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/docs/rate_limit_analysis.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/fixtures/item_detail.json +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/fixtures/offer_buyer_request.json +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/fixtures/search_bicicleta.json +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/fixtures/sell_item_request.json +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/fixtures/wire_contracts.json +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/scripts/check_code_quality.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/scripts/dogfood_run.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/scripts/probe_rate.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/skills/walla/SKILL.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/skills/walla-buy/SKILL.md +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_account.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_account_more.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_catch.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_chat_open.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_cli_json.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_core.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_desk.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_edges.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_export.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_http_more.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_live.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_negotiate.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_polite.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_regressions.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_search_api.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_session_store.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_shortlist.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_verdict.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/tests/test_wire_contracts.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/actions.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/chat.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/cookies.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/desk.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/inbox.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/login.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/offer_wire.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/prompt.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/account/session_store.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/catch.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/cmd_account.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/cmd_desk.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/cmd_ops.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/cli/console.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/envelope.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/errors.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/exceptions.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/human_fix.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/core/path.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/http/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/http/client.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/http/headers.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/http/polite.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/converge.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/export.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/export_pdf.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/negotiate.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/profile_store.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/pursuits.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/shortlist.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/stack.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/verdict.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/hunter/watches.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/mcp/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/mcp/_entry.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/models/__init__.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/models/account.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/models/listing.py +0 -0
- {walla_cli-0.1.8 → walla_cli-0.1.10}/walla/search/api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: walla-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Wallapop.es CLI - look · offer · talk · sell for humans and agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/berendgort/wallapop-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/berendgort/wallapop-cli
|
|
@@ -55,12 +55,21 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
Dr. Berend Gort · www.berendgort.dev
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
](https://github.com/berendgort/wallapop-cli/releases/download/demo/walla-demo.mp4)
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
▶ [Play full demo with sound](https://github.com/berendgort/wallapop-cli/releases/download/demo/walla-demo.mp4)
|
|
61
|
+
· Demo music: [Funkee Monkeee](https://mixkit.co/free-stock-music/funkee-monkeee-1140/) by Michael Ramir C.
|
|
62
|
+
([Mixkit Stock Music Free License](https://mixkit.co/license/#musicFree)).
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
**walla** turns Claude, GPT, or Cursor into a Wallapop helper that actually
|
|
65
|
+
*does* the work for you. You drop a few photos and answer a couple of
|
|
66
|
+
questions; the agent publishes the listing. When buyers message, it reads
|
|
67
|
+
the chats, replies for you, and negotiates down to your minimum price —
|
|
68
|
+
then shows you the best deal. You only open the Wallapop app to accept.
|
|
69
|
+
No typing chats. No babysitting the inbox.
|
|
70
|
+
|
|
71
|
+
Unofficial Wallapop.es CLI + MCP + Python library. Not affiliated with
|
|
72
|
+
Wallapop. Respect ToS and rate limits.
|
|
64
73
|
|
|
65
74
|
### What this unlocks
|
|
66
75
|
|
|
@@ -11,12 +11,21 @@
|
|
|
11
11
|
Dr. Berend Gort · www.berendgort.dev
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
](https://github.com/berendgort/wallapop-cli/releases/download/demo/walla-demo.mp4)
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
▶ [Play full demo with sound](https://github.com/berendgort/wallapop-cli/releases/download/demo/walla-demo.mp4)
|
|
17
|
+
· Demo music: [Funkee Monkeee](https://mixkit.co/free-stock-music/funkee-monkeee-1140/) by Michael Ramir C.
|
|
18
|
+
([Mixkit Stock Music Free License](https://mixkit.co/license/#musicFree)).
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
**walla** turns Claude, GPT, or Cursor into a Wallapop helper that actually
|
|
21
|
+
*does* the work for you. You drop a few photos and answer a couple of
|
|
22
|
+
questions; the agent publishes the listing. When buyers message, it reads
|
|
23
|
+
the chats, replies for you, and negotiates down to your minimum price —
|
|
24
|
+
then shows you the best deal. You only open the Wallapop app to accept.
|
|
25
|
+
No typing chats. No babysitting the inbox.
|
|
26
|
+
|
|
27
|
+
Unofficial Wallapop.es CLI + MCP + Python library. Not affiliated with
|
|
28
|
+
Wallapop. Respect ToS and rate limits.
|
|
20
29
|
|
|
21
30
|
### What this unlocks
|
|
22
31
|
|
|
@@ -29,7 +29,10 @@ Public URL: `https://es.wallapop.com/item/<web_slug>`.
|
|
|
29
29
|
|
|
30
30
|
## Categories
|
|
31
31
|
|
|
32
|
-
`GET https://api.wallapop.com/api/v3/categories` —
|
|
32
|
+
`GET https://api.wallapop.com/api/v3/categories` — nested tree
|
|
33
|
+
(`subcategories[]`). CLI: `walla categories --find escritorio --json` returns
|
|
34
|
+
`leaf_id` + `root_id`. Sell accepts `--category <leaf-or-name>`; `--root` is
|
|
35
|
+
optional.
|
|
33
36
|
|
|
34
37
|
## Auth
|
|
35
38
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"categories": [
|
|
3
|
+
{
|
|
4
|
+
"id": 100,
|
|
5
|
+
"name": "Cars",
|
|
6
|
+
"path": "",
|
|
7
|
+
"vertical_id": "cars",
|
|
8
|
+
"icon": "car",
|
|
9
|
+
"subcategories": [],
|
|
10
|
+
"category_leaf_selection_mandatory": false
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": 12467,
|
|
14
|
+
"name": "Hogar y jardín",
|
|
15
|
+
"path": "",
|
|
16
|
+
"vertical_id": "consumer_goods",
|
|
17
|
+
"icon": "home",
|
|
18
|
+
"subcategories": [
|
|
19
|
+
{
|
|
20
|
+
"id": 10125,
|
|
21
|
+
"name": "Muebles y organización",
|
|
22
|
+
"parent_id": 12467,
|
|
23
|
+
"subcategories": [
|
|
24
|
+
{
|
|
25
|
+
"id": 24207,
|
|
26
|
+
"name": "Mesas y mesitas",
|
|
27
|
+
"parent_id": 10125,
|
|
28
|
+
"subcategories": [
|
|
29
|
+
{
|
|
30
|
+
"id": 24208,
|
|
31
|
+
"name": "Escritorios",
|
|
32
|
+
"parent_id": 24207,
|
|
33
|
+
"subcategories": []
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"category_leaf_selection_mandatory": false
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": 12579,
|
|
44
|
+
"name": "Deporte y ocio",
|
|
45
|
+
"path": "",
|
|
46
|
+
"vertical_id": "consumer_goods",
|
|
47
|
+
"icon": "ball",
|
|
48
|
+
"subcategories": [
|
|
49
|
+
{
|
|
50
|
+
"id": 10105,
|
|
51
|
+
"name": "Surf y bodyboard",
|
|
52
|
+
"parent_id": 12579,
|
|
53
|
+
"subcategories": []
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"category_leaf_selection_mandatory": false
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -13,6 +13,7 @@ license: MIT
|
|
|
13
13
|
Do not ask the human to type buyer replies. Desk sends those.
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
+
walla categories --find escritorio --json
|
|
16
17
|
walla sell ./shot1.jpg ./shot2.jpg --json
|
|
17
18
|
```
|
|
18
19
|
|
|
@@ -21,13 +22,13 @@ Ask every question in `data.questions`, then publish once:
|
|
|
21
22
|
```bash
|
|
22
23
|
walla sell ./shot1.jpg ./shot2.jpg \
|
|
23
24
|
--title "…" --desc "…" --eur 40 \
|
|
24
|
-
--category
|
|
25
|
+
--category escritorio --condition good \
|
|
25
26
|
--floor 35 --yes --json
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
`--
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
`--category` accepts a leaf id **or** name tokens (`escritorio`, `hogar/muebles`).
|
|
30
|
+
`--root` is optional (derived from the leaf). `--floor` is the lowest EUR desk may
|
|
31
|
+
accept. Omit it to hold the asking price.
|
|
31
32
|
Then:
|
|
32
33
|
|
|
33
34
|
```bash
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Category tree find / root resolve."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from walla.search.category_find import find_categories, flatten_categories, resolve_root_id
|
|
11
|
+
from walla.search.parse import parse_categories
|
|
12
|
+
from walla.search.pick_category import pick_sell_category
|
|
13
|
+
|
|
14
|
+
FIX = Path(__file__).resolve().parents[1] / "fixtures"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _roots():
|
|
18
|
+
raw = json.loads((FIX / "categories.json").read_text(encoding="utf-8"))
|
|
19
|
+
return parse_categories(raw)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_parse_nested_categories() -> None:
|
|
23
|
+
roots = _roots()
|
|
24
|
+
hogar = next(c for c in roots if c.id == 12467)
|
|
25
|
+
assert hogar.subcategories
|
|
26
|
+
assert flatten_categories(roots)
|
|
27
|
+
assert resolve_root_id(roots, "24208") == "12467"
|
|
28
|
+
assert resolve_root_id(roots, "10105") == "12579"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_find_escritorio() -> None:
|
|
32
|
+
hits = find_categories(_roots(), "escritorio")
|
|
33
|
+
assert hits
|
|
34
|
+
assert hits[0].leaf_id == "24208"
|
|
35
|
+
assert hits[0].root_id == "12467"
|
|
36
|
+
assert hits[0].is_leaf
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_pick_by_name_and_id() -> None:
|
|
40
|
+
roots = _roots()
|
|
41
|
+
by_name = pick_sell_category(roots, category="escritorio")
|
|
42
|
+
assert by_name.leaf_id == "24208"
|
|
43
|
+
assert by_name.root_id == "12467"
|
|
44
|
+
by_id = pick_sell_category(roots, category="24208")
|
|
45
|
+
assert by_id.leaf_id == "24208"
|
|
46
|
+
assert by_id.root_id == "12467"
|
|
47
|
+
forced = pick_sell_category(roots, category="10105", root="12579")
|
|
48
|
+
assert forced.root_id == "12579"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_find_empty_and_unknown() -> None:
|
|
52
|
+
with pytest.raises(ValueError, match="empty"):
|
|
53
|
+
find_categories(_roots(), " ")
|
|
54
|
+
assert find_categories(_roots(), "zzzz-no-such") == []
|
|
55
|
+
with pytest.raises(ValueError, match="unknown"):
|
|
56
|
+
resolve_root_id(_roots(), "999999")
|
|
57
|
+
with pytest.raises(ValueError, match="no category matches"):
|
|
58
|
+
pick_sell_category(_roots(), category="zzzz-no-such")
|
|
@@ -14,6 +14,7 @@ from walla.account.sell_wire import (
|
|
|
14
14
|
build_item_body,
|
|
15
15
|
missing_sell_fields,
|
|
16
16
|
)
|
|
17
|
+
from walla.core.exceptions import WallaHTTPError
|
|
17
18
|
|
|
18
19
|
ROOT = Path(__file__).resolve().parents[1]
|
|
19
20
|
FIXTURE = ROOT / "fixtures" / "sell_item_request.json"
|
|
@@ -130,6 +131,9 @@ def test_publish_listing_mocked(tmp_path: Path) -> None:
|
|
|
130
131
|
{"step": {"id": "listing"}},
|
|
131
132
|
]
|
|
132
133
|
fake_http.get.return_value = {}
|
|
134
|
+
listing = MagicMock()
|
|
135
|
+
listing.url = "https://es.wallapop.com/item/test-item-99"
|
|
136
|
+
listing.web_slug = "test-item-99"
|
|
133
137
|
with (
|
|
134
138
|
patch("walla.account.sell._auth_client", return_value=fake_http),
|
|
135
139
|
patch("walla.account.sell.upload_pictures", return_value=1),
|
|
@@ -137,6 +141,7 @@ def test_publish_listing_mocked(tmp_path: Path) -> None:
|
|
|
137
141
|
"walla.account.sell.create_listing",
|
|
138
142
|
return_value={"id": "abc123", "flags": {}},
|
|
139
143
|
),
|
|
144
|
+
patch("walla.account.sell.get_item", return_value=listing),
|
|
140
145
|
):
|
|
141
146
|
out = publish_listing(
|
|
142
147
|
[photo],
|
|
@@ -150,6 +155,7 @@ def test_publish_listing_mocked(tmp_path: Path) -> None:
|
|
|
150
155
|
)
|
|
151
156
|
assert out["id"] == "abc123"
|
|
152
157
|
assert out["photos"] == 1
|
|
158
|
+
assert out["url"] == "https://es.wallapop.com/item/test-item-99"
|
|
153
159
|
assert fake_http.post.call_count == 5
|
|
154
160
|
|
|
155
161
|
|
|
@@ -217,6 +223,9 @@ def test_publish_listing_two_photos(tmp_path: Path) -> None:
|
|
|
217
223
|
fake_resp.text = ""
|
|
218
224
|
fake_session = MagicMock()
|
|
219
225
|
fake_session.request.return_value = fake_resp
|
|
226
|
+
listing = MagicMock()
|
|
227
|
+
listing.url = "https://es.wallapop.com/item/test-item-99"
|
|
228
|
+
listing.web_slug = "test-item-99"
|
|
220
229
|
with (
|
|
221
230
|
patch("walla.account.sell._auth_client", return_value=fake_http),
|
|
222
231
|
patch("walla.account.sell.upload_pictures", return_value=2),
|
|
@@ -224,6 +233,7 @@ def test_publish_listing_two_photos(tmp_path: Path) -> None:
|
|
|
224
233
|
"walla.account.sell.create_listing",
|
|
225
234
|
return_value={"id": "abc123", "flags": {}},
|
|
226
235
|
),
|
|
236
|
+
patch("walla.account.sell.get_item", return_value=listing),
|
|
227
237
|
patch("walla.account.sell._auth_headers", return_value={}),
|
|
228
238
|
patch("walla.account.sell.requests.Session", return_value=fake_session),
|
|
229
239
|
patch("walla.account.sell.CurlMime") as mime_cls,
|
|
@@ -243,9 +253,27 @@ def test_publish_listing_two_photos(tmp_path: Path) -> None:
|
|
|
243
253
|
weight_kg=2,
|
|
244
254
|
)
|
|
245
255
|
assert out["photos"] == 2
|
|
256
|
+
assert out["url"] == "https://es.wallapop.com/item/test-item-99"
|
|
246
257
|
fake_session.request.assert_called()
|
|
247
258
|
|
|
248
259
|
|
|
260
|
+
def test_public_item_url_uses_slug_not_hash() -> None:
|
|
261
|
+
from walla.account.sell import _public_item_url
|
|
262
|
+
|
|
263
|
+
listing = MagicMock()
|
|
264
|
+
listing.url = ""
|
|
265
|
+
listing.web_slug = "escritorio-madera-1309402890"
|
|
266
|
+
with patch("walla.account.sell.get_item", return_value=listing):
|
|
267
|
+
assert _public_item_url("x6qq0n82pe6y").endswith(
|
|
268
|
+
"/item/escritorio-madera-1309402890"
|
|
269
|
+
)
|
|
270
|
+
with patch(
|
|
271
|
+
"walla.account.sell.get_item",
|
|
272
|
+
side_effect=WallaHTTPError("down", status_code=500),
|
|
273
|
+
):
|
|
274
|
+
assert _public_item_url("x6qq0n82pe6y").endswith("/item/x6qq0n82pe6y")
|
|
275
|
+
|
|
276
|
+
|
|
249
277
|
def test_assert_item_body_errors() -> None:
|
|
250
278
|
with pytest.raises(ValueError, match="missing"):
|
|
251
279
|
assert_item_body({})
|