postpeer 0.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.
@@ -0,0 +1,75 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v6
22
+ with:
23
+ version: "0.9.26"
24
+ python-version: ${{ matrix.python-version }}
25
+ enable-cache: true
26
+ - run: uv sync --frozen --extra dev
27
+ - run: uv run ruff check .
28
+ - run: uv run ruff format --check .
29
+ - run: uv run mypy
30
+ - run: uv run pytest
31
+
32
+ generated:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: pnpm/action-setup@v4
37
+ with:
38
+ version: 10.30.1
39
+ - uses: actions/setup-node@v4
40
+ with:
41
+ node-version: 22
42
+ cache: pnpm
43
+ - uses: astral-sh/setup-uv@v6
44
+ with:
45
+ version: "0.9.26"
46
+ python-version: "3.13"
47
+ enable-cache: true
48
+ - run: pnpm install --frozen-lockfile
49
+ - run: uv sync --frozen --extra dev
50
+ - run: pnpm generate
51
+ - name: Verify generated SDK is current
52
+ run: git diff --exit-code -- openapi.json src/postpeer/_generated src/postpeer/resources/_generated.py
53
+
54
+ package:
55
+ runs-on: ubuntu-latest
56
+ needs: [test, generated]
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: astral-sh/setup-uv@v6
60
+ with:
61
+ version: "0.9.26"
62
+ python-version: "3.13"
63
+ enable-cache: true
64
+ - run: uv sync --frozen --extra dev
65
+ - run: uv build
66
+ - run: uv run twine check dist/*
67
+ - name: Verify wheel import
68
+ run: |
69
+ uv venv --python 3.13 .wheel-venv
70
+ uv pip install --python .wheel-venv/bin/python dist/*.whl
71
+ .wheel-venv/bin/python -c "from postpeer import PostPeer, AsyncPostPeer"
72
+ - uses: actions/upload-artifact@v4
73
+ with:
74
+ name: python-distributions
75
+ path: dist/
@@ -0,0 +1,34 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ publish:
12
+ if: startsWith(github.event.release.tag_name, 'v')
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: pypi
16
+ url: https://pypi.org/project/postpeer/
17
+ permissions:
18
+ contents: read
19
+ id-token: write
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: astral-sh/setup-uv@v6
23
+ with:
24
+ version: "0.9.26"
25
+ python-version: "3.13"
26
+ enable-cache: true
27
+ - run: uv sync --frozen --extra dev
28
+ - run: uv build
29
+ - run: uv run twine check dist/*
30
+ - name: Verify tag matches package version
31
+ run: |
32
+ PACKAGE_VERSION=$(uv run python -c "from postpeer import __version__; print(__version__)")
33
+ test "v${PACKAGE_VERSION}" = "${{ github.event.release.tag_name }}"
34
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .mypy_cache/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ build/
10
+ dist/
11
+ node_modules/
12
+ .pnpm-store/
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Initial official PostPeer Python SDK.
6
+ - Synchronous and asynchronous HTTPX clients.
7
+ - OpenAPI-generated Pydantic models and resource methods.
postpeer-0.1.0/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 PostPeer
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: postpeer
3
+ Version: 0.1.0
4
+ Summary: The official Python SDK for the PostPeer API
5
+ Project-URL: Homepage, https://postpeer.dev
6
+ Project-URL: Documentation, https://docs.postpeer.dev
7
+ Project-URL: Repository, https://github.com/PostPeer-API/postpeer-python
8
+ Project-URL: Issues, https://github.com/PostPeer-API/postpeer-python/issues
9
+ Author: PostPeer
10
+ License: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: api,postpeer,sdk,social-media
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: httpx<1,>=0.27
24
+ Requires-Dist: pydantic[email]<3,>=2
25
+ Provides-Extra: dev
26
+ Requires-Dist: build>=1.2; extra == 'dev'
27
+ Requires-Dist: hatchling>=1.27; extra == 'dev'
28
+ Requires-Dist: mypy>=1.13; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=6; extra == 'dev'
31
+ Requires-Dist: pytest>=8; extra == 'dev'
32
+ Requires-Dist: respx>=0.22; extra == 'dev'
33
+ Requires-Dist: ruff>=0.9; extra == 'dev'
34
+ Requires-Dist: twine>=6; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # PostPeer Python SDK
38
+
39
+ The official Python SDK for the [PostPeer API](https://postpeer.dev), generated
40
+ from PostPeer's OpenAPI contract with [Hey API](https://heyapi.dev/).
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install postpeer
46
+ ```
47
+
48
+ Python 3.10 or newer is required.
49
+
50
+ ## Quick start
51
+
52
+ ```python
53
+ from postpeer import PostPeer
54
+
55
+ client = PostPeer() # Reads POSTPEER_API_KEY
56
+
57
+ post = client.posts.create(
58
+ content="Hello from PostPeer!",
59
+ platforms=[{"platform": "twitter", "accountId": "integration-id"}],
60
+ publish_now=True,
61
+ )
62
+
63
+ print(post.post_id)
64
+ client.close()
65
+ ```
66
+
67
+ The client can also be used as a context manager:
68
+
69
+ ```python
70
+ with PostPeer(api_key="your-access-key") as client:
71
+ profiles = client.profiles.list()
72
+ ```
73
+
74
+ ## Async usage
75
+
76
+ `AsyncPostPeer` has the same resources and method names:
77
+
78
+ ```python
79
+ import asyncio
80
+
81
+ from postpeer import AsyncPostPeer
82
+
83
+
84
+ async def main() -> None:
85
+ async with AsyncPostPeer() as client:
86
+ posts = await client.posts.list(status="scheduled")
87
+ print(posts)
88
+
89
+
90
+ asyncio.run(main())
91
+ ```
92
+
93
+ ## Configuration
94
+
95
+ ```python
96
+ import httpx
97
+
98
+ from postpeer import PostPeer
99
+
100
+ transport = httpx.Client(http2=True)
101
+ client = PostPeer(
102
+ api_key="your-access-key",
103
+ base_url="https://api.postpeer.dev",
104
+ timeout=60.0,
105
+ max_retries=2,
106
+ default_headers={"X-Application": "my-app"},
107
+ http_client=transport,
108
+ )
109
+ ```
110
+
111
+ Each SDK instance is isolated. An injected HTTPX client remains owned by the
112
+ caller and is not closed by the SDK.
113
+
114
+ ## Resources
115
+
116
+ The resource hierarchy matches the official Node.js SDK:
117
+
118
+ ```python
119
+ client.health.check()
120
+ client.health.verify_access_key()
121
+
122
+ client.connect.get_oauth_url(platform="linkedin")
123
+ client.connect.linkedin.get_selection(token="...")
124
+ client.connect.integrations.list()
125
+
126
+ client.profiles.create(name="Marketing")
127
+ client.apps.list()
128
+ client.notifications.list()
129
+ client.platforms.list()
130
+
131
+ client.posts.create(content="Hello", platforms=[...], publish_now=True)
132
+ client.posts.list(status="scheduled")
133
+ client.posts.get(post_id="...")
134
+ client.posts.delete(post_id="...")
135
+ client.posts.scheduled.list()
136
+ client.posts.scheduled.cancel(post_id="...")
137
+
138
+ client.media.upload(filename="image.png", mime_type="image/png")
139
+ client.analytics.get()
140
+ client.usage.get()
141
+ client.pinterest.get_boards(account_id="...")
142
+ client.tiktok.get_creator_info(account_id="...")
143
+ client.ai.write(description="A launch announcement", platforms=["linkedin"])
144
+ ```
145
+
146
+ Parameters use Python `snake_case`; the SDK serializes their OpenAPI aliases on
147
+ the wire. Responses are validated Pydantic v2 models. All generated models and
148
+ enums are available from `postpeer.types`.
149
+
150
+ ## Errors
151
+
152
+ ```python
153
+ from postpeer import NotFoundError, RateLimitError
154
+
155
+ try:
156
+ client.posts.get(post_id="missing")
157
+ except NotFoundError as error:
158
+ print(error.status, error.request_id, error.message)
159
+ except RateLimitError:
160
+ print("PostPeer rate limit reached")
161
+ ```
162
+
163
+ The SDK exports typed API, connection, timeout, and response-validation errors.
164
+
165
+ ## Retries and request options
166
+
167
+ GET, PUT, and DELETE requests retry transient connection failures, 408, 409,
168
+ 429, and 5xx responses by default. POST and PATCH are not automatically retried,
169
+ because replaying an ambiguous request could publish or create a resource twice.
170
+
171
+ Use `RequestOptions` for an explicit per-call override:
172
+
173
+ ```python
174
+ from postpeer import RequestOptions
175
+
176
+ client.posts.create(
177
+ content="Hello",
178
+ platforms=[...],
179
+ publish_now=True,
180
+ _request_options=RequestOptions(
181
+ timeout=30.0,
182
+ max_retries=2,
183
+ retry_non_idempotent=True,
184
+ ),
185
+ )
186
+ ```
187
+
188
+ ## Updating generated code
189
+
190
+ The OpenAPI specification and package releases are intentionally separate:
191
+
192
+ ```bash
193
+ pnpm spec:fetch
194
+ pnpm generate
195
+ uv run ruff format .
196
+ uv run ruff check .
197
+ uv run mypy
198
+ uv run pytest
199
+ ```
200
+
201
+ `openapi.json`, `src/postpeer/_generated`, and
202
+ `src/postpeer/resources/_generated.py` must be committed together. Generated
203
+ files must not be edited manually.
204
+
205
+ Hey API 0.0.24 currently generates the Pydantic models. A deterministic
206
+ PostPeer-owned generator emits the sync and async resources until Hey API's
207
+ Python runtime is mature enough to replace it.
208
+
209
+ ## Versioning
210
+
211
+ PostPeer uses conservative pre-1.0 versioning. Compatible additions remain in
212
+ `0.1.x`; a breaking SDK change moves to `0.2.0`; `1.0.0` is reserved for a
213
+ stable public contract.
@@ -0,0 +1,177 @@
1
+ # PostPeer Python SDK
2
+
3
+ The official Python SDK for the [PostPeer API](https://postpeer.dev), generated
4
+ from PostPeer's OpenAPI contract with [Hey API](https://heyapi.dev/).
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pip install postpeer
10
+ ```
11
+
12
+ Python 3.10 or newer is required.
13
+
14
+ ## Quick start
15
+
16
+ ```python
17
+ from postpeer import PostPeer
18
+
19
+ client = PostPeer() # Reads POSTPEER_API_KEY
20
+
21
+ post = client.posts.create(
22
+ content="Hello from PostPeer!",
23
+ platforms=[{"platform": "twitter", "accountId": "integration-id"}],
24
+ publish_now=True,
25
+ )
26
+
27
+ print(post.post_id)
28
+ client.close()
29
+ ```
30
+
31
+ The client can also be used as a context manager:
32
+
33
+ ```python
34
+ with PostPeer(api_key="your-access-key") as client:
35
+ profiles = client.profiles.list()
36
+ ```
37
+
38
+ ## Async usage
39
+
40
+ `AsyncPostPeer` has the same resources and method names:
41
+
42
+ ```python
43
+ import asyncio
44
+
45
+ from postpeer import AsyncPostPeer
46
+
47
+
48
+ async def main() -> None:
49
+ async with AsyncPostPeer() as client:
50
+ posts = await client.posts.list(status="scheduled")
51
+ print(posts)
52
+
53
+
54
+ asyncio.run(main())
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ```python
60
+ import httpx
61
+
62
+ from postpeer import PostPeer
63
+
64
+ transport = httpx.Client(http2=True)
65
+ client = PostPeer(
66
+ api_key="your-access-key",
67
+ base_url="https://api.postpeer.dev",
68
+ timeout=60.0,
69
+ max_retries=2,
70
+ default_headers={"X-Application": "my-app"},
71
+ http_client=transport,
72
+ )
73
+ ```
74
+
75
+ Each SDK instance is isolated. An injected HTTPX client remains owned by the
76
+ caller and is not closed by the SDK.
77
+
78
+ ## Resources
79
+
80
+ The resource hierarchy matches the official Node.js SDK:
81
+
82
+ ```python
83
+ client.health.check()
84
+ client.health.verify_access_key()
85
+
86
+ client.connect.get_oauth_url(platform="linkedin")
87
+ client.connect.linkedin.get_selection(token="...")
88
+ client.connect.integrations.list()
89
+
90
+ client.profiles.create(name="Marketing")
91
+ client.apps.list()
92
+ client.notifications.list()
93
+ client.platforms.list()
94
+
95
+ client.posts.create(content="Hello", platforms=[...], publish_now=True)
96
+ client.posts.list(status="scheduled")
97
+ client.posts.get(post_id="...")
98
+ client.posts.delete(post_id="...")
99
+ client.posts.scheduled.list()
100
+ client.posts.scheduled.cancel(post_id="...")
101
+
102
+ client.media.upload(filename="image.png", mime_type="image/png")
103
+ client.analytics.get()
104
+ client.usage.get()
105
+ client.pinterest.get_boards(account_id="...")
106
+ client.tiktok.get_creator_info(account_id="...")
107
+ client.ai.write(description="A launch announcement", platforms=["linkedin"])
108
+ ```
109
+
110
+ Parameters use Python `snake_case`; the SDK serializes their OpenAPI aliases on
111
+ the wire. Responses are validated Pydantic v2 models. All generated models and
112
+ enums are available from `postpeer.types`.
113
+
114
+ ## Errors
115
+
116
+ ```python
117
+ from postpeer import NotFoundError, RateLimitError
118
+
119
+ try:
120
+ client.posts.get(post_id="missing")
121
+ except NotFoundError as error:
122
+ print(error.status, error.request_id, error.message)
123
+ except RateLimitError:
124
+ print("PostPeer rate limit reached")
125
+ ```
126
+
127
+ The SDK exports typed API, connection, timeout, and response-validation errors.
128
+
129
+ ## Retries and request options
130
+
131
+ GET, PUT, and DELETE requests retry transient connection failures, 408, 409,
132
+ 429, and 5xx responses by default. POST and PATCH are not automatically retried,
133
+ because replaying an ambiguous request could publish or create a resource twice.
134
+
135
+ Use `RequestOptions` for an explicit per-call override:
136
+
137
+ ```python
138
+ from postpeer import RequestOptions
139
+
140
+ client.posts.create(
141
+ content="Hello",
142
+ platforms=[...],
143
+ publish_now=True,
144
+ _request_options=RequestOptions(
145
+ timeout=30.0,
146
+ max_retries=2,
147
+ retry_non_idempotent=True,
148
+ ),
149
+ )
150
+ ```
151
+
152
+ ## Updating generated code
153
+
154
+ The OpenAPI specification and package releases are intentionally separate:
155
+
156
+ ```bash
157
+ pnpm spec:fetch
158
+ pnpm generate
159
+ uv run ruff format .
160
+ uv run ruff check .
161
+ uv run mypy
162
+ uv run pytest
163
+ ```
164
+
165
+ `openapi.json`, `src/postpeer/_generated`, and
166
+ `src/postpeer/resources/_generated.py` must be committed together. Generated
167
+ files must not be edited manually.
168
+
169
+ Hey API 0.0.24 currently generates the Pydantic models. A deterministic
170
+ PostPeer-owned generator emits the sync and async resources until Hey API's
171
+ Python runtime is mature enough to replace it.
172
+
173
+ ## Versioning
174
+
175
+ PostPeer uses conservative pre-1.0 versioning. Compatible additions remain in
176
+ `0.1.x`; a breaking SDK change moves to `0.2.0`; `1.0.0` is reserved for a
177
+ stable public contract.
@@ -0,0 +1,8 @@
1
+ /** @type {import('@hey-api/openapi-python').UserConfig} */
2
+ export default {
3
+ input: './openapi.json',
4
+ output: {
5
+ path: './src/postpeer/_generated',
6
+ },
7
+ plugins: ['pydantic'],
8
+ };