runspec-confluence-core 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.
- runspec_confluence_core/__init__.py +67 -0
- runspec_confluence_core/client.py +68 -0
- runspec_confluence_core/config.py +108 -0
- runspec_confluence_core/content.py +44 -0
- runspec_confluence_core/errors.py +13 -0
- runspec_confluence_core/pages.py +114 -0
- runspec_confluence_core/search.py +15 -0
- runspec_confluence_core-0.1.0.dist-info/METADATA +10 -0
- runspec_confluence_core-0.1.0.dist-info/RECORD +10 -0
- runspec_confluence_core-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""runspec-confluence-core — Confluence helpers over atlassian-python-api.
|
|
2
|
+
|
|
3
|
+
This package depends only on ``atlassian-python-api`` — it has **no dependency on
|
|
4
|
+
runspec** and ships **no runspec.toml and no entry points**, so installing it
|
|
5
|
+
exposes the helper functions for import without surfacing any runnables (it is
|
|
6
|
+
invisible to ``runspec local`` / ``runspec serve`` discovery). ``runspec-confluence``
|
|
7
|
+
depends on it and wraps each helper as a verb of the ``confluence`` runnable.
|
|
8
|
+
|
|
9
|
+
Every operation takes an explicit :class:`ConfluenceConfig` first argument, so a
|
|
10
|
+
private (e.g. Nexus-hosted) wrapper package can inject credentials in code, bake in
|
|
11
|
+
a default ``space`` / ``env``, and build on top. Each function returns plain data
|
|
12
|
+
and raises :class:`ConfluenceError` on failure. Cloud and Server/Data Center are
|
|
13
|
+
both supported.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from runspec_confluence_core.client import build_client, translate_errors
|
|
17
|
+
from runspec_confluence_core.config import VALID_ENVS, ConfluenceConfig, config_from_env
|
|
18
|
+
from runspec_confluence_core.content import (
|
|
19
|
+
add_comment,
|
|
20
|
+
add_label,
|
|
21
|
+
get_comments,
|
|
22
|
+
get_labels,
|
|
23
|
+
get_page_history,
|
|
24
|
+
get_page_restrictions,
|
|
25
|
+
)
|
|
26
|
+
from runspec_confluence_core.errors import ConfluenceError
|
|
27
|
+
from runspec_confluence_core.pages import (
|
|
28
|
+
create_page,
|
|
29
|
+
delete_page,
|
|
30
|
+
get_page,
|
|
31
|
+
get_page_ancestors,
|
|
32
|
+
get_page_children,
|
|
33
|
+
get_space,
|
|
34
|
+
get_space_pages,
|
|
35
|
+
move_page,
|
|
36
|
+
update_page,
|
|
37
|
+
)
|
|
38
|
+
from runspec_confluence_core.search import search
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
# config / client
|
|
42
|
+
"ConfluenceConfig",
|
|
43
|
+
"ConfluenceError",
|
|
44
|
+
"config_from_env",
|
|
45
|
+
"build_client",
|
|
46
|
+
"translate_errors",
|
|
47
|
+
"VALID_ENVS",
|
|
48
|
+
# pages
|
|
49
|
+
"get_page",
|
|
50
|
+
"get_page_children",
|
|
51
|
+
"get_page_ancestors",
|
|
52
|
+
"create_page",
|
|
53
|
+
"update_page",
|
|
54
|
+
"delete_page",
|
|
55
|
+
"move_page",
|
|
56
|
+
"get_space_pages",
|
|
57
|
+
"get_space",
|
|
58
|
+
# search
|
|
59
|
+
"search",
|
|
60
|
+
# content
|
|
61
|
+
"get_page_history",
|
|
62
|
+
"get_labels",
|
|
63
|
+
"add_label",
|
|
64
|
+
"get_comments",
|
|
65
|
+
"add_comment",
|
|
66
|
+
"get_page_restrictions",
|
|
67
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""client.py — build an ``atlassian.Confluence`` client + shared op helpers.
|
|
2
|
+
|
|
3
|
+
``build_client`` picks exactly one auth mode (Basic when username+api_token are
|
|
4
|
+
set, else Bearer PAT). ``@translate_errors`` wraps each operation so the SDK's
|
|
5
|
+
``requests`` exceptions surface as a :class:`ConfluenceError` carrying
|
|
6
|
+
Confluence's own error message.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import functools
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from typing import Any, TypeVar
|
|
14
|
+
|
|
15
|
+
import requests
|
|
16
|
+
from atlassian import Confluence
|
|
17
|
+
|
|
18
|
+
from runspec_confluence_core.config import ConfluenceConfig
|
|
19
|
+
from runspec_confluence_core.errors import ConfluenceError
|
|
20
|
+
|
|
21
|
+
_T = TypeVar("_T")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _auth_kwargs(config: ConfluenceConfig) -> dict[str, Any]:
|
|
25
|
+
base: dict[str, Any] = {"url": config.url, "cloud": config.cloud, "verify_ssl": config.verify_ssl}
|
|
26
|
+
if config.username and config.api_token:
|
|
27
|
+
base.update(username=config.username, password=config.api_token)
|
|
28
|
+
elif config.personal_token:
|
|
29
|
+
base.update(token=config.personal_token)
|
|
30
|
+
else:
|
|
31
|
+
raise ConfluenceError("ConfluenceConfig has no usable credentials (need personal_token or username+api_token)")
|
|
32
|
+
return base
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_client(config: ConfluenceConfig) -> Confluence:
|
|
36
|
+
"""Construct an ``atlassian.Confluence`` client for ``config``."""
|
|
37
|
+
return Confluence(**_auth_kwargs(config))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _message(exc: requests.HTTPError) -> str:
|
|
41
|
+
"""Extract a human-readable message from a Confluence error response."""
|
|
42
|
+
resp = getattr(exc, "response", None)
|
|
43
|
+
if resp is None:
|
|
44
|
+
return f"Confluence request failed: {exc}"
|
|
45
|
+
try:
|
|
46
|
+
body = resp.json()
|
|
47
|
+
except Exception:
|
|
48
|
+
return f"Confluence {resp.status_code}: {resp.text[:500]}"
|
|
49
|
+
if isinstance(body, dict):
|
|
50
|
+
message = body.get("message") or body.get("reason")
|
|
51
|
+
if message:
|
|
52
|
+
return f"Confluence {resp.status_code}: {message}"
|
|
53
|
+
return f"Confluence {resp.status_code}: {str(body)[:500]}"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def translate_errors(fn: Callable[..., _T]) -> Callable[..., _T]:
|
|
57
|
+
"""Decorator: turn the SDK's ``requests`` exceptions into ``ConfluenceError``."""
|
|
58
|
+
|
|
59
|
+
@functools.wraps(fn)
|
|
60
|
+
def wrapper(*args: Any, **kwargs: Any) -> _T:
|
|
61
|
+
try:
|
|
62
|
+
return fn(*args, **kwargs)
|
|
63
|
+
except requests.HTTPError as exc:
|
|
64
|
+
raise ConfluenceError(_message(exc)) from exc
|
|
65
|
+
except requests.RequestException as exc:
|
|
66
|
+
raise ConfluenceError(f"Confluence request failed: {exc}") from exc
|
|
67
|
+
|
|
68
|
+
return wrapper
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""config.py — connection + identity for a Confluence instance, from the environment.
|
|
2
|
+
|
|
3
|
+
Mirrors ``runspec-jira-core``'s config: ``config_from_env`` reads the
|
|
4
|
+
``CONFLUENCE_*`` family (with an optional ``CONFLUENCE_<ENV>_*`` prefix selected by
|
|
5
|
+
``--env``). Every operation function takes an explicit ``ConfluenceConfig`` first
|
|
6
|
+
argument, so a private (e.g. Nexus-hosted) wrapper can inject credentials in code
|
|
7
|
+
and bake in a default ``space`` / ``env``.
|
|
8
|
+
|
|
9
|
+
Cloud vs Server/Data Center is resolved once: an explicit ``CONFLUENCE_CLOUD`` wins,
|
|
10
|
+
otherwise a ``.atlassian.net`` host is treated as Cloud and anything else as
|
|
11
|
+
Server/DC.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
|
|
19
|
+
from runspec_confluence_core.errors import ConfluenceError
|
|
20
|
+
|
|
21
|
+
VALID_ENVS = ("dev", "uat", "prod")
|
|
22
|
+
|
|
23
|
+
_FALSEY = ("0", "false", "no", "off")
|
|
24
|
+
_TRUTHY = ("1", "true", "yes", "on")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ConfluenceConfig:
|
|
29
|
+
"""Connection + identity for a Confluence instance.
|
|
30
|
+
|
|
31
|
+
Provide EITHER ``personal_token`` (a Server/Data Center Personal Access Token,
|
|
32
|
+
sent as a Bearer token) OR ``username`` + ``api_token`` (Cloud email + API
|
|
33
|
+
token, or a Server/DC basic username + password). ``space`` is an optional
|
|
34
|
+
default a wrapper can bake in.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
url: str
|
|
38
|
+
cloud: bool
|
|
39
|
+
username: str | None = None
|
|
40
|
+
api_token: str | None = None
|
|
41
|
+
personal_token: str | None = None
|
|
42
|
+
space: str | None = None
|
|
43
|
+
verify_ssl: bool = True
|
|
44
|
+
env: str | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _env_first(names: list[str]) -> str | None:
|
|
48
|
+
"""Return the first non-empty environment variable among ``names``."""
|
|
49
|
+
for name in names:
|
|
50
|
+
value = os.environ.get(name)
|
|
51
|
+
if value:
|
|
52
|
+
return value
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _resolve_cloud(url: str, override: str | None) -> bool:
|
|
57
|
+
"""Decide Cloud vs Server/DC: explicit override wins, else infer from host."""
|
|
58
|
+
if override is not None:
|
|
59
|
+
return override.strip().lower() in _TRUTHY
|
|
60
|
+
return ".atlassian.net" in url.lower()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def config_from_env(env: str | None = None) -> ConfluenceConfig:
|
|
64
|
+
"""Build a :class:`ConfluenceConfig` from environment variables.
|
|
65
|
+
|
|
66
|
+
When ``env`` (or the ``CONFLUENCE_ENV`` variable) selects dev/uat/prod, the
|
|
67
|
+
environment-prefixed variables are read first (e.g. ``CONFLUENCE_UAT_URL``),
|
|
68
|
+
falling back to the unprefixed ``CONFLUENCE_*`` family. Raises
|
|
69
|
+
:class:`ConfluenceError` when the env label is invalid, the base URL is
|
|
70
|
+
missing, or no usable credentials are configured.
|
|
71
|
+
"""
|
|
72
|
+
env = env or os.environ.get("CONFLUENCE_ENV")
|
|
73
|
+
if env is not None:
|
|
74
|
+
env = env.lower()
|
|
75
|
+
if env not in VALID_ENVS:
|
|
76
|
+
raise ConfluenceError(f"Invalid env {env!r} — expected one of {', '.join(VALID_ENVS)}")
|
|
77
|
+
|
|
78
|
+
def lookup(suffix: str) -> str | None:
|
|
79
|
+
names = []
|
|
80
|
+
if env:
|
|
81
|
+
names.append(f"CONFLUENCE_{env.upper()}_{suffix}")
|
|
82
|
+
names.append(f"CONFLUENCE_{suffix}")
|
|
83
|
+
return _env_first(names)
|
|
84
|
+
|
|
85
|
+
url = lookup("URL")
|
|
86
|
+
if not url:
|
|
87
|
+
hint = f"CONFLUENCE_{env.upper()}_URL" if env else "CONFLUENCE_URL"
|
|
88
|
+
raise ConfluenceError(f"No base URL configured — set {hint}")
|
|
89
|
+
|
|
90
|
+
username = lookup("USERNAME")
|
|
91
|
+
api_token = lookup("API_TOKEN")
|
|
92
|
+
personal_token = lookup("PERSONAL_TOKEN")
|
|
93
|
+
if not personal_token and not (username and api_token):
|
|
94
|
+
raise ConfluenceError("No credentials configured — set CONFLUENCE_PERSONAL_TOKEN (Server/DC PAT) or CONFLUENCE_USERNAME + CONFLUENCE_API_TOKEN (Cloud email + API token, or DC basic auth)")
|
|
95
|
+
|
|
96
|
+
verify = lookup("VERIFY_SSL")
|
|
97
|
+
verify_ssl = True if verify is None else verify.strip().lower() not in _FALSEY
|
|
98
|
+
|
|
99
|
+
return ConfluenceConfig(
|
|
100
|
+
url=url.rstrip("/"),
|
|
101
|
+
cloud=_resolve_cloud(url, lookup("CLOUD")),
|
|
102
|
+
username=username,
|
|
103
|
+
api_token=api_token,
|
|
104
|
+
personal_token=personal_token,
|
|
105
|
+
space=lookup("SPACE"),
|
|
106
|
+
verify_ssl=verify_ssl,
|
|
107
|
+
env=env,
|
|
108
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""content.py — history, labels, comments, and restrictions for a page."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from runspec_confluence_core.client import build_client, translate_errors
|
|
8
|
+
from runspec_confluence_core.config import ConfluenceConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@translate_errors
|
|
12
|
+
def get_page_history(config: ConfluenceConfig, page_id: str) -> Any:
|
|
13
|
+
"""Return a page's content history (created/last-updated, versions)."""
|
|
14
|
+
return build_client(config).get_content_history(page_id)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@translate_errors
|
|
18
|
+
def get_labels(config: ConfluenceConfig, page_id: str) -> Any:
|
|
19
|
+
"""List a page's labels."""
|
|
20
|
+
return build_client(config).get_page_labels(page_id)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@translate_errors
|
|
24
|
+
def add_label(config: ConfluenceConfig, page_id: str, label: str) -> Any:
|
|
25
|
+
"""Add a label to a page."""
|
|
26
|
+
return build_client(config).set_page_label(page_id, label)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@translate_errors
|
|
30
|
+
def get_comments(config: ConfluenceConfig, page_id: str, *, limit: int = 25) -> Any:
|
|
31
|
+
"""List a page's comments (rendered bodies)."""
|
|
32
|
+
return build_client(config).get_page_comments(page_id, expand="body.view", limit=limit)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@translate_errors
|
|
36
|
+
def add_comment(config: ConfluenceConfig, page_id: str, text: str) -> Any:
|
|
37
|
+
"""Add a comment to a page."""
|
|
38
|
+
return build_client(config).add_comment(page_id, text)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@translate_errors
|
|
42
|
+
def get_page_restrictions(config: ConfluenceConfig, page_id: str) -> Any:
|
|
43
|
+
"""Return the view/edit restrictions on a page."""
|
|
44
|
+
return build_client(config).get_all_restrictions_for_content(page_id)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""errors.py — the exception type raised across runspec-confluence-core.
|
|
2
|
+
|
|
3
|
+
Every operation function raises :class:`ConfluenceError` on configuration
|
|
4
|
+
problems, invalid arguments, and non-2xx API responses (the underlying
|
|
5
|
+
``atlassian-python-api`` raises ``requests`` exceptions, translated to
|
|
6
|
+
``ConfluenceError`` at the operation boundary).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConfluenceError(Exception):
|
|
13
|
+
"""Raised on config problems, invalid arguments, and Confluence API errors."""
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""pages.py — page read/create/update/delete/move + space listing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from runspec_confluence_core.client import build_client, translate_errors
|
|
8
|
+
from runspec_confluence_core.config import ConfluenceConfig
|
|
9
|
+
from runspec_confluence_core.errors import ConfluenceError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@translate_errors
|
|
13
|
+
def get_page(
|
|
14
|
+
config: ConfluenceConfig,
|
|
15
|
+
*,
|
|
16
|
+
page_id: str | None = None,
|
|
17
|
+
space: str | None = None,
|
|
18
|
+
title: str | None = None,
|
|
19
|
+
expand: str | None = None,
|
|
20
|
+
) -> Any:
|
|
21
|
+
"""Fetch a page by id, or by space + title. ``expand`` (e.g.
|
|
22
|
+
``body.storage,version``) controls what is returned."""
|
|
23
|
+
client = build_client(config)
|
|
24
|
+
if page_id:
|
|
25
|
+
return client.get_page_by_id(page_id, expand=expand)
|
|
26
|
+
space = space or config.space
|
|
27
|
+
if space and title:
|
|
28
|
+
return client.get_page_by_title(space, title, expand=expand)
|
|
29
|
+
raise ConfluenceError("get-page needs --page-id, or --space (or CONFLUENCE_SPACE) and --title")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@translate_errors
|
|
33
|
+
def get_page_children(config: ConfluenceConfig, page_id: str) -> Any:
|
|
34
|
+
"""List a page's immediate child pages."""
|
|
35
|
+
return build_client(config).get_child_pages(page_id)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@translate_errors
|
|
39
|
+
def get_page_ancestors(config: ConfluenceConfig, page_id: str) -> Any:
|
|
40
|
+
"""List a page's ancestor pages (its breadcrumb, root first)."""
|
|
41
|
+
return build_client(config).get_page_ancestors(page_id)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@translate_errors
|
|
45
|
+
def create_page(
|
|
46
|
+
config: ConfluenceConfig,
|
|
47
|
+
space: str,
|
|
48
|
+
title: str,
|
|
49
|
+
body: str,
|
|
50
|
+
*,
|
|
51
|
+
parent_id: str | None = None,
|
|
52
|
+
representation: str = "storage",
|
|
53
|
+
) -> Any:
|
|
54
|
+
"""Create a page. ``body`` is in ``representation`` format (``storage`` XHTML by
|
|
55
|
+
default, or ``wiki`` / ``editor``)."""
|
|
56
|
+
return build_client(config).create_page(space, title, body, parent_id=parent_id, representation=representation)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@translate_errors
|
|
60
|
+
def update_page(
|
|
61
|
+
config: ConfluenceConfig,
|
|
62
|
+
page_id: str,
|
|
63
|
+
title: str,
|
|
64
|
+
*,
|
|
65
|
+
body: str | None = None,
|
|
66
|
+
parent_id: str | None = None,
|
|
67
|
+
representation: str = "storage",
|
|
68
|
+
version_comment: str | None = None,
|
|
69
|
+
minor_edit: bool = False,
|
|
70
|
+
) -> Any:
|
|
71
|
+
"""Update a page. ``title`` is required by the API even when only the body
|
|
72
|
+
changes (pass the page's current title)."""
|
|
73
|
+
return build_client(config).update_page(
|
|
74
|
+
page_id,
|
|
75
|
+
title,
|
|
76
|
+
body=body,
|
|
77
|
+
parent_id=parent_id,
|
|
78
|
+
representation=representation,
|
|
79
|
+
minor_edit=minor_edit,
|
|
80
|
+
version_comment=version_comment,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@translate_errors
|
|
85
|
+
def delete_page(config: ConfluenceConfig, page_id: str, *, recursive: bool = False) -> dict[str, Any]:
|
|
86
|
+
"""Delete a page (and, with ``recursive``, its descendants)."""
|
|
87
|
+
build_client(config).remove_page(page_id, recursive=recursive)
|
|
88
|
+
return {"page_id": page_id, "deleted": True}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@translate_errors
|
|
92
|
+
def move_page(
|
|
93
|
+
config: ConfluenceConfig,
|
|
94
|
+
space: str,
|
|
95
|
+
page_id: str,
|
|
96
|
+
*,
|
|
97
|
+
target_id: str | None = None,
|
|
98
|
+
target_title: str | None = None,
|
|
99
|
+
position: str = "append",
|
|
100
|
+
) -> Any:
|
|
101
|
+
"""Move a page relative to a target (``append`` under it, or ``above``/``below``)."""
|
|
102
|
+
return build_client(config).move_page(space, page_id, target_id=target_id, target_title=target_title, position=position)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@translate_errors
|
|
106
|
+
def get_space_pages(config: ConfluenceConfig, space: str, *, start: int = 0, limit: int = 50) -> Any:
|
|
107
|
+
"""List pages in a space (one page of results)."""
|
|
108
|
+
return build_client(config).get_all_pages_from_space(space, start=start, limit=limit)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@translate_errors
|
|
112
|
+
def get_space(config: ConfluenceConfig, space_key: str) -> Any:
|
|
113
|
+
"""Fetch a space's metadata."""
|
|
114
|
+
return build_client(config).get_space(space_key)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""search.py — CQL content search."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from runspec_confluence_core.client import build_client, translate_errors
|
|
8
|
+
from runspec_confluence_core.config import ConfluenceConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@translate_errors
|
|
12
|
+
def search(config: ConfluenceConfig, cql: str, *, start: int = 0, limit: int = 25, expand: str | None = None) -> Any:
|
|
13
|
+
"""Search content with CQL (Confluence Query Language), e.g.
|
|
14
|
+
``type = page AND space = DOCS AND text ~ "onboarding"``. Returns one page."""
|
|
15
|
+
return build_client(config).cql(cql, start=start, limit=limit, expand=expand)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runspec-confluence-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pure-Python Confluence helpers (over atlassian-python-api) — the importable core behind runspec-confluence (no runspec dependency, no runnables)
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: atlassian-python-api>=3.41
|
|
7
|
+
Provides-Extra: dev
|
|
8
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
9
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
10
|
+
Requires-Dist: ruff==0.15.20; extra == 'dev'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
runspec_confluence_core/__init__.py,sha256=6AYUHa5uu8egbvEDnCIDLisaBfcyK3Q7W301xAo1Kvs,2007
|
|
2
|
+
runspec_confluence_core/client.py,sha256=5pevGx2_5icDJSYybFK0t8da8h4RiitFitrS6MKBeKw,2480
|
|
3
|
+
runspec_confluence_core/config.py,sha256=eSkolXkChGl_R2hTj0prDH7mpn6ynuzeSG992DswA-c,3922
|
|
4
|
+
runspec_confluence_core/content.py,sha256=ySC2lW_fDtveRAaCsh-MAzcW-uJIIVrUo2e1EP5yqPs,1521
|
|
5
|
+
runspec_confluence_core/errors.py,sha256=KmYNrBRV0ynA2IuCFk5pgYSXBZLDx4XwM0c87hRmnys,499
|
|
6
|
+
runspec_confluence_core/pages.py,sha256=vlGWUjVB9r3ZBy9bsVc1gTfkTjt7gGln_RDz_bq2ZZI,3689
|
|
7
|
+
runspec_confluence_core/search.py,sha256=JY351R3FMmbcIWcJ1sR1HbMGNNAQJopzczIleG2tahw,603
|
|
8
|
+
runspec_confluence_core-0.1.0.dist-info/METADATA,sha256=KUue8lh2ZTOuY28GC4HHazDvAG97r68L0MiRixTaulk,433
|
|
9
|
+
runspec_confluence_core-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
10
|
+
runspec_confluence_core-0.1.0.dist-info/RECORD,,
|