semble-api 0.0.1__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 (36) hide show
  1. semble_api-0.0.1/.gitignore +13 -0
  2. semble_api-0.0.1/.pre-commit-config.yaml +23 -0
  3. semble_api-0.0.1/LICENSE +21 -0
  4. semble_api-0.0.1/PKG-INFO +165 -0
  5. semble_api-0.0.1/README.md +136 -0
  6. semble_api-0.0.1/justfile +12 -0
  7. semble_api-0.0.1/pyproject.toml +114 -0
  8. semble_api-0.0.1/scripts/roundtrip.py +43 -0
  9. semble_api-0.0.1/src/semble/__init__.py +33 -0
  10. semble_api-0.0.1/src/semble/_client.py +204 -0
  11. semble_api-0.0.1/src/semble/_exceptions.py +60 -0
  12. semble_api-0.0.1/src/semble/_utils.py +9 -0
  13. semble_api-0.0.1/src/semble/cli.py +158 -0
  14. semble_api-0.0.1/src/semble/mcp.py +42 -0
  15. semble_api-0.0.1/src/semble/py.typed +0 -0
  16. semble_api-0.0.1/src/semble/records.py +82 -0
  17. semble_api-0.0.1/src/semble/resources/__init__.py +8 -0
  18. semble_api-0.0.1/src/semble/resources/_base.py +14 -0
  19. semble_api-0.0.1/src/semble/resources/actors.py +35 -0
  20. semble_api-0.0.1/src/semble/resources/cards.py +344 -0
  21. semble_api-0.0.1/src/semble/resources/collections.py +447 -0
  22. semble_api-0.0.1/src/semble/resources/connections.py +199 -0
  23. semble_api-0.0.1/src/semble/resources/feeds.py +121 -0
  24. semble_api-0.0.1/src/semble/resources/graph.py +155 -0
  25. semble_api-0.0.1/src/semble/resources/notifications.py +87 -0
  26. semble_api-0.0.1/src/semble/resources/search.py +135 -0
  27. semble_api-0.0.1/src/semble/settings.py +26 -0
  28. semble_api-0.0.1/src/semble/types.py +268 -0
  29. semble_api-0.0.1/tests/__init__.py +0 -0
  30. semble_api-0.0.1/tests/conftest.py +54 -0
  31. semble_api-0.0.1/tests/test_cli.py +188 -0
  32. semble_api-0.0.1/tests/test_client.py +150 -0
  33. semble_api-0.0.1/tests/test_mcp.py +45 -0
  34. semble_api-0.0.1/tests/test_resources.py +168 -0
  35. semble_api-0.0.1/tests/test_types.py +81 -0
  36. semble_api-0.0.1/uv.lock +2037 -0
@@ -0,0 +1,13 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Environment variables
13
+ .env
@@ -0,0 +1,23 @@
1
+ fail_fast: false
2
+
3
+ repos:
4
+ - repo: https://github.com/abravalheri/validate-pyproject
5
+ rev: v0.24.1
6
+ hooks:
7
+ - id: validate-pyproject
8
+
9
+ - repo: https://github.com/astral-sh/ruff-pre-commit
10
+ rev: v0.12.1
11
+ hooks:
12
+ - id: ruff-check
13
+ args: [--fix, --exit-non-zero-on-fix]
14
+ - id: ruff-format
15
+
16
+ - repo: local
17
+ hooks:
18
+ - id: type-check
19
+ name: type check
20
+ entry: uv run ty check
21
+ language: system
22
+ types: [python]
23
+ pass_filenames: false
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zzstoatzz
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.
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.4
2
+ Name: semble-api
3
+ Version: 0.0.1
4
+ Summary: python client for the semble api
5
+ Author-email: zzstoatzz <thrast36@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: atproto,bookmarks,curation,knowledge-graph,semble
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
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: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: httpx2>=2.3.0
22
+ Requires-Dist: pydantic-settings>=2.14.1
23
+ Requires-Dist: pydantic>=2.7
24
+ Provides-Extra: cli
25
+ Requires-Dist: cyclopts>=4.17.0; extra == 'cli'
26
+ Provides-Extra: mcp
27
+ Requires-Dist: fastmcp[code-mode]>=3.4.2; extra == 'mcp'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # semble-api
31
+
32
+ python client for the [semble](https://semble.so) api — collaborative bookmarking and knowledge curation on [atproto](https://atproto.com).
33
+
34
+ built on [httpx2](https://github.com/pydantic/httpx2) and [pydantic](https://docs.pydantic.dev), with sync and async clients.
35
+
36
+ ## installation
37
+
38
+ ```bash
39
+ uv add semble-api
40
+ ```
41
+
42
+ ## quick start
43
+
44
+ create an api key at [semble.so/settings/api-keys](https://semble.so/settings/api-keys), then:
45
+
46
+ ```python
47
+ from semble import Semble
48
+
49
+ client = Semble() # reads SEMBLE_API_KEY from the environment or a local .env
50
+
51
+ # add a url to your library
52
+ result = client.cards.add_url("https://example.com", note="worth a read")
53
+
54
+ # search your cards
55
+ for card in client.cards.search("durable execution"):
56
+ print(card.url)
57
+
58
+ # semantic search across semble
59
+ for hit in client.search.semantic("agent memory", threshold=0.7):
60
+ print(hit.metadata.title, hit.url)
61
+ ```
62
+
63
+ async is the same surface:
64
+
65
+ ```python
66
+ from semble import AsyncSemble
67
+
68
+ async with AsyncSemble() as client:
69
+ profile = await client.actors.get_my_profile(include_stats=True)
70
+ feed = await client.feeds.get_following(limit=25)
71
+ ```
72
+
73
+ ## api surface
74
+
75
+ resources mirror the `network.cosmik.*` xrpc namespaces:
76
+
77
+ | namespace | what's there |
78
+ | --------------------- | ------------------------------------------------------------------ |
79
+ | `client.cards` | add/search/list urls and notes, metadata, library status |
80
+ | `client.collections` | create/update/delete collections, followers, contributors |
81
+ | `client.connections` | typed links between urls (supports, opposes, explains, ...) |
82
+ | `client.feeds` | global and following activity feeds |
83
+ | `client.notifications`| list, unread count, mark read |
84
+ | `client.search` | semantic search, similar urls, account search |
85
+ | `client.actors` | profiles |
86
+ | `client.graph` | follow/unfollow users and collections |
87
+
88
+ every endpoint not yet wrapped is reachable via the escape hatch:
89
+
90
+ ```python
91
+ client.get("network.cosmik.card.getLibraryStatus", {"url": "https://example.com"})
92
+ ```
93
+
94
+ `semble.records` has pydantic models for the raw `network.cosmik.*` pds records, if you're reading or writing them directly (e.g. with [pdsx](https://github.com/zzstoatzz/pdsx)).
95
+
96
+ ## configuration
97
+
98
+ settings come from explicit kwargs, then `SEMBLE_*` environment variables, then a local `.env` file (via [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)):
99
+
100
+ | setting | kwarg | default |
101
+ | ----------------- | ---------- | ----------------------------- |
102
+ | `SEMBLE_API_KEY` | `api_key` | unauthenticated (public reads work) |
103
+ | `SEMBLE_BASE_URL` | `base_url` | `https://api.semble.so/xrpc` |
104
+ | `SEMBLE_TIMEOUT` | `timeout` | `30.0` |
105
+
106
+ the api key is held as a pydantic `SecretStr`, so it won't leak into logs or reprs.
107
+
108
+ ## cli
109
+
110
+ a small [cyclopts](https://github.com/BrianPugh/cyclopts) cli ships as an extra:
111
+
112
+ ```bash
113
+ uv add 'semble-api[cli]'
114
+ # or run without installing
115
+ uvx --from 'semble-api[cli]' semble --help
116
+
117
+ semble whoami # auth sanity check
118
+ semble feed 10 --following # activity feeds
119
+ semble search "durable execution" # semantic search
120
+ semble library pdewey.com # anyone's library (or yours, with no handle)
121
+ semble add https://example.com --note "worth a read"
122
+ semble rm <card-id>
123
+ ```
124
+
125
+ output is machine-readable by default — lists are ndjson, single results are one json object, keys match the api's camelCase — so it pipes straight into jq or an agent. add `--pretty` to any command for human-formatted output:
126
+
127
+ ```bash
128
+ semble feed 25 | jq -r '.card.url'
129
+ semble search "agent memory" | jq -r '.metadata.title'
130
+ semble feed --pretty
131
+ ```
132
+
133
+ ## mcp server
134
+
135
+ the `mcp` extra ships a `semble-mcp` entry point that exposes this sdk to mcp clients via [fastmcp code mode](https://gofastmcp.com/servers/transforms/code-mode): three meta-tools (`search` / `get_schema` / `execute`) instead of one tool per endpoint, with model-written python composing sdk calls in a [monty](https://github.com/pydantic/monty) sandbox. intermediate results stay in the sandbox; only the final answer returns to the model's context.
136
+
137
+ ```bash
138
+ claude mcp add semble -- uvx --from 'semble-api[mcp]' semble-mcp
139
+ # or from a checkout
140
+ claude mcp add semble -- uv run --directory /path/to/this/repo semble-mcp
141
+ ```
142
+
143
+ auth comes from `SEMBLE_API_KEY` (environment or `.env`); without a key the server is limited to public reads.
144
+
145
+ ## examples
146
+
147
+ `scripts/roundtrip.py` exercises the write paths end to end (add url → note → collection → cleanup). it mutates your real account, so run it deliberately:
148
+
149
+ ```bash
150
+ uv run scripts/roundtrip.py
151
+ ```
152
+
153
+ ## development
154
+
155
+ ```bash
156
+ just test # pytest
157
+ just fmt # ruff format + check
158
+ just check # ty
159
+ ```
160
+
161
+ ## see also
162
+
163
+ - [semble api docs](https://docs.cosmik.network/semble-api)
164
+ - [@semble.so/api](https://npmx.dev/package/@semble.so/api) — official typescript client
165
+ - [tangled.org/pdewey.com/semble](https://tangled.org/pdewey.com/semble) — go client
@@ -0,0 +1,136 @@
1
+ # semble-api
2
+
3
+ python client for the [semble](https://semble.so) api — collaborative bookmarking and knowledge curation on [atproto](https://atproto.com).
4
+
5
+ built on [httpx2](https://github.com/pydantic/httpx2) and [pydantic](https://docs.pydantic.dev), with sync and async clients.
6
+
7
+ ## installation
8
+
9
+ ```bash
10
+ uv add semble-api
11
+ ```
12
+
13
+ ## quick start
14
+
15
+ create an api key at [semble.so/settings/api-keys](https://semble.so/settings/api-keys), then:
16
+
17
+ ```python
18
+ from semble import Semble
19
+
20
+ client = Semble() # reads SEMBLE_API_KEY from the environment or a local .env
21
+
22
+ # add a url to your library
23
+ result = client.cards.add_url("https://example.com", note="worth a read")
24
+
25
+ # search your cards
26
+ for card in client.cards.search("durable execution"):
27
+ print(card.url)
28
+
29
+ # semantic search across semble
30
+ for hit in client.search.semantic("agent memory", threshold=0.7):
31
+ print(hit.metadata.title, hit.url)
32
+ ```
33
+
34
+ async is the same surface:
35
+
36
+ ```python
37
+ from semble import AsyncSemble
38
+
39
+ async with AsyncSemble() as client:
40
+ profile = await client.actors.get_my_profile(include_stats=True)
41
+ feed = await client.feeds.get_following(limit=25)
42
+ ```
43
+
44
+ ## api surface
45
+
46
+ resources mirror the `network.cosmik.*` xrpc namespaces:
47
+
48
+ | namespace | what's there |
49
+ | --------------------- | ------------------------------------------------------------------ |
50
+ | `client.cards` | add/search/list urls and notes, metadata, library status |
51
+ | `client.collections` | create/update/delete collections, followers, contributors |
52
+ | `client.connections` | typed links between urls (supports, opposes, explains, ...) |
53
+ | `client.feeds` | global and following activity feeds |
54
+ | `client.notifications`| list, unread count, mark read |
55
+ | `client.search` | semantic search, similar urls, account search |
56
+ | `client.actors` | profiles |
57
+ | `client.graph` | follow/unfollow users and collections |
58
+
59
+ every endpoint not yet wrapped is reachable via the escape hatch:
60
+
61
+ ```python
62
+ client.get("network.cosmik.card.getLibraryStatus", {"url": "https://example.com"})
63
+ ```
64
+
65
+ `semble.records` has pydantic models for the raw `network.cosmik.*` pds records, if you're reading or writing them directly (e.g. with [pdsx](https://github.com/zzstoatzz/pdsx)).
66
+
67
+ ## configuration
68
+
69
+ settings come from explicit kwargs, then `SEMBLE_*` environment variables, then a local `.env` file (via [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)):
70
+
71
+ | setting | kwarg | default |
72
+ | ----------------- | ---------- | ----------------------------- |
73
+ | `SEMBLE_API_KEY` | `api_key` | unauthenticated (public reads work) |
74
+ | `SEMBLE_BASE_URL` | `base_url` | `https://api.semble.so/xrpc` |
75
+ | `SEMBLE_TIMEOUT` | `timeout` | `30.0` |
76
+
77
+ the api key is held as a pydantic `SecretStr`, so it won't leak into logs or reprs.
78
+
79
+ ## cli
80
+
81
+ a small [cyclopts](https://github.com/BrianPugh/cyclopts) cli ships as an extra:
82
+
83
+ ```bash
84
+ uv add 'semble-api[cli]'
85
+ # or run without installing
86
+ uvx --from 'semble-api[cli]' semble --help
87
+
88
+ semble whoami # auth sanity check
89
+ semble feed 10 --following # activity feeds
90
+ semble search "durable execution" # semantic search
91
+ semble library pdewey.com # anyone's library (or yours, with no handle)
92
+ semble add https://example.com --note "worth a read"
93
+ semble rm <card-id>
94
+ ```
95
+
96
+ output is machine-readable by default — lists are ndjson, single results are one json object, keys match the api's camelCase — so it pipes straight into jq or an agent. add `--pretty` to any command for human-formatted output:
97
+
98
+ ```bash
99
+ semble feed 25 | jq -r '.card.url'
100
+ semble search "agent memory" | jq -r '.metadata.title'
101
+ semble feed --pretty
102
+ ```
103
+
104
+ ## mcp server
105
+
106
+ the `mcp` extra ships a `semble-mcp` entry point that exposes this sdk to mcp clients via [fastmcp code mode](https://gofastmcp.com/servers/transforms/code-mode): three meta-tools (`search` / `get_schema` / `execute`) instead of one tool per endpoint, with model-written python composing sdk calls in a [monty](https://github.com/pydantic/monty) sandbox. intermediate results stay in the sandbox; only the final answer returns to the model's context.
107
+
108
+ ```bash
109
+ claude mcp add semble -- uvx --from 'semble-api[mcp]' semble-mcp
110
+ # or from a checkout
111
+ claude mcp add semble -- uv run --directory /path/to/this/repo semble-mcp
112
+ ```
113
+
114
+ auth comes from `SEMBLE_API_KEY` (environment or `.env`); without a key the server is limited to public reads.
115
+
116
+ ## examples
117
+
118
+ `scripts/roundtrip.py` exercises the write paths end to end (add url → note → collection → cleanup). it mutates your real account, so run it deliberately:
119
+
120
+ ```bash
121
+ uv run scripts/roundtrip.py
122
+ ```
123
+
124
+ ## development
125
+
126
+ ```bash
127
+ just test # pytest
128
+ just fmt # ruff format + check
129
+ just check # ty
130
+ ```
131
+
132
+ ## see also
133
+
134
+ - [semble api docs](https://docs.cosmik.network/semble-api)
135
+ - [@semble.so/api](https://npmx.dev/package/@semble.so/api) — official typescript client
136
+ - [tangled.org/pdewey.com/semble](https://tangled.org/pdewey.com/semble) — go client
@@ -0,0 +1,12 @@
1
+ # run tests
2
+ test:
3
+ uv run pytest tests/ -x
4
+
5
+ # format and lint
6
+ fmt:
7
+ uv run ruff format src/ tests/
8
+ uv run ruff check src/ tests/ --fix
9
+
10
+ # type check
11
+ check:
12
+ uv run ty check
@@ -0,0 +1,114 @@
1
+ [project]
2
+ name = "semble-api"
3
+ dynamic = ["version"]
4
+ description = "python client for the semble api"
5
+ readme = "README.md"
6
+ authors = [{ name = "zzstoatzz", email = "thrast36@gmail.com" }]
7
+ requires-python = ">=3.10"
8
+ license = "MIT"
9
+
10
+ keywords = ["semble", "atproto", "bookmarks", "curation", "knowledge-graph"]
11
+
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ "Typing :: Typed",
24
+ ]
25
+
26
+ dependencies = [
27
+ "httpx2>=2.3.0",
28
+ "pydantic>=2.7",
29
+ "pydantic-settings>=2.14.1",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ cli = [
34
+ "cyclopts>=4.17.0",
35
+ ]
36
+ mcp = [
37
+ "fastmcp[code-mode]>=3.4.2",
38
+ ]
39
+
40
+ [project.scripts]
41
+ semble = "semble.cli:main"
42
+ semble-mcp = "semble.mcp:main"
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "pytest>=8.3.0",
47
+ "pytest-asyncio>=0.25.0",
48
+ "pytest-sugar",
49
+ "ruff>=0.12.0",
50
+ "prek>=0.2.0",
51
+ "ty>=0.0.1a25",
52
+ "cyclopts>=4.17.0",
53
+ "fastmcp[code-mode]>=3.4.2",
54
+ ]
55
+
56
+ [build-system]
57
+ requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
58
+ build-backend = "hatchling.build"
59
+
60
+ [tool.hatch.build.targets.wheel]
61
+ packages = ["src/semble"]
62
+
63
+ [tool.hatch.version]
64
+ source = "uv-dynamic-versioning"
65
+
66
+ [tool.uv-dynamic-versioning]
67
+ vcs = "git"
68
+ style = "pep440"
69
+ bump = true
70
+ fallback-version = "0.0.0"
71
+
72
+ [tool.pytest.ini_options]
73
+ asyncio_mode = "auto"
74
+ asyncio_default_fixture_loop_scope = "function"
75
+ testpaths = ["tests"]
76
+ python_files = ["test_*.py", "*_test.py"]
77
+ python_classes = ["Test*"]
78
+ python_functions = ["test_*"]
79
+
80
+ [tool.ruff.lint]
81
+ fixable = ["ALL"]
82
+ ignore = [
83
+ "COM812",
84
+ "PLR0913", # Too many arguments
85
+ "SIM102", # Dont require combining if statements
86
+ "ANN401", # Any is allowed where it's the honest type (escape hatches)
87
+ ]
88
+ extend-select = [
89
+ "ANN", # flake8-annotations: require complete signatures
90
+ "B", # flake8-bugbear
91
+ "C4", # flake8-comprehensions
92
+ "I", # isort
93
+ "PIE", # flake8-pie
94
+ "RUF", # Ruff-specific
95
+ "SIM", # flake8-simplify
96
+ "UP", # pyupgrade
97
+ ]
98
+
99
+ [tool.ruff.lint.per-file-ignores]
100
+ "__init__.py" = ["F401", "I001"]
101
+ "tests/**/*.py" = ["S101"] # Allow assert in tests
102
+
103
+ [tool.ty.src]
104
+ include = ["src", "tests"]
105
+ exclude = [
106
+ "**/node_modules",
107
+ "**/__pycache__",
108
+ ".venv",
109
+ ".git",
110
+ "dist",
111
+ ]
112
+
113
+ [tool.ty.environment]
114
+ python-version = "3.10"
@@ -0,0 +1,43 @@
1
+ """exercise the write paths end to end, cleaning up after itself.
2
+
3
+ WARNING: this writes real records to your semble account (and pds) before
4
+ removing them. run it deliberately:
5
+
6
+ uv run scripts/roundtrip.py
7
+ """
8
+
9
+ from semble import Semble
10
+
11
+ URL = "https://example.com"
12
+
13
+ with Semble() as client:
14
+ print("adding url to library...")
15
+ added = client.cards.add_url(URL, note="semble-api roundtrip test")
16
+ print(f" url card: {added.url_card_id}, note card: {added.note_card_id}")
17
+
18
+ card = client.cards.get(added.url_card_id)
19
+ print(f" fetched: {card.url} (in library: {card.url_in_library})")
20
+
21
+ print("creating collection...")
22
+ created = client.collections.create(
23
+ "semble-api roundtrip",
24
+ description="temporary — created by scripts/roundtrip.py",
25
+ )
26
+ collection_id = created.collection_id
27
+ print(f" collection: {collection_id}")
28
+
29
+ print("adding card to collection...")
30
+ client.cards.update_url_associations(
31
+ added.url_card_id, add_to_collections=[collection_id]
32
+ )
33
+ detail = client.collections.get(collection_id)
34
+ in_collection = [c.id for c in detail.url_cards or []]
35
+ print(f" collection now has: {in_collection}")
36
+
37
+ print("updating note...")
38
+ client.cards.update_note(added.note_card_id, "updated by roundtrip")
39
+
40
+ print("cleaning up...")
41
+ client.collections.delete(collection_id)
42
+ client.cards.remove_from_library(added.url_card_id)
43
+ print("done — collection deleted, card removed")
@@ -0,0 +1,33 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ from semble._client import AsyncSemble, Semble
4
+ from semble.settings import DEFAULT_BASE_URL, SembleSettings
5
+ from semble._exceptions import (
6
+ APIStatusError,
7
+ AuthenticationError,
8
+ NotFoundError,
9
+ PermissionDeniedError,
10
+ RateLimitError,
11
+ SembleError,
12
+ ServerError,
13
+ )
14
+
15
+ try:
16
+ __version__ = version("semble-api")
17
+ except PackageNotFoundError:
18
+ __version__ = "0.0.0"
19
+
20
+ __all__ = [
21
+ "DEFAULT_BASE_URL",
22
+ "APIStatusError",
23
+ "AsyncSemble",
24
+ "AuthenticationError",
25
+ "NotFoundError",
26
+ "PermissionDeniedError",
27
+ "RateLimitError",
28
+ "Semble",
29
+ "SembleError",
30
+ "SembleSettings",
31
+ "ServerError",
32
+ "__version__",
33
+ ]