Package deepl_api
Provides a lightweight wrapper for the DeepL Pro REST API.
If you are looking for the deepl
commandline utitlity, please refer
to its documentation instead.
Requirements
You need to have a valid DeepL Pro Developer account with an associated API key. This key must be made available to the application, e. g. via environment variable:
export DEEPL_API_KEY=YOUR_KEY
Example
import os
import pytest
import deepl_api
def test_documentation():
# Create a DeepL instance for our account.
deepl = deepl_api.DeepL(os.getenv("DEEPL_API_KEY"))
# Translate Text
translations = deepl.translate(source_language="DE", target_language="EN-US", texts=["ja"])
assert translations == [{"detected_source_language": "DE", "text": "yes"}]
# Fetch Usage Information
usage_information = deepl_api.DeepL(os.getenv("DEEPL_API_KEY")).usage_information()
assert usage_information.character_limit > 0
See Also
The main API functions are documented in the DeepL
class.
Expand source code
"""
Provides a lightweight wrapper for the DeepL Pro REST API.
*If you are looking for the `deepl` commandline utitlity, please refer
to [its documentation](cli.html) instead.*
.. include:: ./doc_api.md
"""
__version__ = "0.1.0"
from dataclasses import dataclass
from enum import Enum
import requests
from deepl_api.exceptions import (
DeeplAuthorizationError,
DeeplServerError,
DeeplDeserializationError,
)
@dataclass
class UsageInformation:
"""Information about API usage & limits for this account."""
character_count: int
"""How many characters can be translated per billing period, based on the account settings."""
character_limit: int
"""How many characters were already translated in the current billing period."""
class SplitSentences(Enum):
"""Translation option that controls the splitting of sentences before the translation."""
NONE = 0
"""Don't split sentences."""
PUNCTUATION = 1
"""Split on punctiation only."""
PUNCTUATION_AND_NEWLINES = "newlines"
"""Split on punctuation and newlines."""
class Formality(Enum):
"""Translation option that controls the desired translation formality."""
LESS = "less"
"""Translate less formally."""
DEFAULT = "default"
"""Default formality."""
MORE = "more"
"""Translate more formally."""
class DeepL:
"""
The main API entry point representing a DeepL developer account with an associated API key.
Use this to create a new DeepL API client instance where multiple function calls can be performed.
A valid `api_key` is required.
Should you ever need to use more than one DeepL account in our program, then you can create one
instance for each account / API key.
##Error Handling
These methods may throw exceptions defined in `deepl_api.exceptions` and [requests.exceptions](https://requests.readthedocs.io/en/latest/api/#exceptions).
"""
_api_key: str
_api_base_url: str
def __init__(self, api_key: str):
self._api_key = api_key
self._api_base_url = (
"https://api-free.deepl.com/v2"
if api_key.endswith(":fx")
else "https://api.deepl.com/v2"
)
# Private method that performs the HTTP calls.
def _api_call(self, url: str, payload: dict = {}):
# Create a new dict to avoid modifying the passed one.
post_data = {**payload, "auth_key": self._api_key}
with requests.post(self._api_base_url + url, post_data) as response:
if response.status_code in (
requests.codes["unauthorized"],
requests.codes["forbidden"],
):
raise DeeplAuthorizationError(
"Authorization failed, is your API key correct?"
)
# DeepL sends back error messages in the response body.
# Try to fetch them to construct more helpful exceptions.
if not response.ok:
try:
data = response.json()
if data["message"]:
raise DeeplServerError(
f"An error occurred while communicating with the DeepL server: '{data['message']}'."
)
# In case the message could not be decoded, just go on to raise
# a built-in "requests" exception.
except (ValueError):
pass
# Use the default error handling of "requests".
response.raise_for_status()
return response.json()
def usage_information(self) -> UsageInformation:
"""
Retrieve information about API usage & limits.
This can also be used to verify an API key without consuming translation contingent.
See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/monitoring-usage/).
"""
data = self._api_call("/usage")
if not "character_count" in (data):
raise DeeplDeserializationError()
return UsageInformation(
character_count=data["character_count"],
character_limit=data["character_limit"],
)
# Private method to make the API calls for the language lists.
def _languages(self, ltype: str):
data = self._api_call("/languages", {"type": ltype})
if not "language" in (data[0]):
raise DeeplDeserializationError()
return {item["language"]: item["name"] for item in data}
def source_languages(self) -> dict:
"""
Retrieve all currently available source languages.
See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/).
"""
return self._languages("source")
def target_languages(self) -> dict:
"""
Retrieve all currently available target languages.
See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/).
"""
return self._languages("target")
def translate(
self,
*,
source_language: str = None,
target_language: str,
split_sentences: SplitSentences = None,
preserve_formatting: bool = None,
formality: Formality = None,
handle_xml: bool = None,
texts: list,
) -> list:
"""
Translate one or more text chunks at once. You can pass in optional
translation options if you need non-default behaviour.
Please see the parameter documentation and the
[vendor documentation](https://www.deepl.com/docs-api/translating-text/) for details.
Returns a list of dictionaries for the translated content:
```python
[
{
"detected_source_language": "DE",
"text": "Yes. No.",
},
...
]
```
"""
payload = {
"target_lang": target_language,
"text": texts,
}
if source_language != None:
payload["source_lang"] = source_language
if split_sentences != None:
payload["split_sentences"] = split_sentences.value
if preserve_formatting != None:
payload["preserve_formatting"] = 1 if preserve_formatting else 0
if formality != None:
payload["formality"] = formality.value
if handle_xml:
payload["tag_handling"] = "xml"
data = self._api_call("/translate", payload)
if not "translations" in (data):
raise DeeplDeserializationError
return data["translations"]
Sub-modules
deepl_api.cli
-
Unix-style commandline application for integrating the DeepL API into toolchains without any programming effort …
deepl_api.exceptions
-
DeepL API exception classes.
Classes
class DeepL (api_key: str)
-
The main API entry point representing a DeepL developer account with an associated API key.
Use this to create a new DeepL API client instance where multiple function calls can be performed. A valid
api_key
is required.Should you ever need to use more than one DeepL account in our program, then you can create one instance for each account / API key.
Error Handling
These methods may throw exceptions defined in
deepl_api.exceptions
and requests.exceptions.Expand source code
class DeepL: """ The main API entry point representing a DeepL developer account with an associated API key. Use this to create a new DeepL API client instance where multiple function calls can be performed. A valid `api_key` is required. Should you ever need to use more than one DeepL account in our program, then you can create one instance for each account / API key. ##Error Handling These methods may throw exceptions defined in `deepl_api.exceptions` and [requests.exceptions](https://requests.readthedocs.io/en/latest/api/#exceptions). """ _api_key: str _api_base_url: str def __init__(self, api_key: str): self._api_key = api_key self._api_base_url = ( "https://api-free.deepl.com/v2" if api_key.endswith(":fx") else "https://api.deepl.com/v2" ) # Private method that performs the HTTP calls. def _api_call(self, url: str, payload: dict = {}): # Create a new dict to avoid modifying the passed one. post_data = {**payload, "auth_key": self._api_key} with requests.post(self._api_base_url + url, post_data) as response: if response.status_code in ( requests.codes["unauthorized"], requests.codes["forbidden"], ): raise DeeplAuthorizationError( "Authorization failed, is your API key correct?" ) # DeepL sends back error messages in the response body. # Try to fetch them to construct more helpful exceptions. if not response.ok: try: data = response.json() if data["message"]: raise DeeplServerError( f"An error occurred while communicating with the DeepL server: '{data['message']}'." ) # In case the message could not be decoded, just go on to raise # a built-in "requests" exception. except (ValueError): pass # Use the default error handling of "requests". response.raise_for_status() return response.json() def usage_information(self) -> UsageInformation: """ Retrieve information about API usage & limits. This can also be used to verify an API key without consuming translation contingent. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/monitoring-usage/). """ data = self._api_call("/usage") if not "character_count" in (data): raise DeeplDeserializationError() return UsageInformation( character_count=data["character_count"], character_limit=data["character_limit"], ) # Private method to make the API calls for the language lists. def _languages(self, ltype: str): data = self._api_call("/languages", {"type": ltype}) if not "language" in (data[0]): raise DeeplDeserializationError() return {item["language"]: item["name"] for item in data} def source_languages(self) -> dict: """ Retrieve all currently available source languages. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/). """ return self._languages("source") def target_languages(self) -> dict: """ Retrieve all currently available target languages. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/). """ return self._languages("target") def translate( self, *, source_language: str = None, target_language: str, split_sentences: SplitSentences = None, preserve_formatting: bool = None, formality: Formality = None, handle_xml: bool = None, texts: list, ) -> list: """ Translate one or more text chunks at once. You can pass in optional translation options if you need non-default behaviour. Please see the parameter documentation and the [vendor documentation](https://www.deepl.com/docs-api/translating-text/) for details. Returns a list of dictionaries for the translated content: ```python [ { "detected_source_language": "DE", "text": "Yes. No.", }, ... ] ``` """ payload = { "target_lang": target_language, "text": texts, } if source_language != None: payload["source_lang"] = source_language if split_sentences != None: payload["split_sentences"] = split_sentences.value if preserve_formatting != None: payload["preserve_formatting"] = 1 if preserve_formatting else 0 if formality != None: payload["formality"] = formality.value if handle_xml: payload["tag_handling"] = "xml" data = self._api_call("/translate", payload) if not "translations" in (data): raise DeeplDeserializationError return data["translations"]
Methods
def source_languages(self) ‑> dict
-
Retrieve all currently available source languages.
See also the vendor documentation.
Expand source code
def source_languages(self) -> dict: """ Retrieve all currently available source languages. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/). """ return self._languages("source")
def target_languages(self) ‑> dict
-
Retrieve all currently available target languages.
See also the vendor documentation.
Expand source code
def target_languages(self) -> dict: """ Retrieve all currently available target languages. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/listing-supported-languages/). """ return self._languages("target")
def translate(self, *, source_language: str = None, target_language: str, split_sentences: SplitSentences = None, preserve_formatting: bool = None, formality: Formality = None, handle_xml: bool = None, texts: list) ‑> list
-
Translate one or more text chunks at once. You can pass in optional translation options if you need non-default behaviour.
Please see the parameter documentation and the vendor documentation for details.
Returns a list of dictionaries for the translated content:
[ { "detected_source_language": "DE", "text": "Yes. No.", }, ... ]
Expand source code
def translate( self, *, source_language: str = None, target_language: str, split_sentences: SplitSentences = None, preserve_formatting: bool = None, formality: Formality = None, handle_xml: bool = None, texts: list, ) -> list: """ Translate one or more text chunks at once. You can pass in optional translation options if you need non-default behaviour. Please see the parameter documentation and the [vendor documentation](https://www.deepl.com/docs-api/translating-text/) for details. Returns a list of dictionaries for the translated content: ```python [ { "detected_source_language": "DE", "text": "Yes. No.", }, ... ] ``` """ payload = { "target_lang": target_language, "text": texts, } if source_language != None: payload["source_lang"] = source_language if split_sentences != None: payload["split_sentences"] = split_sentences.value if preserve_formatting != None: payload["preserve_formatting"] = 1 if preserve_formatting else 0 if formality != None: payload["formality"] = formality.value if handle_xml: payload["tag_handling"] = "xml" data = self._api_call("/translate", payload) if not "translations" in (data): raise DeeplDeserializationError return data["translations"]
def usage_information(self) ‑> UsageInformation
-
Retrieve information about API usage & limits. This can also be used to verify an API key without consuming translation contingent.
See also the vendor documentation.
Expand source code
def usage_information(self) -> UsageInformation: """ Retrieve information about API usage & limits. This can also be used to verify an API key without consuming translation contingent. See also the [vendor documentation](https://www.deepl.com/docs-api/other-functions/monitoring-usage/). """ data = self._api_call("/usage") if not "character_count" in (data): raise DeeplDeserializationError() return UsageInformation( character_count=data["character_count"], character_limit=data["character_limit"], )
class Formality (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
Translation option that controls the desired translation formality.
Expand source code
class Formality(Enum): """Translation option that controls the desired translation formality.""" LESS = "less" """Translate less formally.""" DEFAULT = "default" """Default formality.""" MORE = "more" """Translate more formally."""
Ancestors
- enum.Enum
Class variables
var DEFAULT
-
Default formality.
var LESS
-
Translate less formally.
var MORE
-
Translate more formally.
class SplitSentences (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
Translation option that controls the splitting of sentences before the translation.
Expand source code
class SplitSentences(Enum): """Translation option that controls the splitting of sentences before the translation.""" NONE = 0 """Don't split sentences.""" PUNCTUATION = 1 """Split on punctiation only.""" PUNCTUATION_AND_NEWLINES = "newlines" """Split on punctuation and newlines."""
Ancestors
- enum.Enum
Class variables
var NONE
-
Don't split sentences.
var PUNCTUATION
-
Split on punctiation only.
var PUNCTUATION_AND_NEWLINES
-
Split on punctuation and newlines.
class UsageInformation (character_count: int, character_limit: int)
-
Information about API usage & limits for this account.
Expand source code
@dataclass class UsageInformation: """Information about API usage & limits for this account.""" character_count: int """How many characters can be translated per billing period, based on the account settings.""" character_limit: int """How many characters were already translated in the current billing period."""
Class variables
var character_count : int
-
How many characters can be translated per billing period, based on the account settings.
var character_limit : int
-
How many characters were already translated in the current billing period.