yuque-cli 0.2.0__tar.gz → 1.0.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 (40) hide show
  1. yuque_cli-1.0.0/.claude/settings.json +15 -0
  2. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/PKG-INFO +3 -3
  3. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/README.md +2 -2
  4. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/pyproject.toml +1 -1
  5. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/cli.py +15 -14
  6. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/urls.py +21 -5
  7. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_cli.py +5 -5
  8. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_urls.py +33 -9
  9. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/uv.lock +1 -1
  10. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/.claude/settings.local.json +0 -0
  11. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/.gitignore +0 -0
  12. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/.python-version +0 -0
  13. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/.vscode/extensions.json +0 -0
  14. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/.vscode/settings.json +0 -0
  15. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/AGENTS.md +0 -0
  16. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/CLAUDE.md +0 -0
  17. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/CONTEXT.md +0 -0
  18. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/docs/adr/0001-use-internal-web-api-with-cookie-auth.md +0 -0
  19. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/docs/adr/0002-cookie-acquisition-cdp-with-manual-fallback.md +0 -0
  20. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/docs/adr/0003-doc-update-fetch-then-merge.md +0 -0
  21. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/docs/internal-api.md +0 -0
  22. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/main.py +0 -0
  23. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/mise.toml +0 -0
  24. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/__init__.py +0 -0
  25. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/__main__.py +0 -0
  26. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/appdata.py +0 -0
  27. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/auth.py +0 -0
  28. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/client.py +0 -0
  29. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/config.py +0 -0
  30. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/errors.py +0 -0
  31. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/inputs.py +0 -0
  32. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/output.py +0 -0
  33. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/src/yuque_cli/session.py +0 -0
  34. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_appdata.py +0 -0
  35. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_auth.py +0 -0
  36. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_client.py +0 -0
  37. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_config.py +0 -0
  38. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_inputs.py +0 -0
  39. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_output.py +0 -0
  40. {yuque_cli-0.2.0 → yuque_cli-1.0.0}/test/test_session.py +0 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "hooks": {
3
+ "Stop": [
4
+ {
5
+ "matcher": "EDIT|Write",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "if git diff --name-only HEAD 2>/dev/null | grep -q '^src/\\|^pyproject.toml'; then current=$(grep '^version = ' pyproject.toml | head -1 | sed 's/version = \"\\(.*\\)\"/\\1/'); IFS='.' read -r major minor patch <<< \"$current\"; new=\"$major.$minor.$((patch + 1))\"; sed -i '' \"s/^version = \\\".*\\\"/version = \\\"$new\\\"/\" pyproject.toml && echo \"[版本升级] $current → $new (patch)\"; fi"
10
+ }
11
+ ]
12
+ }
13
+ ]
14
+ }
15
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yuque-cli
3
- Version: 0.2.0
3
+ Version: 1.0.0
4
4
  Summary: 针对语雀的命令行客户端:cookie 认证,驱动内部 web 接口,提供文档与评论的 CRUD
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: httpx>=0.27
@@ -101,12 +101,12 @@ yuque -y doc delete team/handbook/old-draft
101
101
  | 命令 | 说明 |
102
102
  | --- | --- |
103
103
  | `comment list <space>/<repo>/<slug>` | 列出评论 |
104
- | `comment add <space>/<repo>/<slug> [-b/--body \| -F/--file]` | 添加评论 |
104
+ | `comment create <space>/<repo>/<slug> [-b/--body \| -F/--file]` | 添加评论 |
105
105
  | `comment delete <comment_id>` | 删除评论 |
106
106
 
107
107
  ## 正文输入
108
108
 
109
- `doc create` / `comment add` 正文来源(`--body` 与 `--file` 互斥):
109
+ `doc create` / `comment create` 正文来源(`--body` 与 `--file` 互斥):
110
110
 
111
111
  1. `-b/--body` 内联字符串
112
112
  2. `-F/--file` 从文件读(`-F -` 读 stdin)
@@ -91,12 +91,12 @@ yuque -y doc delete team/handbook/old-draft
91
91
  | 命令 | 说明 |
92
92
  | --- | --- |
93
93
  | `comment list <space>/<repo>/<slug>` | 列出评论 |
94
- | `comment add <space>/<repo>/<slug> [-b/--body \| -F/--file]` | 添加评论 |
94
+ | `comment create <space>/<repo>/<slug> [-b/--body \| -F/--file]` | 添加评论 |
95
95
  | `comment delete <comment_id>` | 删除评论 |
96
96
 
97
97
  ## 正文输入
98
98
 
99
- `doc create` / `comment add` 正文来源(`--body` 与 `--file` 互斥):
99
+ `doc create` / `comment create` 正文来源(`--body` 与 `--file` 互斥):
100
100
 
101
101
  1. `-b/--body` 内联字符串
102
102
  2. `-F/--file` 从文件读(`-F -` 读 stdin)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "yuque-cli"
3
- version = "0.2.0"
3
+ version = "1.0.0"
4
4
  description = "针对语雀的命令行客户端:cookie 认证,驱动内部 web 接口,提供文档与评论的 CRUD"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -86,7 +86,7 @@ def cli_errors():
86
86
  raise typer.Exit(1)
87
87
 
88
88
 
89
- def build_client(state: AppState) -> Client:
89
+ def build_client(state: AppState, host_hint: str | None = None) -> Client:
90
90
  sess = session.load(config.session_file())
91
91
  hooks: dict[str, list[Callable[..., Any]]] = {}
92
92
  if state.verbose:
@@ -99,7 +99,8 @@ def build_client(state: AppState) -> Client:
99
99
  # trust_env=False:默认直连,绕开 *_proxy 环境变量(如本地 Clash 的 socks5 代理)——
100
100
  # 避免请求被本地代理拦截,也免去 SOCKS 需 socksio 的崩溃。如需经代理访问,移除此参数并装 httpx[socks]。
101
101
  http = httpx.Client(timeout=30.0, event_hooks=hooks, trust_env=False)
102
- return Client(http, sess, base_url=config.base_url(state.host))
102
+ # --host 显式指定优先;否则从 URL 提取的 host 作为 fallback
103
+ return Client(http, sess, base_url=config.base_url(state.host or host_hint))
103
104
 
104
105
 
105
106
  def _pager(text: str) -> None:
@@ -320,7 +321,7 @@ def repo_get(
320
321
  state: AppState = ctx.obj
321
322
  with cli_errors():
322
323
  ref = _resolve_repo_ref(url, space, repo)
323
- client = build_client(state)
324
+ client = build_client(state, host_hint=ref.host)
324
325
  repo_id = client.resolve_repo_id(ref.space, ref.repo)
325
326
  data = client.repo_overview(repo_id)
326
327
  docs = client.repo_docs(repo_id)
@@ -351,7 +352,7 @@ def doc_list(ctx: typer.Context, url: UrlArg) -> None:
351
352
  with cli_errors():
352
353
  assert url is not None
353
354
  ref = parse_repo_ref(url)
354
- client = build_client(state)
355
+ client = build_client(state, host_hint=ref.host)
355
356
  repo_id = client.resolve_repo_id(ref.space, ref.repo)
356
357
  docs = client.repo_docs(repo_id)
357
358
  _emit(state, docs, output.render_docs(docs))
@@ -364,7 +365,7 @@ def doc_get(ctx: typer.Context, url: UrlArg) -> None:
364
365
  with cli_errors():
365
366
  assert url is not None
366
367
  ref = parse_doc_ref(url)
367
- client = build_client(state)
368
+ client = build_client(state, host_hint=ref.host)
368
369
  if state.json:
369
370
  app_data = client.doc_page_app_data(ref.space, ref.repo, ref.slug)
370
371
  detail = client.doc_detail(ref.slug, appdata_repo_id(app_data))
@@ -404,13 +405,13 @@ def doc_create(
404
405
  raise YuqueError("--title 为必填项")
405
406
  ref = _resolve_repo_ref(url, space, repo)
406
407
  text = _read_body(body, file)
407
- client = build_client(state)
408
+ client = build_client(state, host_hint=ref.host)
408
409
  repo_id = client.resolve_repo_id(ref.space, ref.repo)
409
410
  pub = None if public is None else (1 if public else 0)
410
411
  created = client.create_doc(
411
412
  repo_id=repo_id, title=title, body=text, slug=slug, public=pub
412
413
  )
413
- url_out = f"{config.base_url(state.host)}/{ref.space}/{ref.repo}/{created.get('slug', '')}"
414
+ url_out = f"{config.base_url(state.host or ref.host)}/{ref.space}/{ref.repo}/{created.get('slug', '')}"
414
415
  _emit(state, created, f"已创建:{url_out}")
415
416
 
416
417
 
@@ -433,7 +434,7 @@ def doc_update(
433
434
  "没有要更新的字段(至少给 --title / 正文 / --public|--private 之一)"
434
435
  )
435
436
  ref = _resolve_doc_ref(url, space, repo)
436
- client = build_client(state)
437
+ client = build_client(state, host_hint=ref.host)
437
438
  app_data = client.doc_page_app_data(ref.space, ref.repo, ref.slug)
438
439
  doc_id = appdata_doc_id(app_data)
439
440
  meta = app_data.get("doc", {})
@@ -446,7 +447,7 @@ def doc_update(
446
447
  updated = client.update_doc(
447
448
  doc_id=doc_id, title=new_title, body=new_body, public=new_public
448
449
  )
449
- url_out = f"{config.base_url(state.host)}/{ref.space}/{ref.repo}/{ref.slug}"
450
+ url_out = f"{config.base_url(state.host or ref.host)}/{ref.space}/{ref.repo}/{ref.slug}"
450
451
  _emit(state, updated, f"已更新:{url_out}")
451
452
 
452
453
 
@@ -457,7 +458,7 @@ def doc_delete(ctx: typer.Context, url: UrlArg) -> None:
457
458
  with cli_errors():
458
459
  assert url is not None
459
460
  ref = parse_doc_ref(url)
460
- client = build_client(state)
461
+ client = build_client(state, host_hint=ref.host)
461
462
  app_data = client.doc_page_app_data(ref.space, ref.repo, ref.slug)
462
463
  doc_id = appdata_doc_id(app_data)
463
464
  title = app_data.get("doc", {}).get("title", ref.slug)
@@ -476,7 +477,7 @@ def comment_list(ctx: typer.Context, url: UrlArg) -> None:
476
477
  with cli_errors():
477
478
  assert url is not None
478
479
  ref = parse_doc_ref(url)
479
- client = build_client(state)
480
+ client = build_client(state, host_hint=ref.host)
480
481
  _, doc_id = client.resolve_doc_ids(ref.space, ref.repo, ref.slug)
481
482
  items = client.comments(doc_id)
482
483
  _emit(state, items, output.render_comments(items))
@@ -488,8 +489,8 @@ SelectionOpt = Annotated[
488
489
  ]
489
490
 
490
491
 
491
- @comment_app.command("add")
492
- def comment_add(
492
+ @comment_app.command("create")
493
+ def comment_create(
493
494
  ctx: typer.Context,
494
495
  url: UrlArg,
495
496
  body: BodyOpt = None,
@@ -504,7 +505,7 @@ def comment_add(
504
505
  text = _read_body(body, file)
505
506
  if not text:
506
507
  raise YuqueError("评论正文不能为空(用 --body 或 --file/-)")
507
- client = build_client(state)
508
+ client = build_client(state, host_hint=ref.host)
508
509
  _, doc_id = client.resolve_doc_ids(ref.space, ref.repo, ref.slug)
509
510
  if selection is not None:
510
511
  try:
@@ -12,6 +12,7 @@ class UrlParseError(ValueError):
12
12
  class RepoRef:
13
13
  space: str
14
14
  repo: str
15
+ host: str | None = None
15
16
 
16
17
 
17
18
  @dataclass(frozen=True)
@@ -19,10 +20,11 @@ class DocRef:
19
20
  space: str
20
21
  repo: str
21
22
  slug: str
23
+ host: str | None = None
22
24
 
23
25
  @property
24
26
  def repo_ref(self) -> RepoRef:
25
- return RepoRef(self.space, self.repo)
27
+ return RepoRef(self.space, self.repo, host=self.host)
26
28
 
27
29
 
28
30
  def _segments(raw: str) -> list[str]:
@@ -42,14 +44,28 @@ def _segments(raw: str) -> list[str]:
42
44
  return [seg for seg in path.split("/") if seg]
43
45
 
44
46
 
47
+ def extract_host(raw: str) -> str | None:
48
+ """从完整 URL 或带 host 的路径中提取 host;无法识别时返回 None。"""
49
+ s = raw.strip()
50
+ if not s:
51
+ return None
52
+ if "://" in s:
53
+ return urlsplit(s).hostname
54
+ # 无 scheme:首段含 "." 即视为 host
55
+ parts = s.split("/")
56
+ if parts and "." in parts[0]:
57
+ return parts[0]
58
+ return None
59
+
60
+
45
61
  def parse_doc_ref(raw: str) -> DocRef:
46
62
  segs = _segments(raw)
47
- if len(segs) != 3:
63
+ if len(segs) < 3:
48
64
  raise UrlParseError(
49
65
  f"文档地址应形如 {{space}}/{{repo}}/{{slug}}(三段),得到:{raw!r}"
50
66
  )
51
- space, repo, slug = segs
52
- return DocRef(space=space, repo=repo, slug=slug)
67
+ space, repo, slug = segs[:3]
68
+ return DocRef(space=space, repo=repo, slug=slug, host=extract_host(raw))
53
69
 
54
70
 
55
71
  def parse_repo_ref(raw: str) -> RepoRef:
@@ -60,4 +76,4 @@ def parse_repo_ref(raw: str) -> RepoRef:
60
76
  )
61
77
  if len(segs) > 3:
62
78
  raise UrlParseError(f"地址段数过多,无法识别为知识库:{raw!r}")
63
- return RepoRef(space=segs[0], repo=segs[1])
79
+ return RepoRef(space=segs[0], repo=segs[1], host=extract_host(raw))
@@ -99,7 +99,7 @@ class FakeClient:
99
99
  @pytest.fixture
100
100
  def fake(monkeypatch):
101
101
  fc = FakeClient()
102
- monkeypatch.setattr(cli, "build_client", lambda state: fc)
102
+ monkeypatch.setattr(cli, "build_client", lambda state, host_hint=None: fc)
103
103
  return fc
104
104
 
105
105
 
@@ -374,20 +374,20 @@ class TestComment:
374
374
 
375
375
  def test_add(self, fake):
376
376
  result = runner.invoke(
377
- cli.app, ["comment", "add", "lg/bk/sl", "--body", "nice"]
377
+ cli.app, ["comment", "create", "lg/bk/sl", "--body", "nice"]
378
378
  )
379
379
  assert "已评论" in result.output
380
380
  assert calls(fake, "create_comment")[0][1] == {"doc_id": 88, "body": "nice"}
381
381
 
382
382
  def test_add_empty_body_errors(self, fake):
383
- result = runner.invoke(cli.app, ["comment", "add", "lg/bk/sl"])
383
+ result = runner.invoke(cli.app, ["comment", "create", "lg/bk/sl"])
384
384
  assert result.exit_code == 1
385
385
  assert "评论正文不能为空" in result.output
386
386
 
387
387
  def test_add_with_selection(self, fake):
388
388
  sel = '{"paragraph_id":"u-pid","text":"hello","text_offset":0,"selection_range":{"start":{"id":"u-eid","text":"hello","offset":0,"paragraphId":"u-pid","paragraphOffset":0},"end":{"id":"u-eid","text":"hello","offset":3,"paragraphId":"u-pid","paragraphOffset":3}},"doc_version_id":123}'
389
389
  result = runner.invoke(
390
- cli.app, ["comment", "add", "lg/bk/sl", "--body", "nice", "--selection", sel]
390
+ cli.app, ["comment", "create", "lg/bk/sl", "--body", "nice", "--selection", sel]
391
391
  )
392
392
  assert "已评论" in result.output
393
393
  kw = calls(fake, "create_comment")[0][1]
@@ -406,7 +406,7 @@ class TestComment:
406
406
 
407
407
  def test_add_with_selection_invalid_json_errors(self, fake):
408
408
  result = runner.invoke(
409
- cli.app, ["comment", "add", "lg/bk/sl", "--body", "nice", "--selection", "not json"]
409
+ cli.app, ["comment", "create", "lg/bk/sl", "--body", "nice", "--selection", "not json"]
410
410
  )
411
411
  assert result.exit_code == 1
412
412
  assert "--selection JSON 解析失败" in result.output
@@ -4,6 +4,7 @@ from yuque_cli.urls import (
4
4
  RepoRef,
5
5
  DocRef,
6
6
  UrlParseError,
7
+ extract_host,
7
8
  parse_repo_ref,
8
9
  parse_doc_ref,
9
10
  )
@@ -12,15 +13,15 @@ from yuque_cli.urls import (
12
13
  class TestParseDocRef:
13
14
  def test_full_https_url(self):
14
15
  ref = parse_doc_ref("https://www.yuque.com/abc/team-book/my-slug")
15
- assert ref == DocRef(space="abc", repo="team-book", slug="my-slug")
16
+ assert ref == DocRef(space="abc", repo="team-book", slug="my-slug", host="www.yuque.com")
16
17
 
17
18
  def test_http_scheme(self):
18
19
  ref = parse_doc_ref("http://www.yuque.com/abc/book/slug")
19
- assert ref == DocRef("abc", "book", "slug")
20
+ assert ref == DocRef("abc", "book", "slug", host="www.yuque.com")
20
21
 
21
22
  def test_host_without_scheme(self):
22
23
  ref = parse_doc_ref("www.yuque.com/abc/book/slug")
23
- assert ref == DocRef("abc", "book", "slug")
24
+ assert ref == DocRef("abc", "book", "slug", host="www.yuque.com")
24
25
 
25
26
  def test_path_only(self):
26
27
  ref = parse_doc_ref("abc/book/slug")
@@ -34,7 +35,7 @@ class TestParseDocRef:
34
35
 
35
36
  def test_strips_query_and_fragment(self):
36
37
  ref = parse_doc_ref("https://www.yuque.com/abc/book/slug?from=x#h1")
37
- assert ref == DocRef("abc", "book", "slug")
38
+ assert ref == DocRef("abc", "book", "slug", host="www.yuque.com")
38
39
 
39
40
  def test_strips_surrounding_whitespace(self):
40
41
  assert parse_doc_ref(" abc/book/slug ") == DocRef("abc", "book", "slug")
@@ -51,9 +52,12 @@ class TestParseDocRef:
51
52
  with pytest.raises(UrlParseError):
52
53
  parse_doc_ref("")
53
54
 
54
- def test_too_many_segments_rejected(self):
55
- with pytest.raises(UrlParseError):
56
- parse_doc_ref("abc/book/slug/extra")
55
+ def test_extra_segments_use_first_three(self):
56
+ """多余的路径段(如 /edit)会被忽略,只取前三段。"""
57
+ assert parse_doc_ref("abc/book/slug/edit") == DocRef("abc", "book", "slug")
58
+ assert parse_doc_ref(
59
+ "https://www.yuque.com/abc/book/slug/edit"
60
+ ) == DocRef("abc", "book", "slug", host="www.yuque.com")
57
61
 
58
62
  def test_repo_ref_property(self):
59
63
  ref = parse_doc_ref("abc/book/slug")
@@ -63,7 +67,7 @@ class TestParseDocRef:
63
67
  class TestParseRepoRef:
64
68
  def test_full_https_url(self):
65
69
  assert parse_repo_ref("https://www.yuque.com/abc/team-book") == RepoRef(
66
- "abc", "team-book"
70
+ "abc", "team-book", host="www.yuque.com"
67
71
  )
68
72
 
69
73
  def test_path_only(self):
@@ -73,7 +77,7 @@ class TestParseRepoRef:
73
77
  assert parse_repo_ref("abc/team-book/some-slug") == RepoRef("abc", "team-book")
74
78
 
75
79
  def test_host_stripped_and_trailing_slash(self):
76
- assert parse_repo_ref("www.yuque.com/abc/book/") == RepoRef("abc", "book")
80
+ assert parse_repo_ref("www.yuque.com/abc/book/") == RepoRef("abc", "book", host="www.yuque.com")
77
81
 
78
82
  def test_space_only_is_rejected(self):
79
83
  with pytest.raises(UrlParseError):
@@ -82,3 +86,23 @@ class TestParseRepoRef:
82
86
  def test_empty_is_rejected(self):
83
87
  with pytest.raises(UrlParseError):
84
88
  parse_repo_ref(" ")
89
+
90
+
91
+ class TestExtractHost:
92
+ def test_full_url(self):
93
+ assert extract_host("https://www.yuque.com/abc/book/slug") == "www.yuque.com"
94
+
95
+ def test_custom_domain(self):
96
+ assert extract_host("https://jlpay.yuque.com/pmw77l/iybc48/doc") == "jlpay.yuque.com"
97
+
98
+ def test_no_scheme_with_host(self):
99
+ assert extract_host("jlpay.yuque.com/abc/book/slug") == "jlpay.yuque.com"
100
+
101
+ def test_path_only(self):
102
+ assert extract_host("abc/book/slug") is None
103
+
104
+ def test_empty(self):
105
+ assert extract_host("") is None
106
+
107
+ def test_whitespace(self):
108
+ assert extract_host(" https://foo.com/a/b ") == "foo.com"
@@ -337,7 +337,7 @@ wheels = [
337
337
 
338
338
  [[package]]
339
339
  name = "yuque-cli"
340
- version = "0.2.0"
340
+ version = "1.0.0"
341
341
  source = { editable = "." }
342
342
  dependencies = [
343
343
  { name = "httpx" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes