templatefox 1.0.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.
templatefox/rest.py ADDED
@@ -0,0 +1,264 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ TemplateFox API
5
+
6
+ Generate PDFs from HTML templates via API. Design once, generate thousands.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Contact: support@pdftemplateapi.com
10
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
+
12
+ Do not edit the class manually.
13
+ """ # noqa: E501
14
+
15
+
16
+ import io
17
+ import json
18
+ import re
19
+ import ssl
20
+
21
+ import urllib3
22
+
23
+ from templatefox.exceptions import ApiException, ApiValueError
24
+
25
+ SUPPORTED_SOCKS_PROXIES = {"socks5", "socks5h", "socks4", "socks4a"}
26
+ RESTResponseType = urllib3.HTTPResponse
27
+
28
+
29
+ def is_socks_proxy_url(url):
30
+ if url is None:
31
+ return False
32
+ split_section = url.split("://")
33
+ if len(split_section) < 2:
34
+ return False
35
+ else:
36
+ return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES
37
+
38
+
39
+ class RESTResponse(io.IOBase):
40
+
41
+ def __init__(self, resp) -> None:
42
+ self.response = resp
43
+ self.status = resp.status
44
+ self.reason = resp.reason
45
+ self.data = None
46
+
47
+ def read(self):
48
+ if self.data is None:
49
+ self.data = self.response.data
50
+ return self.data
51
+
52
+ @property
53
+ def headers(self):
54
+ """Returns a dictionary of response headers."""
55
+ return self.response.headers
56
+
57
+ def getheaders(self):
58
+ """Returns a dictionary of the response headers; use ``headers`` instead."""
59
+ return self.response.headers
60
+
61
+ def getheader(self, name, default=None):
62
+ """Returns a given response header; use ``headers.get()`` instead."""
63
+ return self.response.headers.get(name, default)
64
+
65
+
66
+ class RESTClientObject:
67
+
68
+ def __init__(self, configuration) -> None:
69
+ # urllib3.PoolManager will pass all kw parameters to connectionpool
70
+ # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
71
+ # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
72
+ # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
73
+
74
+ # cert_reqs
75
+ if configuration.verify_ssl:
76
+ cert_reqs = ssl.CERT_REQUIRED
77
+ else:
78
+ cert_reqs = ssl.CERT_NONE
79
+
80
+ pool_args = {
81
+ "cert_reqs": cert_reqs,
82
+ "ca_certs": configuration.ssl_ca_cert,
83
+ "cert_file": configuration.cert_file,
84
+ "key_file": configuration.key_file,
85
+ "ca_cert_data": configuration.ca_cert_data,
86
+ }
87
+ if configuration.assert_hostname is not None:
88
+ pool_args['assert_hostname'] = (
89
+ configuration.assert_hostname
90
+ )
91
+
92
+ if configuration.retries is not None:
93
+ pool_args['retries'] = configuration.retries
94
+
95
+ if configuration.tls_server_name:
96
+ pool_args['server_hostname'] = configuration.tls_server_name
97
+
98
+
99
+ if configuration.socket_options is not None:
100
+ pool_args['socket_options'] = configuration.socket_options
101
+
102
+ if configuration.connection_pool_maxsize is not None:
103
+ pool_args['maxsize'] = configuration.connection_pool_maxsize
104
+
105
+ # https pool manager
106
+ self.pool_manager: urllib3.PoolManager
107
+
108
+ if configuration.proxy:
109
+ if is_socks_proxy_url(configuration.proxy):
110
+ from urllib3.contrib.socks import SOCKSProxyManager
111
+ pool_args["proxy_url"] = configuration.proxy
112
+ pool_args["headers"] = configuration.proxy_headers
113
+ self.pool_manager = SOCKSProxyManager(**pool_args)
114
+ else:
115
+ pool_args["proxy_url"] = configuration.proxy
116
+ pool_args["proxy_headers"] = configuration.proxy_headers
117
+ self.pool_manager = urllib3.ProxyManager(**pool_args)
118
+ else:
119
+ self.pool_manager = urllib3.PoolManager(**pool_args)
120
+
121
+ def request(
122
+ self,
123
+ method,
124
+ url,
125
+ headers=None,
126
+ body=None,
127
+ post_params=None,
128
+ _request_timeout=None
129
+ ):
130
+ """Perform requests.
131
+
132
+ :param method: http request method
133
+ :param url: http request url
134
+ :param headers: http request headers
135
+ :param body: request json body, for `application/json`
136
+ :param post_params: request post parameters,
137
+ `application/x-www-form-urlencoded`
138
+ and `multipart/form-data`
139
+ :param _request_timeout: timeout setting for this request. If one
140
+ number provided, it will be total request
141
+ timeout. It can also be a pair (tuple) of
142
+ (connection, read) timeouts.
143
+ """
144
+ method = method.upper()
145
+ assert method in [
146
+ 'GET',
147
+ 'HEAD',
148
+ 'DELETE',
149
+ 'POST',
150
+ 'PUT',
151
+ 'PATCH',
152
+ 'OPTIONS'
153
+ ]
154
+
155
+ if post_params and body:
156
+ raise ApiValueError(
157
+ "body parameter cannot be used with post_params parameter."
158
+ )
159
+
160
+ post_params = post_params or {}
161
+ headers = headers or {}
162
+
163
+ timeout = None
164
+ if _request_timeout:
165
+ if isinstance(_request_timeout, (int, float)):
166
+ timeout = urllib3.Timeout(total=_request_timeout)
167
+ elif (
168
+ isinstance(_request_timeout, tuple)
169
+ and len(_request_timeout) == 2
170
+ ):
171
+ timeout = urllib3.Timeout(
172
+ connect=_request_timeout[0],
173
+ read=_request_timeout[1]
174
+ )
175
+
176
+ try:
177
+ # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
178
+ if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
179
+
180
+ # no content type provided or payload is json
181
+ content_type = headers.get('Content-Type')
182
+ if (
183
+ not content_type
184
+ or re.search('json', content_type, re.IGNORECASE)
185
+ ):
186
+ request_body = None
187
+ if body is not None:
188
+ request_body = json.dumps(body)
189
+ r = self.pool_manager.request(
190
+ method,
191
+ url,
192
+ body=request_body,
193
+ timeout=timeout,
194
+ headers=headers,
195
+ preload_content=False
196
+ )
197
+ elif content_type == 'application/x-www-form-urlencoded':
198
+ r = self.pool_manager.request(
199
+ method,
200
+ url,
201
+ fields=post_params,
202
+ encode_multipart=False,
203
+ timeout=timeout,
204
+ headers=headers,
205
+ preload_content=False
206
+ )
207
+ elif content_type == 'multipart/form-data':
208
+ # must del headers['Content-Type'], or the correct
209
+ # Content-Type which generated by urllib3 will be
210
+ # overwritten.
211
+ del headers['Content-Type']
212
+ # Ensures that dict objects are serialized
213
+ post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params]
214
+ r = self.pool_manager.request(
215
+ method,
216
+ url,
217
+ fields=post_params,
218
+ encode_multipart=True,
219
+ timeout=timeout,
220
+ headers=headers,
221
+ preload_content=False
222
+ )
223
+ # Pass a `string` parameter directly in the body to support
224
+ # other content types than JSON when `body` argument is
225
+ # provided in serialized form.
226
+ elif isinstance(body, str) or isinstance(body, bytes):
227
+ r = self.pool_manager.request(
228
+ method,
229
+ url,
230
+ body=body,
231
+ timeout=timeout,
232
+ headers=headers,
233
+ preload_content=False
234
+ )
235
+ elif headers['Content-Type'].startswith('text/') and isinstance(body, bool):
236
+ request_body = "true" if body else "false"
237
+ r = self.pool_manager.request(
238
+ method,
239
+ url,
240
+ body=request_body,
241
+ preload_content=False,
242
+ timeout=timeout,
243
+ headers=headers)
244
+ else:
245
+ # Cannot generate the request from given parameters
246
+ msg = """Cannot prepare a request message for provided
247
+ arguments. Please check that your arguments match
248
+ declared content type."""
249
+ raise ApiException(status=0, reason=msg)
250
+ # For `GET`, `HEAD`
251
+ else:
252
+ r = self.pool_manager.request(
253
+ method,
254
+ url,
255
+ fields={},
256
+ timeout=timeout,
257
+ headers=headers,
258
+ preload_content=False
259
+ )
260
+ except urllib3.exceptions.SSLError as e:
261
+ msg = "\n".join([type(e).__name__, str(e)])
262
+ raise ApiException(status=0, reason=msg)
263
+
264
+ return RESTResponse(r)
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: templatefox
3
+ Version: 1.0.0
4
+ Summary: Official TemplateFox Python SDK - Generate PDFs from HTML templates
5
+ Home-page: https://github.com/TemplateFoxPDF/pythonsdk
6
+ Author: TemplateFox
7
+ Author-email: TemplateFox <support@pdftemplateapi.com>
8
+ License: MIT
9
+ Project-URL: Repository, https://github.com/TemplateFoxPDF/pythonsdk
10
+ Keywords: OpenAPI,OpenAPI-Generator,TemplateFox API
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: urllib3<3.0.0,>=2.1.0
15
+ Requires-Dist: python-dateutil>=2.8.2
16
+ Requires-Dist: pydantic>=2
17
+ Requires-Dist: typing-extensions>=4.7.1
18
+ Dynamic: author
19
+ Dynamic: home-page
20
+ Dynamic: license-file
21
+
22
+ # TemplateFox Python SDK
23
+
24
+ Official Python SDK for [TemplateFox](https://pdftemplateapi.com) - Generate PDFs from HTML templates via API.
25
+
26
+ [![PyPI version](https://badge.fury.io/py/templatefox.svg)](https://pypi.org/project/templatefox/)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install templatefox
33
+ ```
34
+
35
+ Or with poetry:
36
+
37
+ ```bash
38
+ poetry add templatefox
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from templatefox import ApiClient, Configuration
45
+ from templatefox.api import PDFApi
46
+ from templatefox.models import CreatePdfRequest
47
+
48
+ # Initialize the client
49
+ config = Configuration()
50
+ config.api_key['ApiKeyAuth'] = 'your-api-key'
51
+
52
+ with ApiClient(config) as client:
53
+ api = PDFApi(client)
54
+
55
+ # Generate a PDF
56
+ response = api.create_pdf(
57
+ CreatePdfRequest(
58
+ template_id='YOUR_TEMPLATE_ID',
59
+ data={
60
+ 'name': 'John Doe',
61
+ 'invoice_number': 'INV-001',
62
+ 'total_amount': 150.00,
63
+ }
64
+ )
65
+ )
66
+
67
+ print(f'PDF URL: {response.url}')
68
+ print(f'Credits remaining: {response.credits_remaining}')
69
+ ```
70
+
71
+ ## Features
72
+
73
+ - **Template-based PDF generation** - Create templates with dynamic variables, generate PDFs with your data
74
+ - **Multiple export options** - Get a signed URL (default) or raw binary PDF
75
+ - **S3 integration** - Upload generated PDFs directly to your own S3-compatible storage
76
+ - **Type hints** - Full type annotations for IDE support
77
+
78
+ ## API Methods
79
+
80
+ ### PDF Generation
81
+
82
+ ```python
83
+ from templatefox.models import CreatePdfRequest
84
+
85
+ # Generate PDF and get URL
86
+ response = api.create_pdf(
87
+ CreatePdfRequest(
88
+ template_id='TEMPLATE_ID',
89
+ data={'name': 'John Doe'},
90
+ export_type='url', # 'url' or 'binary'
91
+ expiration=86400, # URL expiration in seconds (default: 24h)
92
+ filename='invoice-001' # Custom filename
93
+ )
94
+ )
95
+ ```
96
+
97
+ ### Templates
98
+
99
+ ```python
100
+ from templatefox.api import TemplatesApi
101
+
102
+ templates_api = TemplatesApi(client)
103
+
104
+ # List all templates
105
+ templates = templates_api.list_templates()
106
+ for template in templates.templates:
107
+ print(f'{template.id}: {template.name}')
108
+
109
+ # Get template fields
110
+ fields = templates_api.get_template_fields(template_id='TEMPLATE_ID')
111
+ for field in fields:
112
+ print(f'{field.key}: {field.type} (required: {field.required})')
113
+ ```
114
+
115
+ ### Account
116
+
117
+ ```python
118
+ from templatefox.api import AccountApi
119
+
120
+ account_api = AccountApi(client)
121
+
122
+ # Get account info
123
+ account = account_api.get_account()
124
+ print(f'Credits: {account.credits}')
125
+ print(f'Email: {account.email}')
126
+
127
+ # List transactions
128
+ transactions = account_api.list_transactions(limit=100, offset=0)
129
+ for tx in transactions.transactions:
130
+ print(f'{tx.transaction_type}: {tx.credits} credits')
131
+ ```
132
+
133
+ ### S3 Integration
134
+
135
+ ```python
136
+ from templatefox.api import IntegrationsApi
137
+ from templatefox.models import S3ConfigRequest
138
+
139
+ integrations_api = IntegrationsApi(client)
140
+
141
+ # Save S3 configuration
142
+ integrations_api.save_s3_config(
143
+ S3ConfigRequest(
144
+ endpoint_url='https://s3.amazonaws.com',
145
+ access_key_id='AKIAIOSFODNN7EXAMPLE',
146
+ secret_access_key='your-secret-key',
147
+ bucket_name='my-pdf-bucket',
148
+ default_prefix='generated/pdfs/'
149
+ )
150
+ )
151
+
152
+ # Test connection
153
+ test = integrations_api.test_s3_connection()
154
+ print(f'Connection: {"OK" if test.success else "Failed"}')
155
+ ```
156
+
157
+ ## Configuration
158
+
159
+ ```python
160
+ from templatefox import Configuration
161
+
162
+ config = Configuration(
163
+ host='https://api.pdftemplateapi.com', # Default API URL
164
+ )
165
+ config.api_key['ApiKeyAuth'] = 'your-api-key'
166
+
167
+ # Or use environment variable
168
+ import os
169
+ config.api_key['ApiKeyAuth'] = os.environ.get('TEMPLATEFOX_API_KEY')
170
+ ```
171
+
172
+ ## Error Handling
173
+
174
+ ```python
175
+ from templatefox.exceptions import ApiException
176
+
177
+ try:
178
+ response = api.create_pdf(CreatePdfRequest(...))
179
+ except ApiException as e:
180
+ if e.status == 402:
181
+ print('Insufficient credits')
182
+ elif e.status == 403:
183
+ print('Access denied - check your API key')
184
+ elif e.status == 404:
185
+ print('Template not found')
186
+ else:
187
+ print(f'Error: {e.reason}')
188
+ ```
189
+
190
+ ## Async Support
191
+
192
+ ```python
193
+ import asyncio
194
+ from templatefox import ApiClient, Configuration
195
+ from templatefox.api import PDFApi
196
+ from templatefox.models import CreatePdfRequest
197
+
198
+ async def generate_pdfs():
199
+ config = Configuration()
200
+ config.api_key['ApiKeyAuth'] = 'your-api-key'
201
+
202
+ async with ApiClient(config) as client:
203
+ api = PDFApi(client)
204
+ # Use async methods
205
+ response = await api.create_pdf(
206
+ CreatePdfRequest(template_id='...', data={...})
207
+ )
208
+
209
+ asyncio.run(generate_pdfs())
210
+ ```
211
+
212
+ ## Documentation
213
+
214
+ - [API Documentation](https://pdftemplateapi.com/docs)
215
+ - [Swagger UI](https://api.pdftemplateapi.com/docs)
216
+ - [Dashboard](https://pdftemplateapi.com/dashboard)
217
+
218
+ ## Support
219
+
220
+ - Email: support@pdftemplateapi.com
221
+ - Issues: [GitHub Issues](https://github.com/TemplateFoxPDF/pythonsdk/issues)
222
+
223
+ ## License
224
+
225
+ MIT License - see [LICENSE](LICENSE) for details.
@@ -0,0 +1,34 @@
1
+ templatefox/__init__.py,sha256=alii2T_BztynbASoOvBYcbmls0HeLLbjAOkn_7C7Znw,3376
2
+ templatefox/api_client.py,sha256=E3YL1cXqnY6w4tMrEHL43S7PCgsAOOnv0QxVZykTVSg,27788
3
+ templatefox/api_response.py,sha256=eMxw1mpmJcoGZ3gs9z6jM4oYoZ10Gjk333s9sKxGv7s,652
4
+ templatefox/configuration.py,sha256=6_l72ngubZLdqtFMr3R6NaxWGRRgp4E64flfeaOKdXE,19154
5
+ templatefox/exceptions.py,sha256=Hcel4vbmPgpu1E7Vs_6D2xzxRiwdORmo_HoqxZqp90w,6555
6
+ templatefox/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ templatefox/rest.py,sha256=zUfLbqW561bWt6hqUuwHu_Z-YA8EdgXa5HfiwIMJndM,9669
8
+ templatefox/api/__init__.py,sha256=eILPdjf1khXsyw8cwgadHha_yb7xiCHhNK9uAprHSew,258
9
+ templatefox/api/account_api.py,sha256=GfW1ZqHC2aWcfBHgOYAkPG3DJCVRiMcf1Huv0CjvRhA,23993
10
+ templatefox/api/integrations_api.py,sha256=MOC1tzaFCeYvrJPjcVwYkAgrWwwW1cvrQRrOE5ldAzg,45423
11
+ templatefox/api/pdf_api.py,sha256=Y7ohwlVdugtbLBitrDqVEtLbrAeGTJrj-wJBhAFO1d8,13988
12
+ templatefox/api/templates_api.py,sha256=_YMf5Ns2S6q_VqKELBwvuUeQV3IqaVOT8uKhRn6_nNc,23896
13
+ templatefox/models/__init__.py,sha256=hbjF-9Z6RPnpdBQ4eQ3-wIp42VSc_JmXsMCgtXAbC-0,1442
14
+ templatefox/models/account_info_response.py,sha256=j_zwxnZG-AtIvwK9Y9A4Jc331EwaRuIZsFp0f66hV-I,2894
15
+ templatefox/models/create_pdf_request.py,sha256=uyEsUxV5wS08nCoB_vVkPi-QfPTVk_U6VfpMSEE6dfQ,5983
16
+ templatefox/models/create_pdf_response.py,sha256=pfvMW5eW2NNW79WodF5E9-NNcsXNyKZVkwDh90nohs8,3060
17
+ templatefox/models/export_type.py,sha256=3rjFl_GfMUMBolmfrOKLVuu8nLnIpD5O0a02B0kTIic,767
18
+ templatefox/models/http_validation_error.py,sha256=I6M4ECtyrv0zcyeJki6M1-_Z6_b4At6gDlwdGk6XtAk,3018
19
+ templatefox/models/location_inner.py,sha256=6munPndEDR98pv6Sm4IXxTELCuwORWuAI8vIKCcmcLY,4842
20
+ templatefox/models/s3_config_request.py,sha256=hKTN559fEyG_khQHFnxs1hR6LiRmve0i7FfzTP7QRrY,4977
21
+ templatefox/models/s3_config_response.py,sha256=5KWsv61rdt2MTTV8jtrMOXYaKFTgv6WKgKKMGZZN3Oc,3430
22
+ templatefox/models/s3_success_response.py,sha256=I03llZ1DQC6rdeuOXI8rV3BrdP56kjlyEX_tnpnvkNQ,2602
23
+ templatefox/models/s3_test_response.py,sha256=-CDj2ZO7z0a-M30O5WN1ihgGcO1wH3bAAMVK4kmGmzA,2719
24
+ templatefox/models/template_field.py,sha256=7A0ylB5cjhDjDnXD-XN4Jz_JPMzSM80Pbfa2rWyzp-U,3457
25
+ templatefox/models/template_list_item.py,sha256=G9WlwQxbznHFthYtG3TD39MmBlERulCCk6zfkvn-Wa0,2931
26
+ templatefox/models/templates_list_response.py,sha256=Jo-kLKNVB-mZF9vf-hlbDtR-hwYCrLzXyVbTz5ANrdQ,3054
27
+ templatefox/models/transaction.py,sha256=4sQMQnA-e_mmz_OQ2HnZ8i35zUW7YMyjlL8lw3rnsdQ,3722
28
+ templatefox/models/transactions_response.py,sha256=-LXBiOdJGFOt9UkQnc3sRF5PxbFZZWDQMADFrEYtkJs,3449
29
+ templatefox/models/validation_error.py,sha256=vHM5POO0Ze9BJalMAvnCrATmn511kkh92wDXrDzenJQ,3068
30
+ templatefox-1.0.0.dist-info/licenses/LICENSE,sha256=LS5mJ2kGW6681vGD3LITctiVok0PUc9xZ1ZDpzHAHSQ,1068
31
+ templatefox-1.0.0.dist-info/METADATA,sha256=brnZbvSk_aNiE-1wcKywRjKhdZWIwczbQSBHPxOsndM,5699
32
+ templatefox-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
33
+ templatefox-1.0.0.dist-info/top_level.txt,sha256=90Av3vksTOHrRrfMRCjRbNJ5fn2uZIRg3Jasi-oiteQ,12
34
+ templatefox-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 TemplateFox
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 @@
1
+ templatefox