og-pilot 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.
- og_pilot-0.1.0/.gitignore +80 -0
- og_pilot-0.1.0/LICENSE +21 -0
- og_pilot-0.1.0/PKG-INFO +502 -0
- og_pilot-0.1.0/README.md +458 -0
- og_pilot-0.1.0/og_pilot/__init__.py +136 -0
- og_pilot-0.1.0/og_pilot/client.py +191 -0
- og_pilot-0.1.0/og_pilot/config.py +31 -0
- og_pilot-0.1.0/og_pilot/django/__init__.py +21 -0
- og_pilot-0.1.0/og_pilot/django/apps.py +37 -0
- og_pilot-0.1.0/og_pilot/django/management/__init__.py +1 -0
- og_pilot-0.1.0/og_pilot/django/management/commands/__init__.py +1 -0
- og_pilot-0.1.0/og_pilot/django/management/commands/og_pilot_check.py +66 -0
- og_pilot-0.1.0/og_pilot/django/templates/og_pilot/meta_tags.html +12 -0
- og_pilot-0.1.0/og_pilot/django/templatetags/__init__.py +1 -0
- og_pilot-0.1.0/og_pilot/django/templatetags/og_pilot_tags.py +109 -0
- og_pilot-0.1.0/og_pilot/exceptions.py +25 -0
- og_pilot-0.1.0/og_pilot/jwt_encoder.py +24 -0
- og_pilot-0.1.0/pyproject.toml +121 -0
- og_pilot-0.1.0/tests/__init__.py +1 -0
- og_pilot-0.1.0/tests/test_client.py +142 -0
- og_pilot-0.1.0/tests/test_config.py +65 -0
- og_pilot-0.1.0/tests/test_init.py +94 -0
- og_pilot-0.1.0/tests/test_jwt_encoder.py +53 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.nox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
*.py,cover
|
|
46
|
+
.hypothesis/
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
|
|
49
|
+
# Translations
|
|
50
|
+
*.mo
|
|
51
|
+
*.pot
|
|
52
|
+
|
|
53
|
+
# Environments
|
|
54
|
+
.env
|
|
55
|
+
.venv
|
|
56
|
+
env/
|
|
57
|
+
venv/
|
|
58
|
+
ENV/
|
|
59
|
+
env.bak/
|
|
60
|
+
venv.bak/
|
|
61
|
+
|
|
62
|
+
# IDE
|
|
63
|
+
.idea/
|
|
64
|
+
.vscode/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
67
|
+
*~
|
|
68
|
+
|
|
69
|
+
# mypy
|
|
70
|
+
.mypy_cache/
|
|
71
|
+
.dmypy.json
|
|
72
|
+
dmypy.json
|
|
73
|
+
|
|
74
|
+
# ruff
|
|
75
|
+
.ruff_cache/
|
|
76
|
+
|
|
77
|
+
# OS
|
|
78
|
+
.DS_Store
|
|
79
|
+
Thumbs.db
|
|
80
|
+
.venv/
|
og_pilot-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sunergos IT LLC
|
|
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.
|
og_pilot-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: og-pilot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the OG Pilot Open Graph image generator with Django integration
|
|
5
|
+
Project-URL: Homepage, https://ogpilot.com
|
|
6
|
+
Project-URL: Documentation, https://ogpilot.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/sunergos-ro/og-pilot-python
|
|
8
|
+
Project-URL: Issues, https://github.com/sunergos-ro/og-pilot-python/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/sunergos-ro/og-pilot-python/commits/main
|
|
10
|
+
Author-email: Sunergos IT LLC <office@sunergos.ro>, Raul Popadineti <raul@sunergos.ro>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: django,meta-tags,og-image,og-pilot,open-graph,seo,social-media
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Framework :: Django
|
|
17
|
+
Classifier: Framework :: Django :: 4.2
|
|
18
|
+
Classifier: Framework :: Django :: 5.0
|
|
19
|
+
Classifier: Framework :: Django :: 5.1
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Requires-Python: >=3.10
|
|
31
|
+
Requires-Dist: pyjwt>=2.0.0
|
|
32
|
+
Requires-Dist: requests>=2.25.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: django>=4.2; extra == 'dev'
|
|
35
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: responses>=0.23.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: types-requests>=2.31.0; extra == 'dev'
|
|
41
|
+
Provides-Extra: django
|
|
42
|
+
Requires-Dist: django>=4.2; extra == 'django'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# OG Pilot Python
|
|
46
|
+
|
|
47
|
+
A Python client for generating OG Pilot Open Graph images via signed JWTs, with first-class Django integration.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install og-pilot
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For Django integration:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install og-pilot[django]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Basic Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import og_pilot
|
|
67
|
+
|
|
68
|
+
# Configure globally (reads from OG_PILOT_API_KEY and OG_PILOT_DOMAIN env vars by default)
|
|
69
|
+
og_pilot.configure(
|
|
70
|
+
api_key="your-api-key",
|
|
71
|
+
domain="example.com"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Generate an image URL
|
|
75
|
+
image_url = og_pilot.create_image(
|
|
76
|
+
template="blog_post",
|
|
77
|
+
title="How to Build Amazing OG Images",
|
|
78
|
+
description="A complete guide to social media previews",
|
|
79
|
+
author_name="Jane Smith",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
print(image_url)
|
|
83
|
+
# https://ogpilot.com/api/v1/images?token=eyJ...
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Using Environment Variables
|
|
87
|
+
|
|
88
|
+
The SDK automatically reads from environment variables:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
export OG_PILOT_API_KEY="your-api-key"
|
|
92
|
+
export OG_PILOT_DOMAIN="example.com"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import og_pilot
|
|
97
|
+
|
|
98
|
+
# No configuration needed - uses env vars
|
|
99
|
+
url = og_pilot.create_image(title="My Page", template="default")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Cache Busting with `iat`
|
|
103
|
+
|
|
104
|
+
By default, OG Pilot caches images indefinitely. Use `iat` (issued at) to refresh the cache:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import time
|
|
108
|
+
from datetime import datetime
|
|
109
|
+
|
|
110
|
+
# Using Unix timestamp
|
|
111
|
+
url = og_pilot.create_image(
|
|
112
|
+
title="My Post",
|
|
113
|
+
template="blog",
|
|
114
|
+
iat=int(time.time()) # Changes daily
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Using datetime
|
|
118
|
+
url = og_pilot.create_image(
|
|
119
|
+
title="My Post",
|
|
120
|
+
template="blog",
|
|
121
|
+
iat=datetime.now()
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Get JSON Metadata
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
data = og_pilot.create_image(
|
|
129
|
+
title="Hello OG Pilot",
|
|
130
|
+
template="page",
|
|
131
|
+
json=True
|
|
132
|
+
)
|
|
133
|
+
print(data) # {"url": "...", "width": 1200, "height": 630, ...}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Custom Client Instance
|
|
137
|
+
|
|
138
|
+
For multiple configurations or dependency injection:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from og_pilot import create_client
|
|
142
|
+
|
|
143
|
+
client = create_client(
|
|
144
|
+
api_key="your-api-key",
|
|
145
|
+
domain="example.com",
|
|
146
|
+
open_timeout=10,
|
|
147
|
+
read_timeout=30,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
url = client.create_image({"template": "default", "title": "Hello"})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Django Integration
|
|
154
|
+
|
|
155
|
+
### 1. Add to Installed Apps
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# settings.py
|
|
159
|
+
INSTALLED_APPS = [
|
|
160
|
+
# ...
|
|
161
|
+
'og_pilot.django',
|
|
162
|
+
]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2. Configure Settings
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
# settings.py
|
|
169
|
+
|
|
170
|
+
# Option 1: Using settings dict
|
|
171
|
+
OG_PILOT = {
|
|
172
|
+
'API_KEY': 'your-api-key', # or use OG_PILOT_API_KEY env var
|
|
173
|
+
'DOMAIN': 'example.com', # or use OG_PILOT_DOMAIN env var
|
|
174
|
+
# Optional:
|
|
175
|
+
# 'BASE_URL': 'https://ogpilot.com',
|
|
176
|
+
# 'OPEN_TIMEOUT': 5,
|
|
177
|
+
# 'READ_TIMEOUT': 10,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# Option 2: Using environment variables (no settings needed)
|
|
181
|
+
# Just set OG_PILOT_API_KEY and OG_PILOT_DOMAIN
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 3. Verify Configuration
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
python manage.py og_pilot_check
|
|
188
|
+
python manage.py og_pilot_check --test # Also sends a test request
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 4. Use in Templates
|
|
192
|
+
|
|
193
|
+
```html
|
|
194
|
+
{% load og_pilot_tags %}
|
|
195
|
+
|
|
196
|
+
<!DOCTYPE html>
|
|
197
|
+
<html>
|
|
198
|
+
<head>
|
|
199
|
+
<!-- Option 1: Generate URL and use manually -->
|
|
200
|
+
{% og_pilot_image title=page.title template="blog_post" as og_image_url %}
|
|
201
|
+
<meta property="og:image" content="{{ og_image_url }}" />
|
|
202
|
+
<meta property="og:title" content="{{ page.title }}" />
|
|
203
|
+
|
|
204
|
+
<!-- Option 2: Simple tag (outputs URL directly) -->
|
|
205
|
+
<meta property="og:image" content="{% og_pilot_url title=page.title template='default' %}" />
|
|
206
|
+
|
|
207
|
+
<!-- Option 3: Complete meta tags (requires template) -->
|
|
208
|
+
{% og_pilot_meta_tags title=page.title description=page.description template="blog" %}
|
|
209
|
+
</head>
|
|
210
|
+
<body>
|
|
211
|
+
...
|
|
212
|
+
</body>
|
|
213
|
+
</html>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 5. Use in Views
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from django.shortcuts import render
|
|
220
|
+
import og_pilot
|
|
221
|
+
|
|
222
|
+
def blog_post(request, slug):
|
|
223
|
+
post = get_object_or_404(Post, slug=slug)
|
|
224
|
+
|
|
225
|
+
og_image_url = og_pilot.create_image(
|
|
226
|
+
template="blog_post",
|
|
227
|
+
title=post.title,
|
|
228
|
+
description=post.excerpt,
|
|
229
|
+
author_name=post.author.name,
|
|
230
|
+
publish_date=post.published_at.strftime("%Y-%m-%d"),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return render(request, 'blog/post.html', {
|
|
234
|
+
'post': post,
|
|
235
|
+
'og_image_url': og_image_url,
|
|
236
|
+
})
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Custom Meta Tags Template
|
|
240
|
+
|
|
241
|
+
Create `templates/og_pilot/meta_tags.html` in your project to customize the output of `{% og_pilot_meta_tags %}`:
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<!-- templates/og_pilot/meta_tags.html -->
|
|
245
|
+
<meta property="og:title" content="{{ title }}" />
|
|
246
|
+
<meta property="og:description" content="{{ description }}" />
|
|
247
|
+
<meta property="og:image" content="{{ image_url }}" />
|
|
248
|
+
<meta property="og:type" content="article" />
|
|
249
|
+
<meta property="og:site_name" content="{{ site_name }}" />
|
|
250
|
+
|
|
251
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
252
|
+
<meta name="twitter:title" content="{{ title }}" />
|
|
253
|
+
<meta name="twitter:description" content="{{ description }}" />
|
|
254
|
+
<meta name="twitter:image" content="{{ image_url }}" />
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Configuration Options
|
|
258
|
+
|
|
259
|
+
| Option | Environment Variable | Default | Description |
|
|
260
|
+
|--------|---------------------|---------|-------------|
|
|
261
|
+
| `api_key` | `OG_PILOT_API_KEY` | None | Your OG Pilot API key (required) |
|
|
262
|
+
| `domain` | `OG_PILOT_DOMAIN` | None | Your registered domain (required) |
|
|
263
|
+
| `base_url` | - | `https://ogpilot.com` | OG Pilot API URL |
|
|
264
|
+
| `open_timeout` | - | `5` | Connection timeout (seconds) |
|
|
265
|
+
| `read_timeout` | - | `10` | Read timeout (seconds) |
|
|
266
|
+
|
|
267
|
+
## Error Handling
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from og_pilot import create_image
|
|
271
|
+
from og_pilot.exceptions import ConfigurationError, RequestError
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
url = create_image(title="My Post", template="blog")
|
|
275
|
+
except ConfigurationError as e:
|
|
276
|
+
# Missing API key or domain
|
|
277
|
+
print(f"Configuration error: {e}")
|
|
278
|
+
except RequestError as e:
|
|
279
|
+
# API request failed
|
|
280
|
+
print(f"Request error: {e}")
|
|
281
|
+
if e.status_code:
|
|
282
|
+
print(f"Status code: {e.status_code}")
|
|
283
|
+
except ValueError as e:
|
|
284
|
+
# Missing required parameter (e.g., title)
|
|
285
|
+
print(f"Validation error: {e}")
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## API Reference
|
|
289
|
+
|
|
290
|
+
### Module-level Functions
|
|
291
|
+
|
|
292
|
+
- `og_pilot.configure(**kwargs)` - Configure the global client
|
|
293
|
+
- `og_pilot.reset_config()` - Reset to default configuration
|
|
294
|
+
- `og_pilot.get_config()` - Get the current configuration
|
|
295
|
+
- `og_pilot.client()` - Get a client using global config
|
|
296
|
+
- `og_pilot.create_client(**kwargs)` - Create a new client with custom config
|
|
297
|
+
- `og_pilot.create_image(params, *, json=False, iat=None, headers=None, **kwargs)` - Generate image URL
|
|
298
|
+
|
|
299
|
+
### Client Class
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
from og_pilot import Client, Configuration
|
|
303
|
+
|
|
304
|
+
config = Configuration(api_key="...", domain="...")
|
|
305
|
+
client = Client(config)
|
|
306
|
+
|
|
307
|
+
# Generate URL
|
|
308
|
+
url = client.create_image(
|
|
309
|
+
params={"template": "default", "title": "Hello"},
|
|
310
|
+
json_response=False, # Set True for JSON metadata
|
|
311
|
+
iat=None, # Optional cache busting timestamp
|
|
312
|
+
headers={}, # Optional additional headers
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Development
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# Clone the repository
|
|
320
|
+
git clone https://github.com/sunergos-ro/og-pilot-python.git
|
|
321
|
+
cd og-pilot-python
|
|
322
|
+
|
|
323
|
+
# Create virtual environment
|
|
324
|
+
python -m venv .venv
|
|
325
|
+
source .venv/bin/activate
|
|
326
|
+
|
|
327
|
+
# Install dev dependencies
|
|
328
|
+
pip install -e ".[dev]"
|
|
329
|
+
|
|
330
|
+
# Run tests
|
|
331
|
+
pytest
|
|
332
|
+
|
|
333
|
+
# Run linter
|
|
334
|
+
ruff check .
|
|
335
|
+
|
|
336
|
+
# Run type checker
|
|
337
|
+
mypy og_pilot
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
# Publishing to PyPI
|
|
343
|
+
|
|
344
|
+
This section explains how to publish the package to PyPI so users can install it with `pip install og-pilot`.
|
|
345
|
+
|
|
346
|
+
## Prerequisites
|
|
347
|
+
|
|
348
|
+
1. **Create PyPI Account**: Register at https://pypi.org/account/register/
|
|
349
|
+
|
|
350
|
+
2. **Create API Token**: Go to https://pypi.org/manage/account/token/ and create a token with "Upload packages" scope.
|
|
351
|
+
|
|
352
|
+
3. **Install Build Tools**:
|
|
353
|
+
```bash
|
|
354
|
+
pip install build twine
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Publishing Steps
|
|
358
|
+
|
|
359
|
+
### 1. Update Version
|
|
360
|
+
|
|
361
|
+
Edit `pyproject.toml` and `og_pilot/__init__.py` to update the version number:
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
# og_pilot/__init__.py
|
|
365
|
+
__version__ = "0.2.0" # New version
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
```toml
|
|
369
|
+
# pyproject.toml
|
|
370
|
+
[project]
|
|
371
|
+
version = "0.2.0"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### 2. Build the Package
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# Clean previous builds
|
|
378
|
+
rm -rf dist/ build/ *.egg-info
|
|
379
|
+
|
|
380
|
+
# Build source distribution and wheel
|
|
381
|
+
python -m build
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
This creates:
|
|
385
|
+
- `dist/og_pilot-0.1.0.tar.gz` (source distribution)
|
|
386
|
+
- `dist/og_pilot-0.1.0-py3-none-any.whl` (wheel)
|
|
387
|
+
|
|
388
|
+
### 3. Test on TestPyPI (Optional but Recommended)
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# Upload to TestPyPI first
|
|
392
|
+
twine upload --repository testpypi dist/*
|
|
393
|
+
|
|
394
|
+
# Test installation from TestPyPI
|
|
395
|
+
pip install --index-url https://test.pypi.org/simple/ og-pilot
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 4. Upload to PyPI
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
# Upload to production PyPI
|
|
402
|
+
twine upload dist/*
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
You'll be prompted for credentials:
|
|
406
|
+
- Username: `__token__`
|
|
407
|
+
- Password: Your PyPI API token (starts with `pypi-`)
|
|
408
|
+
|
|
409
|
+
### 5. Configure Credentials (Optional)
|
|
410
|
+
|
|
411
|
+
To avoid entering credentials each time, create `~/.pypirc`:
|
|
412
|
+
|
|
413
|
+
```ini
|
|
414
|
+
[distutils]
|
|
415
|
+
index-servers =
|
|
416
|
+
pypi
|
|
417
|
+
testpypi
|
|
418
|
+
|
|
419
|
+
[pypi]
|
|
420
|
+
username = __token__
|
|
421
|
+
password = pypi-YOUR-TOKEN-HERE
|
|
422
|
+
|
|
423
|
+
[testpypi]
|
|
424
|
+
username = __token__
|
|
425
|
+
password = pypi-YOUR-TESTPYPI-TOKEN-HERE
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Then secure it:
|
|
429
|
+
```bash
|
|
430
|
+
chmod 600 ~/.pypirc
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Automated Publishing with GitHub Actions
|
|
434
|
+
|
|
435
|
+
Create `.github/workflows/publish.yml`:
|
|
436
|
+
|
|
437
|
+
```yaml
|
|
438
|
+
name: Publish to PyPI
|
|
439
|
+
|
|
440
|
+
on:
|
|
441
|
+
release:
|
|
442
|
+
types: [published]
|
|
443
|
+
|
|
444
|
+
jobs:
|
|
445
|
+
publish:
|
|
446
|
+
runs-on: ubuntu-latest
|
|
447
|
+
environment: release
|
|
448
|
+
permissions:
|
|
449
|
+
id-token: write # Required for trusted publishing
|
|
450
|
+
|
|
451
|
+
steps:
|
|
452
|
+
- uses: actions/checkout@v4
|
|
453
|
+
|
|
454
|
+
- name: Set up Python
|
|
455
|
+
uses: actions/setup-python@v5
|
|
456
|
+
with:
|
|
457
|
+
python-version: '3.12'
|
|
458
|
+
|
|
459
|
+
- name: Install build dependencies
|
|
460
|
+
run: pip install build
|
|
461
|
+
|
|
462
|
+
- name: Build package
|
|
463
|
+
run: python -m build
|
|
464
|
+
|
|
465
|
+
- name: Publish to PyPI
|
|
466
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
467
|
+
# Uses trusted publishing - configure at pypi.org
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Setting Up Trusted Publishing
|
|
471
|
+
|
|
472
|
+
1. Go to your PyPI project: https://pypi.org/manage/project/og-pilot/settings/publishing/
|
|
473
|
+
2. Add a new publisher:
|
|
474
|
+
- Owner: `sunergos-ro`
|
|
475
|
+
- Repository: `og-pilot-python`
|
|
476
|
+
- Workflow: `publish.yml`
|
|
477
|
+
- Environment: `release`
|
|
478
|
+
|
|
479
|
+
## Version Numbering
|
|
480
|
+
|
|
481
|
+
Follow [Semantic Versioning](https://semver.org/):
|
|
482
|
+
- `MAJOR.MINOR.PATCH` (e.g., `1.2.3`)
|
|
483
|
+
- MAJOR: Breaking changes
|
|
484
|
+
- MINOR: New features (backward compatible)
|
|
485
|
+
- PATCH: Bug fixes (backward compatible)
|
|
486
|
+
|
|
487
|
+
## Release Checklist
|
|
488
|
+
|
|
489
|
+
- [ ] Update version in `pyproject.toml` and `og_pilot/__init__.py`
|
|
490
|
+
- [ ] Update CHANGELOG (if you have one)
|
|
491
|
+
- [ ] Run tests: `pytest`
|
|
492
|
+
- [ ] Run linter: `ruff check .`
|
|
493
|
+
- [ ] Run type checker: `mypy og_pilot`
|
|
494
|
+
- [ ] Build: `python -m build`
|
|
495
|
+
- [ ] Test locally: `pip install dist/*.whl`
|
|
496
|
+
- [ ] Upload to TestPyPI (optional)
|
|
497
|
+
- [ ] Upload to PyPI
|
|
498
|
+
- [ ] Create GitHub release with tag `v0.1.0`
|
|
499
|
+
|
|
500
|
+
## License
|
|
501
|
+
|
|
502
|
+
MIT License - see [LICENSE](LICENSE) for details.
|