├── .github └── workflows │ ├── main.yml │ └── publish.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── convertapi ├── __init__.py ├── api.py ├── client.py ├── exceptions.py ├── file_param.py ├── format_detector.py ├── result.py ├── result_file.py ├── task.py ├── upload_io.py └── utils.py ├── examples ├── conversions_chaining.py ├── convert_stream.py ├── convert_url_to_pdf.py ├── convert_word_to_pdf_and_png.py ├── create_pdf_thumbnail.py ├── files │ ├── test.docx │ └── test.pdf ├── retrieve_user_information.py └── split_and_merge_pdf.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-requirements.txt └── tests ├── __init__.py ├── test_convertapi.py └── utils.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push,pull_request] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | python-version: 9 | - '3.7' 10 | - '3.9' 11 | name: Python ${{ matrix.python-version }} sample 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-python@v3 15 | with: 16 | python-version: ${{ matrix.python-version }} 17 | cache: 'pip' 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install -r requirements.txt 22 | pip install -r test-requirements.txt 23 | - env: 24 | CONVERT_API_SECRET: ${{ secrets.CONVERTAPI_SECRET }} 25 | run: nosetests 26 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distribution 📦 to PyPI 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | name: Build distribution 📦 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: "3.x" 18 | - name: Install pypa/build 19 | run: >- 20 | python3 -m 21 | pip install 22 | build 23 | --user 24 | - name: Build a binary wheel and a source tarball 25 | run: python3 -m build 26 | - name: Store the distribution packages 27 | uses: actions/upload-artifact@v3 28 | with: 29 | name: python-package-distributions 30 | path: dist/ 31 | 32 | publish-to-pypi: 33 | name: >- 34 | Publish Python 🐍 distribution 📦 to PyPI 35 | needs: 36 | - build 37 | runs-on: ubuntu-latest 38 | environment: 39 | name: pypi 40 | url: https://pypi.org/p/convertapi 41 | permissions: 42 | id-token: write # IMPORTANT: mandatory for trusted publishing 43 | 44 | steps: 45 | - name: Download all the dists 46 | uses: actions/download-artifact@v3 47 | with: 48 | name: python-package-distributions 49 | path: dist/ 50 | - name: Publish distribution 📦 to PyPI 51 | uses: pypa/gh-action-pypi-publish@release/v1 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | .tox/ 31 | .coverage 32 | .cache 33 | nosetests.xml 34 | coverage.xml 35 | 36 | # Translations 37 | *.mo 38 | 39 | # Mr Developer 40 | .mr.developer.cfg 41 | .project 42 | .pydevproject 43 | 44 | # Rope 45 | .ropeproject 46 | 47 | # Django stuff: 48 | *.log 49 | *.pot 50 | 51 | # Sphinx documentation 52 | docs/_build/ 53 | 54 | .python-version 55 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ConvertAPI 2 | https://www.convertapi.com 3 | (c) 2011-2018 Baltsoft 4 | 5 | ConvertAPI.Python 6 | https://github.com/ConvertAPI/convertapi-library-python 7 | Copyright (c) 2018 Tomas Rutkauskas 8 | 9 | The MIT License 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ConvertAPI Python Client 2 | 3 | [![PyPI version](https://badge.fury.io/py/convertapi.svg)](https://badge.fury.io/py/convertapi) 4 | [![Build Status](https://github.com/ConvertAPI/convertapi-library-python/actions/workflows/main.yml/badge.svg)](https://github.com/ConvertAPI/convertapi-library-python/actions) 5 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 6 | 7 | ## Convert your files with our online file conversion API 8 | 9 | ConvertAPI helps to convert various file formats. Creating PDF and Images from various sources like Word, Excel, Powerpoint, images, web pages or raw HTML codes. Merge, Encrypt, Split, Repair and Decrypt PDF files and many other manipulations. You can integrate it into your application in just a few minutes and use it easily. 10 | 11 | ## Installation 12 | 13 | Install with [pip](https://pypi.org/project/pip/): 14 | 15 | pip install --upgrade convertapi 16 | 17 | Install from source with: 18 | 19 | python setup.py install 20 | 21 | ### Requirements 22 | 23 | * Python 3.3+ 24 | 25 | ## Usage 26 | 27 | ### Configuration 28 | 29 | You can get your API credentials at https://www.convertapi.com/a 30 | 31 | ```python 32 | import convertapi 33 | 34 | convertapi.api_credentials = 'api-token' 35 | ``` 36 | 37 | #### Proxy configuration 38 | 39 | If you need to use a proxy, you can specify it using `HTTPS_PROXY` environment variable when running your script. 40 | 41 | Example: 42 | 43 | ``` 44 | API_TOKEN=api-token HTTPS_PROXY=https://user:pass@127.0.0.1:9000/ python convert_word_to_pdf_and_png.py 45 | ``` 46 | 47 | ### File conversion 48 | 49 | Convert a file to PDF example. All supported file formats and options can be found 50 | [here](https://www.convertapi.com/conversions). 51 | 52 | ```python 53 | result = convertapi.convert('pdf', { 'File': '/path/to/my_file.docx' }) 54 | 55 | # save to file 56 | result.file.save('/path/to/save/file.pdf') 57 | ``` 58 | 59 | Other result operations: 60 | 61 | ```python 62 | # save all result files to folder 63 | result.save_files('/path/to/save/files') 64 | 65 | # get conversion cost 66 | conversion_cost = result.conversion_cost 67 | ``` 68 | 69 | #### Convert file url 70 | 71 | ```python 72 | result = convertapi.convert('pdf', { 'File': 'https://website/my_file.docx' }) 73 | ``` 74 | 75 | #### Specifying from format 76 | 77 | ```python 78 | result = convertapi.convert( 79 | 'pdf', 80 | { 'File': '/path/to/my_file' }, 81 | from_format = 'docx' 82 | ) 83 | ``` 84 | 85 | #### Additional conversion parameters 86 | 87 | ConvertAPI accepts additional conversion parameters depending on selected formats. All conversion 88 | parameters and explanations can be found [here](https://www.convertapi.com/conversions). 89 | 90 | ```python 91 | result = convertapi.convert( 92 | 'pdf', 93 | { 94 | 'File': '/path/to/my_file.docx', 95 | 'PageRange': '1-10', 96 | 'PdfResolution': '150', 97 | } 98 | ) 99 | ``` 100 | 101 | ### User information 102 | 103 | You can always check your usage by fetching [user information](https://www.convertapi.com/doc/user). 104 | 105 | ```python 106 | user_info = convertapi.user() 107 | 108 | print(user_info['ConversionsTotal']) 109 | print(user_info['ConversionsConsumed']) 110 | ``` 111 | 112 | ### Alternative domain 113 | 114 | Set `base_uri` parameter to use other service domains. Dedicated to the region [domain list](https://www.convertapi.com/doc/servers-location). 115 | 116 | ```python 117 | convertapi.base_uri = 'https://eu-v2.convertapi.com/' 118 | ``` 119 | 120 | ### More examples 121 | 122 | Find more advanced examples in the [/examples](https://github.com/ConvertAPI/convertapi-library-python/tree/master/examples) folder. 123 | 124 | ## Development 125 | 126 | Execute `API_TOKEN=api-token nosetests --nocapture` to run the tests. 127 | 128 | ## Contributing 129 | 130 | Bug reports and pull requests are welcome on GitHub at https://github.com/ConvertAPI/convertapi-library-python. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 131 | 132 | ## License 133 | 134 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 135 | -------------------------------------------------------------------------------- /convertapi/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '2.0.0' 2 | 3 | from .exceptions import * 4 | from .client import Client 5 | from .upload_io import UploadIO 6 | from .api import convert, user 7 | 8 | # configuration 9 | 10 | api_credentials = None 11 | base_uri = 'https://v2.convertapi.com/' 12 | user_agent = 'ConvertAPI-Python/' + __version__ 13 | timeout = 1800 14 | conversion_timeout = None 15 | conversion_timeout_delta = 10 16 | upload_timeout = None 17 | download_timeout = None 18 | max_parallel_uploads = 10 19 | verify_ssl = True 20 | 21 | client = Client() 22 | -------------------------------------------------------------------------------- /convertapi/api.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | 3 | from .task import Task 4 | 5 | def convert(to_format, params, from_format = None, timeout = None): 6 | task = Task(from_format, to_format, params, timeout = timeout) 7 | return task.run() 8 | 9 | def user(timeout = None): 10 | return convertapi.client.get('user', timeout = timeout) 11 | -------------------------------------------------------------------------------- /convertapi/client.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import convertapi 3 | 4 | from io import BytesIO 5 | from .exceptions import * 6 | 7 | class Client: 8 | def get(self, path, params = {}, timeout = None): 9 | url = self.__url(path) 10 | timeout = timeout or convertapi.timeout 11 | r = self.__session().get(url, params = params, timeout = timeout) 12 | return self.__handle_response(r) 13 | 14 | def post(self, path, payload, timeout = None): 15 | url = self.__url(path) 16 | timeout = timeout or convertapi.timeout 17 | r = self.__session().post(url, data = payload, timeout = timeout) 18 | return self.__handle_response(r) 19 | 20 | def upload(self, io, filename): 21 | url = convertapi.base_uri + 'upload' 22 | encoded_filename = requests.utils.quote(filename) 23 | 24 | headers = { 25 | 'Content-Disposition': "attachment; filename*=UTF-8''" + encoded_filename, 26 | } 27 | 28 | r = self.__session().post(url, data = io, headers = headers, timeout = convertapi.upload_timeout) 29 | return self.__handle_response(r) 30 | 31 | def download(self, url, path): 32 | r = self.__session().get(url, stream = True, timeout = convertapi.download_timeout) 33 | 34 | with open(path, 'wb') as f: 35 | for chunk in r.iter_content(chunk_size = 1024): 36 | if chunk: 37 | f.write(chunk) 38 | 39 | return path 40 | 41 | def download_io(self, url): 42 | response = self.__session().get(url, timeout = convertapi.download_timeout) 43 | return BytesIO(response.content) 44 | 45 | def __handle_response(self, r): 46 | try: 47 | r.raise_for_status() 48 | except requests.RequestException as e: 49 | try: 50 | raise ApiError(r.json()) 51 | except ValueError: 52 | raise e 53 | 54 | return r.json() 55 | 56 | def __url(self, path): 57 | return convertapi.base_uri + path 58 | 59 | def __session(self): 60 | s = requests.Session() 61 | s.headers.update({ 'User-Agent': convertapi.user_agent }) 62 | s.headers.update({ 'Authorization': 'Bearer ' + convertapi.api_credentials }) 63 | s.verify = convertapi.verify_ssl 64 | 65 | return s 66 | -------------------------------------------------------------------------------- /convertapi/exceptions.py: -------------------------------------------------------------------------------- 1 | class BaseError(BaseException): 2 | pass 3 | 4 | class ApiError(BaseError): 5 | def __init__(self, result): 6 | self.message = result.get('Message', '[message not set]') 7 | 8 | super(ApiError, self).__init__(self.message) 9 | 10 | self.code = result.get('Code', '') 11 | self.invalid_parameters = result.get('InvalidParameters', '') 12 | 13 | def __str__(self): 14 | message = "%s Code: %s. %s" % (self.message, self.code, self.invalid_parameters) 15 | return message.strip() 16 | -------------------------------------------------------------------------------- /convertapi/file_param.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from io import FileIO 4 | from .result import Result 5 | from .result_file import ResultFile 6 | from .upload_io import UploadIO 7 | 8 | def build(resource): 9 | if isinstance(resource, Result): 10 | return resource.file.url 11 | 12 | if isinstance(resource, ResultFile): 13 | return resource.url 14 | 15 | if isinstance(resource, UploadIO): 16 | return resource.file_id 17 | 18 | if isinstance(resource, FileIO): 19 | return UploadIO(resource).file_id 20 | 21 | if os.path.isfile(resource): 22 | io = open(resource, 'rb') 23 | return UploadIO(io).file_id 24 | 25 | return resource 26 | -------------------------------------------------------------------------------- /convertapi/format_detector.py: -------------------------------------------------------------------------------- 1 | from os.path import splitext 2 | from io import FileIO 3 | from requests import utils 4 | from .result import Result 5 | from .upload_io import UploadIO 6 | 7 | def detect(resource): 8 | if isinstance(resource, UploadIO): 9 | return resource.file_ext 10 | elif 'filename' in dir(resource): 11 | path = resource.filename 12 | elif isinstance(resource, FileIO): 13 | path = resource.name 14 | elif isinstance(resource, Result): 15 | path = resource.file.filename 16 | else: 17 | path = utils.urlparse(resource).path 18 | 19 | return splitext(path)[1][1:].lower() 20 | -------------------------------------------------------------------------------- /convertapi/result.py: -------------------------------------------------------------------------------- 1 | from .result_file import ResultFile 2 | 3 | class Result: 4 | def __init__(self, response): 5 | self.response = response 6 | 7 | @property 8 | def conversion_cost(self): 9 | return self.response['ConversionCost'] 10 | 11 | @property 12 | def file(self): 13 | return self.files[0] 14 | 15 | @property 16 | def files(self): 17 | return list(map(ResultFile, self.response['Files'])) 18 | 19 | def save_files(self, path): 20 | return [file.save(path) for file in self.files] 21 | -------------------------------------------------------------------------------- /convertapi/result_file.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | 4 | class ResultFile: 5 | def __init__(self, info): 6 | self.info = info 7 | 8 | @property 9 | def url(self): 10 | return self.info['Url'] 11 | 12 | @property 13 | def filename(self): 14 | return self.info['FileName'] 15 | 16 | @property 17 | def size(self): 18 | return self.info['FileSize'] 19 | 20 | @property 21 | def io(self): 22 | if not hasattr(self, '_io'): 23 | self._io = convertapi.client.download_io(self.url) 24 | 25 | return self._io 26 | 27 | def save(self, path): 28 | if os.path.isdir(path): 29 | path = os.path.join(path, self.filename) 30 | 31 | return convertapi.client.download(self.url, path) 32 | -------------------------------------------------------------------------------- /convertapi/task.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | 3 | from convertapi import file_param, format_detector, utils 4 | from .result import Result 5 | 6 | DEFAULT_URL_FORMAT = 'web' 7 | 8 | class Task: 9 | def __init__(self, from_format, to_format, params, timeout = None): 10 | self.from_format = from_format 11 | self.to_format = to_format 12 | self.params = params 13 | self.timeout = timeout or convertapi.conversion_timeout 14 | 15 | self.default_params = { 16 | 'Timeout': self.timeout, 17 | 'StoreFile': True, 18 | } 19 | 20 | def run(self): 21 | params = self.__normalize_params() 22 | from_format = self.from_format or self.__detect_format() 23 | timeout = self.timeout + convertapi.conversion_timeout_delta if self.timeout else None 24 | path = "convert/%s/to/%s" % (from_format, self.to_format) 25 | 26 | response = convertapi.client.post(path, params, timeout = timeout) 27 | 28 | return Result(response) 29 | 30 | def __normalize_params(self): 31 | params = {} 32 | 33 | for k, v in self.params.items(): 34 | if k != 'StoreFile' and k.endswith('File'): 35 | params[k] = file_param.build(v) 36 | elif k == 'Files': 37 | results = utils.map_in_parallel(file_param.build, v, convertapi.max_parallel_uploads) 38 | 39 | for idx, val in enumerate(results): 40 | key = '%s[%i]' % (k, idx) 41 | params[key] = val 42 | else: 43 | params[k] = v 44 | 45 | params.update(self.default_params) 46 | 47 | return params 48 | 49 | def __detect_format(self): 50 | if str(self.to_format).lower() == 'zip': 51 | return 'any' 52 | 53 | if 'Url' in self.params: 54 | return DEFAULT_URL_FORMAT 55 | 56 | if 'File' in self.params: 57 | return format_detector.detect(self.params['File']) 58 | 59 | if 'Files' in self.params: 60 | return format_detector.detect(self.params['Files'][0]) 61 | -------------------------------------------------------------------------------- /convertapi/upload_io.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os.path 3 | 4 | class UploadIO: 5 | def __init__(self, io, filename = None): 6 | self.io = io 7 | self._filename = filename 8 | self._result = None 9 | 10 | @property 11 | def file_id(self): 12 | return self.__result['FileId'] 13 | 14 | @property 15 | def file_ext(self): 16 | return self.__result['FileExt'] 17 | 18 | @property 19 | def __result(self): 20 | if self._result is None: 21 | self._result = convertapi.client.upload(self.io, self.__build_filename()) 22 | 23 | return self._result 24 | 25 | def __build_filename(self): 26 | if self._filename: 27 | return self._filename 28 | 29 | if 'name' in dir(self.io): 30 | return os.path.basename(self.io.name) 31 | 32 | raise 'Filename must be provided for non File resources' 33 | -------------------------------------------------------------------------------- /convertapi/utils.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | 3 | def map_in_parallel(f, values, pool_size): 4 | if pool_size < 2: 5 | return map(f, values) 6 | 7 | pool = multiprocessing.Pool(pool_size) 8 | results = pool.map_async(f, values) 9 | pool.close() 10 | pool.join() 11 | 12 | return results.get() 13 | -------------------------------------------------------------------------------- /examples/conversions_chaining.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import tempfile 4 | 5 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 6 | 7 | # Short example of conversions chaining, the PDF pages extracted and saved as separated JPGs and then ZIP'ed 8 | # https://www.convertapi.com/doc/chaining 9 | 10 | print('Converting PDF to JPG and compressing result files with ZIP') 11 | 12 | jpg_result = convertapi.convert('jpg', { 'File': 'files/test.pdf' }) 13 | 14 | print("Conversions done. Cost: %s. Total files created: %s" % (jpg_result.conversion_cost, len(jpg_result.files))) 15 | 16 | zip_result = convertapi.convert('zip', { 'Files': jpg_result.files }) 17 | 18 | print("Conversions done. Cost: %s. Total files created: %s" % (zip_result.conversion_cost, len(zip_result.files))) 19 | 20 | saved_files = zip_result.save_files(tempfile.gettempdir()) 21 | 22 | print("File saved to %s" % saved_files) 23 | -------------------------------------------------------------------------------- /examples/convert_stream.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import io 4 | import tempfile 5 | 6 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 7 | 8 | # Example of using content stream to convert to pdf 9 | # https://www.convertapi.com/txt-to-pdf 10 | 11 | content = "Test content string" 12 | 13 | upload_io = convertapi.UploadIO(content, 'test.txt') 14 | 15 | result = convertapi.convert('pdf', { 'File': upload_io }) 16 | 17 | saved_files = result.save_files(tempfile.gettempdir()) 18 | 19 | print("The PDF saved to %s" % saved_files) 20 | 21 | -------------------------------------------------------------------------------- /examples/convert_url_to_pdf.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import tempfile 4 | 5 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 6 | 7 | # Example of converting Web Page URL to PDF file 8 | # https://www.convertapi.com/web-to-pdf 9 | 10 | result = convertapi.convert( 11 | 'pdf', 12 | { 13 | 'Url': 'https://en.wikipedia.org/wiki/Data_conversion', 14 | 'FileName': 'web-example', 15 | }, 16 | from_format = 'web', 17 | timeout = 180, 18 | ) 19 | 20 | saved_files = result.save_files(tempfile.gettempdir()) 21 | 22 | print("The web page PDF saved to %s" % saved_files) 23 | -------------------------------------------------------------------------------- /examples/convert_word_to_pdf_and_png.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import tempfile 4 | 5 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 6 | 7 | # Example of saving Word docx to PDF and to PNG 8 | # https://www.convertapi.com/docx-to-pdf 9 | # https://www.convertapi.com/docx-to-png 10 | 11 | # Use upload IO wrapper to upload file only once to the API 12 | upload_io = convertapi.UploadIO(open('files/test.docx', 'rb')) 13 | 14 | saved_files = convertapi.convert('pdf', { 'File': upload_io }).save_files(tempfile.gettempdir()) 15 | 16 | print("The PDF saved to %s" % saved_files) 17 | 18 | # Reuse the same uploaded file 19 | 20 | saved_files = convertapi.convert('png', { 'File': upload_io }).save_files(tempfile.gettempdir()) 21 | 22 | print("The PNG saved to %s" % saved_files) 23 | -------------------------------------------------------------------------------- /examples/create_pdf_thumbnail.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import tempfile 4 | 5 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 6 | 7 | # Example of extracting first page from PDF and then chaining conversion PDF page to JPG. 8 | # https://www.convertapi.com/pdf-to-extract 9 | # https://www.convertapi.com/pdf-to-jpg 10 | 11 | pdf_result = convertapi.convert( 12 | 'extract', 13 | { 14 | 'File': 'files/test.pdf', 15 | 'PageRange': 1, 16 | } 17 | ) 18 | 19 | jpg_result = convertapi.convert( 20 | 'jpg', 21 | { 22 | 'File': pdf_result, 23 | 'ScaleImage': True, 24 | 'ScaleProportions': True, 25 | 'ImageHeight': 300, 26 | 'ImageWidth': 300, 27 | } 28 | ) 29 | 30 | saved_files = jpg_result.save_files(tempfile.gettempdir()) 31 | 32 | print("The thumbnail saved to %s" % saved_files) 33 | -------------------------------------------------------------------------------- /examples/files/test.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConvertAPI/convertapi-library-python/67f66832ca2c641fba18f420c2a3a44ce4316d38/examples/files/test.docx -------------------------------------------------------------------------------- /examples/files/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConvertAPI/convertapi-library-python/67f66832ca2c641fba18f420c2a3a44ce4316d38/examples/files/test.pdf -------------------------------------------------------------------------------- /examples/retrieve_user_information.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | 4 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 5 | 6 | # Retrieve user information 7 | # https://www.convertapi.com/doc/user 8 | 9 | print(convertapi.user()) 10 | -------------------------------------------------------------------------------- /examples/split_and_merge_pdf.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import tempfile 4 | 5 | convertapi.api_credentials = os.environ['API_TOKEN'] # your api token 6 | 7 | # Example of extracting first and last pages from PDF and then merging them back to new PDF. 8 | # https://www.convertapi.com/pdf-to-split 9 | # https://www.convertapi.com/pdf-to-merge 10 | 11 | split_result = convertapi.convert('split', { 'File': 'files/test.pdf' }) 12 | 13 | first_page = split_result.files[0] 14 | last_page = split_result.files[-1] 15 | files = [first_page, last_page] 16 | 17 | merge_result = convertapi.convert('merge', { 'Files': files }) 18 | 19 | saved_files = merge_result.save_files(tempfile.gettempdir()) 20 | 21 | print("The PDF saved to %s" % saved_files) 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=1.2.0 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | 4 | [easy_install] 5 | 6 | [bdist_wheel] 7 | universal = 1 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools.depends import get_module_constant 4 | from setuptools import setup 5 | 6 | setup( 7 | name = 'convertapi', 8 | packages = ['convertapi'], 9 | version = get_module_constant('convertapi', '__version__'), 10 | description = 'Convert API Python Client', 11 | long_description = 'Convert various files like MS Word, Excel, PowerPoint, Images to PDF and Images. Create PDF and Images from url and raw HTML. Extract and create PowerPoint presentation from PDF. Merge, Encrypt, Split, Repair and Decrypt PDF files. All supported files conversions and manipulations can be found at https://www.convertapi.com/doc/supported-formats', 12 | author = 'Tomas Rutkauskas', 13 | author_email = 'support@convertapi.com', 14 | url = 'https://github.com/ConvertAPI/convertapi-library-python', 15 | download_url = 'https://github.com/ConvertAPI/convertapi-library-python', 16 | keywords = ['convert', 'api', 'client', 'conversion'], 17 | install_requires= ['requests>=2.4.2'], 18 | classifiers = [], 19 | license = 'MIT', 20 | ) 21 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | nose 2 | mock 3 | responses 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConvertAPI/convertapi-library-python/67f66832ca2c641fba18f420c2a3a44ce4316d38/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_convertapi.py: -------------------------------------------------------------------------------- 1 | import convertapi 2 | import os 3 | import io 4 | import tempfile 5 | import requests 6 | import responses 7 | 8 | from . import utils 9 | from nose.tools import * 10 | 11 | class TestConvertapi(utils.TestCase): 12 | def setUp(self): 13 | convertapi.api_credentials = os.environ['CONVERT_API_SECRET'] 14 | convertapi.max_parallel_uploads = 10 15 | 16 | def test_defaults(self): 17 | eq_('https://v2.convertapi.com/', convertapi.base_uri) 18 | 19 | def test_configuration(self): 20 | convertapi.api_credentials = 'TEST' 21 | eq_('TEST', convertapi.api_credentials) 22 | 23 | def test_convert_file(self): 24 | result = convertapi.convert('pdf', { 'File': 'examples/files/test.docx' }) 25 | assert result.save_files(tempfile.gettempdir()) 26 | assert result.conversion_cost > 0 27 | 28 | def test_convert_file_no_parallelizm(self): 29 | convertapi.max_parallel_uploads = 1 30 | result = convertapi.convert('pdf', { 'File': 'examples/files/test.docx' }) 31 | assert result.save_files(tempfile.gettempdir()) 32 | 33 | def test_convert_file_url(self): 34 | result = convertapi.convert('pdf', { 'File': 'https://cdn.convertapi.com/cara/testfiles/document.docx?test=1' }) 35 | assert result.conversion_cost > 0 36 | 37 | def test_convert_url(self): 38 | result = convertapi.convert('pdf', { 'Url': 'http://convertapi.com' }) 39 | assert result.conversion_cost > 0 40 | 41 | def test_convert_url_with_timeout_and_format(self): 42 | result = convertapi.convert('pdf', { 'Url': 'https://www.w3.org/TR/PNG/iso_8859-1.txt' }, 'web', 100) 43 | assert result.conversion_cost > 0 44 | 45 | def test_upload_io(self): 46 | bytes_io = io.BytesIO(b'test') 47 | upload_io = convertapi.UploadIO(bytes_io, 'test.txt') 48 | result = convertapi.convert('pdf', { 'File': upload_io }) 49 | assert result.conversion_cost > 0 50 | 51 | def test_download_io(self): 52 | result = convertapi.convert('pdf', { 'Url': 'https://www.w3.org/TR/PNG/iso_8859-1.txt' }) 53 | assert len(result.file.io.getvalue()) > 0 54 | 55 | def test_zip_files(self): 56 | files = ['examples/files/test.docx', 'examples/files/test.docx'] 57 | result = convertapi.convert('zip', { 'Files': files }) 58 | assert result.conversion_cost > 0 59 | 60 | def test_chained_conversion(self): 61 | result = convertapi.convert('pdf', { 'File': 'examples/files/test.docx' }) 62 | zip_result = convertapi.convert('zip', { 'Files': result.files }) 63 | eq_('test.zip', zip_result.file.filename) 64 | 65 | def test_compare_files(self): 66 | file = 'examples/files/test.docx' 67 | result = convertapi.convert('compare', { 'File': file, 'CompareFile': file }) 68 | assert result.conversion_cost > 0 69 | 70 | @raises(convertapi.ApiError) 71 | def test_api_error(self): 72 | convertapi.api_credentials = 'TEST' 73 | convertapi.convert('pdf', { 'Url': 'https://www.w3.org/TR/PNG/iso_8859-1.txt' }) 74 | 75 | def test_user_info(self): 76 | user_info = convertapi.user() 77 | assert user_info['Active'] 78 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | class TestCase(unittest.TestCase): 4 | pass --------------------------------------------------------------------------------