diff --git a/BeginerGuide/UsingCharts/usingChart.py b/BeginerGuide/UsingCharts/usingChart.py index 5753544..e8ddfdb 100644 --- a/BeginerGuide/UsingCharts/usingChart.py +++ b/BeginerGuide/UsingCharts/usingChart.py @@ -5,205 +5,205 @@ # ---------------line_chart line1 = cop.elements.LineSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='line1', - smooth=True, - symbol='diamond', - symbol_size=10, - color='red', - line_width='0.2cm', - line_style='sysDashDotDot' + ('a', 'b', 'c'), + (1, 2, 3), + 'line1', + True, + 'diamond', + 10, + 'red', + '0.2cm', + 'sysDashDotDot' ) line2 = cop.elements.LineSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='line2', - smooth=True, - symbol='square', - symbol_size=12, - color='blue', - line_width='2px', - line_style='sysDash' + ('a', 'b', 'c'), + (4, 5, 6), + 'line2', + True, + 'square', + 12, + 'blue', + '2px', + 'sysDash' ) line_chart = cop.elements.LineChart( - name='line_chart_name', - lines=(line1, line2) + 'line_chart_name', + (line1, line2) ) collection.add(line_chart) # --------------------bar_chart----------- bars1 = cop.elements.BarSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='bars1', - color='red' + ('a', 'b', 'c'), + (1, 2, 3), + 'bars1', + 'red' ) bars2 = cop.elements.BarSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='bars2', - color='blue' + ('a', 'b', 'c'), + (4, 5, 6), + 'bars2', + 'blue' ) bar_chart = cop.elements.BarChart( - name='bar_chart_name', - bars=(bars1, bars2) + 'bar_chart_name', + (bars1, bars2) ) collection.add(bar_chart) # -------------pie_chart---------- pies1 = cop.elements.PieSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='pies1', - colors=('red', None, 'blue') + ('a', 'b', 'c'), + (1, 2, 3), + 'pies1', + ('red', None, 'blue') ) pies2 = cop.elements.PieSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='pies2', - colors=('green', 'blue', None) + ('a', 'b', 'c'), + (4, 5, 6), + 'pies2', + ('green', 'blue', None) ) pies_chart = cop.elements.PieChart( - name='pie_chart_name', - pies=(pies1, pies2) + 'pie_chart_name', + (pies1, pies2) ) collection.add(pies_chart) # ---------------area_chart------------ area1 = cop.elements.AreaSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='area1', - color='red', - opacity=50 + ('a', 'b', 'c'), + (1, 2, 3), + 'area1', + 'red', + 50 ) area2 = cop.elements.AreaSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='area2', - color='blue', - opacity=80 + ('a', 'b', 'c'), + (4, 5, 6), + 'area2', + 'blue', + 80 ) area_chart = cop.elements.AreaChart( - name='area_chart_name', - areas=(area1, area2) + 'area_chart_name', + (area1, area2) ) collection.add(area_chart) # -----------------bubble_chart---------- bubble1 = cop.elements.BubbleSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - sizes=(5, 6, 2), - name='bubble1', - color='red' + ('a', 'b', 'c'), + (1, 2, 3), + (5, 6, 2), + 'bubble1', + 'red' ) bubble2 = cop.elements.BubbleSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - sizes=(5, 6, 2), - name='bubble2', - color='blue' + ('a', 'b', 'c'), + (4, 5, 6), + (5, 6, 2), + 'bubble2', + 'blue' ) bubble_chart = cop.elements.BubbleChart( - name='bubble_chart_name', - bubbles=(bubble1, bubble2) + 'bubble_chart_name', + (bubble1, bubble2) ) collection.add(bubble_chart) # ---------------stock_chart stock1 = cop.elements.StockSeries( - x=(1, 2, 3), - high=(4, 5, 6), - low=(7, 8, 9), - close=(10, 11, 12), - open_=(13, 14, 15), - volume=(16, 17, 18), - name='stock1' + (1, 2, 3), + (4, 5, 6), + (7, 8, 9), + (10, 11, 12), + (13, 14, 15), + (16, 17, 18), + 'stock1' ) stock2 = cop.elements.StockSeries( - x=(1, 2, 3), - high=(4, 5, 6), - low=(7, 8, 9), - close=(10, 11, 12), - open_=(13, 14, 15), - volume=(16, 17, 18), - name='stock2' + (1, 2, 3), + (4, 5, 6), + (7, 8, 9), + (10, 11, 12), + (13, 14, 15), + (16, 17, 18), + 'stock2' ) stock_chart = cop.elements.StockChart( - name='stock_chart_name', - stocks=(stock1, stock2) + 'stock_chart_name', + (stock1, stock2) ) # collection.add(stock_chart) # ----------------combined_chart------- axis = cop.elements.ChartAxisOptions() column1 = cop.elements.ColumnSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='column1' + ('a', 'b', 'c'), + (1, 2, 3), + 'column1' ) column2 = cop.elements.ColumnSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='column2' + ('a', 'b', 'c'), + (4, 5, 6), + 'column2' ) column_chart = cop.elements.ColumnChart( - name='column_chart', - columns=(column1, column2) + 'column_chart', + (column1, column2) ) line1 = cop.elements.LineSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='line1', - symbol='square' + ('a', 'b', 'c'), + (1, 2, 3), + 'line1', + 'square' ) line2 = cop.elements.LineSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='line2', - symbol='square' + ('a', 'b', 'c'), + (4, 5, 6), + 'line2', + 'square' ) line_chart_options = cop.elements.ChartOptions( - x_axis=axis, - y_axis=axis, - width=50, - background_color='gray', - background_opacity=50 + axis, + axis, + 50, + 'gray', + 50 ) line_chart = cop.elements.LineChart( - name='line_chart', - lines=(line1, line2), - options=line_chart_options + 'line_chart', + (line1, line2), + line_chart_options ) bar1 = cop.elements.BarSeries( - x=('a', 'b', 'c'), - y=(1, 2, 3), - name='bar1' + ('a', 'b', 'c'), + (1, 2, 3), + 'bar1' ) bar2 = cop.elements.BarSeries( - x=('a', 'b', 'c'), - y=(4, 5, 6), - name='bar2' + ('a', 'b', 'c'), + (4, 5, 6), + 'bar2' ) bar_chart_options = cop.elements.ChartOptions( - x_axis=axis, - y_axis=axis, - width=100, + axis, + axis, + 100, height=100, rounded_corners=False ) bar_chart = cop.elements.BarChart( - name='bar_chart', - bars=(bar1, bar2), - options=bar_chart_options + 'bar_chart', + (bar1, bar2), + bar_chart_options ) combined_chart = cop.elements.CombinedChart( - name='combined_chart_name', - charts=(column_chart, line_chart), - secondaryCharts=(bar_chart,) + 'combined_chart_name', + (column_chart, line_chart), + (bar_chart,) ) collection.add(combined_chart) @@ -211,7 +211,7 @@ # For running on localhost you do not need api_key else replace below "YOUR_API_KEY" with your api key. server = cop.config.Server( "http://localhost:8010/", - cop.config.ServerConfig(api_key="YOUR_API_KEY") + cop.config.ServerConfig("YOUR_API_KEY") ) # Create print job # PrintJob combines template, data, server and an optional output configuration diff --git a/cloudofficeprint/__init__.py b/cloudofficeprint/__init__.py index da838d5..a2475fe 100644 --- a/cloudofficeprint/__init__.py +++ b/cloudofficeprint/__init__.py @@ -95,6 +95,7 @@ from .printjob import PrintJob from .resource import Resource +from .template import Template from .response import Response # specify what is imported on "from cloudofficeprint import *" @@ -106,5 +107,6 @@ "own_utils", "PrintJob", "Resource", - "Response" + "Template", + "Response", ] diff --git a/cloudofficeprint/config/__init__.py b/cloudofficeprint/config/__init__.py index 1b43102..f96a40f 100644 --- a/cloudofficeprint/config/__init__.py +++ b/cloudofficeprint/config/__init__.py @@ -10,3 +10,4 @@ from .output import * from .pdf import * from .server import * +from .request_option import * \ No newline at end of file diff --git a/cloudofficeprint/config/output.py b/cloudofficeprint/config/output.py index e4ddd0a..9c80c69 100644 --- a/cloudofficeprint/config/output.py +++ b/cloudofficeprint/config/output.py @@ -2,6 +2,7 @@ from typing import Dict from .cloud import CloudAccessToken from .pdf import PDFOptions +from .request_option import requestOptions class OutputConfig: @@ -17,16 +18,25 @@ def __init__(self, cloud_access_token: CloudAccessToken = None, server_directory: str = None, pdf_options: PDFOptions = None, - append_per_page: bool = None,): - """ + append_per_page: bool = None, + prepend_per_page: bool = None, + output_polling: bool = None, + secret_key: str = None, + request_option: requestOptions = None): + """If the parameters are not provided default value will be used. + Args: - filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). + filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). Defaults to None. encoding (str, optional): Encoding of output file. Either "raw" or "base64". Defaults to "raw". converter (str, optional): The pdf converter to use. Can be "libreoffice", "officetopdf" or any custom defined converter. Custom converters are configurated in the Cloud Office Print server's `aop_config.json` file. Defaults to "libreoffice". cloud_access_token (CloudAccessToken, optional): Access token used to access various cloud services for output storage. Defaults to None. server_directory (str, optional): Base directory to save output files into. Can only be used if the server allows to save on disk. The specific output path for each file is appended to the base path. Defaults to None. pdf_options (PDFOptions, optional): Optional PDF options. Defaults to None. - append_per_page (bool, optional): Ability to prepend/append file after each page of output. + append_per_page (bool, optional): Ability to append file after each page of output. Defaults to None. + prepend_per_page (bool, optional): Ability to prepend file after each page of output. Defaults to None. + output_polling (bool, optional): A unique link for each request is sent back, which can be used later to download the output file. Defaults to None. + secret_key (str, optional): A secret key can be specified to encrypt the file stored on the server (ussed with output polling). Defaults to None. + request_option (requestOptions, optional): AOP makes a call to the given option with response/output of the current request. Defaults to None. """ self.filetype: str = filetype self.converter: str = converter @@ -35,6 +45,10 @@ def __init__(self, self.pdf_options: PDFOptions = pdf_options self.encoding = encoding self.append_per_page = append_per_page + self.prepend_per_page = prepend_per_page + self.output_polling = output_polling + self.secret_key = secret_key + self.request_option = request_option @property def json(self) -> str: @@ -69,6 +83,14 @@ def as_dict(self) -> Dict: result.update(self.pdf_options.as_dict) if self.append_per_page is not None: result["output_append_per_page"] = self.append_per_page + if self.prepend_per_page is not None: + result["output_prepend_per_page"] = self.prepend_per_page + if self.output_polling is not None: + result['output_polling'] = self.output_polling + if self.secret_key is not None: + result['secret_key'] = self.secret_key + if self.request_option is not None: + result['request_option'] = self.request_option.as_dict return result @property diff --git a/cloudofficeprint/config/pdf.py b/cloudofficeprint/config/pdf.py index 0400a04..8d3aead 100644 --- a/cloudofficeprint/config/pdf.py +++ b/cloudofficeprint/config/pdf.py @@ -1,5 +1,7 @@ import json -from typing import Union, Iterable, Dict, Mapping +from typing import Union, Dict, Mapping + +from ..resource import Base64Resource, ServerPathResource, URLResource class PDFOptions: @@ -9,79 +11,81 @@ class PDFOptions: All of them are optional, which is why passing an instance of this class in an OutputConfig is also optional. """ - def __init__(self, - read_password: str = None, - watermark: str = None, - watermark_font_size: int = None, - watermark_opacity: int = None, - watermark_color: str = None, - watermark_font: str = None, - page_width: Union[str, int] = None, - page_height: Union[str, int] = None, - even_page: bool = None, - merge_making_even: bool = None, - modify_password: str = None, - password_protection_flag: int = None, - lock_form: bool = None, - copies: int = None, - page_margin: Union[int, dict] = None, - landscape: bool = None, - page_format: str = None, - merge: bool = None, - sign_certificate: str = None, - sign_certificate_password: str = None, - identify_form_fields: bool = None, - split: bool = None, - remove_last_page: bool = None): + def __init__( + self, + even_page: bool = None, + merge_making_even: bool = None, + remove_last_page: bool = None, + modify_password: str = None, + read_password: str = None, + password_protection_flag: int = None, + watermark: str = None, + watermark_color: str = None, + watermark_font: str = None, + watermark_opacity: int = None, + watermark_size: int = None, + lock_form: bool = None, + copies: int = None, + page_margin: Union[int, dict] = None, + landscape: bool = None, + page_width: Union[str, int] = None, + page_height: Union[str, int] = None, + page_format: str = None, + merge: bool = None, + split: bool = None, + identify_form_fields: bool = None, + sign_certificate: str = None, + sign_certificate_password: str = None, + ): """ Args: - read_password (str, optional): The password needed to open the PDF. Defaults to None. - watermark (str, optional): Setting this generates a diagonal custom watermark on every page in the PDF file. Defaults to None. - watermark_color (str, optional): You can specify to change watermark color. Accepts css colors. Defaults to black. - watermark_font (str, optional): You can specify to change the font of watermark. Defaults to Aerial. - watermark_opacity (int, optional): You can specify to change the opacity of watermark. Should be in percentage - watermark_font_size (int, optional): You can specify to change the font size of watemark. Should be a number(px) ie: 45 . - page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. - page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. even_page (bool, optional): If you want your output to have even pages, for example printing on both sides after merging, you can set this to be true. Defaults to None. merge_making_even (bool, optional): Merge each given document making even paged. Defaults to None. + remove_last_page (bool, optional): Remove the last page from the given PDF document. Defaults to None. modify_password (str, optional): The password needed to modify the PDF. Defaults to None. + read_password (str, optional): The password needed to open the PDF. Defaults to None. password_protection_flag (int, optional): Bit field explained in the PDF specs in table 3.20 in section 3.5.2, should be given as an integer. [More info](https://pdfhummus.com/post/147451287581/hummus-1058-and-pdf-writer-updates-encryption). Defaults to None. + watermark (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + watermark_color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + watermark_font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + watermark_opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + watermark_size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. lock_form (bool, optional): Locks / flattens the forms in the PDF. Defaults to None. copies (int, optional): Repeats the output pdf for the given number of times. Defaults to None. page_margin (Union[int, dict], optional): Only for HTML to PDF. Margin in px. Returns either a dict containing: { "top": int, "bottom": int, "left": int, "right": int } or just an int to be used on all sides. Defaults to None. landscape (bool, optional): Only for HTML to PDF. If True: the orientation of the output file is landscape; else portrait (default). Defaults to None. + page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. + page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. page_format (str, optional): Only for HTML to PDF. The page format: "a4" (default) or "letter". Defaults to None. merge (bool, optional): If True: instead of returning back a zip file for multiple output, merge it. Defaults to None. - sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. - sign_certificate_password (str, optional): It is possible to sign certificate with password. - identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. split (bool, optional): You can specify to split a PDF in separate files. You will get one file per page in a zip file. Defaults to None. - remove_last_page (bool, optional): You can specify to remove the last page from output file, this is helpful when the last page of output is blank. + identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. + sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. + sign_certificate_password (str, optional): If you are signing with a password protected certificate, you can specify the password as a plain string. Defaults to None. """ - self.read_password: str = read_password - self.watermark: str = watermark - self.watermark_font: str = watermark_font - self.watermark_font_size: str = watermark_font_size - self.watermark_color: str = watermark_color - self.watermark_opacity: str = watermark_opacity - self.page_width: Union[str, int] = page_width - self.page_height: Union[str, int] = page_height self.even_page: bool = even_page self.merge_making_even: bool = merge_making_even + self.remove_last_page: bool = remove_last_page self.modify_password: str = modify_password + self.read_password: str = read_password self.password_protection_flag: int = password_protection_flag + self.watermark: str = watermark + self.watermark_color: str = watermark_color + self.watermark_font: str = watermark_font + self.watermark_opacity: int = watermark_opacity + self.watermark_size: int = watermark_size self.lock_form: bool = lock_form self.copies: int = copies + self.page_margin: Union[int, dict] = page_margin + self._landscape: bool = landscape + self.page_width: Union[str, int] = page_width + self.page_height: Union[str, int] = page_height self.page_format: str = page_format self.merge: bool = merge - self.page_margin: Union[int, dict] = page_margin + self.split: bool = split + self.identify_form_fields: bool = identify_form_fields self.sign_certificate: str = sign_certificate self.sign_certificate_password: str = sign_certificate_password - self._landscape: bool = landscape - self.identify_form_fields: bool = identify_form_fields - self.split: bool = split - self.remove_last_page = remove_last_page def __str__(self) -> str: """Get the string representation of these PDF options. @@ -116,6 +120,8 @@ def as_dict(self) -> Dict: result["output_even_page"] = self.even_page if self.merge_making_even is not None: result["output_merge_making_even"] = self.merge_making_even + if self.remove_last_page is not None: + result["output_remove_last_page"] = self.remove_last_page if self.modify_password is not None: result["output_modify_password"] = self.modify_password if self.read_password is not None: @@ -130,8 +136,8 @@ def as_dict(self) -> Dict: result["output_watermark_font"] = self.watermark_font if self.watermark_opacity is not None: result["output_watermark_opacity"] = self.watermark_opacity - if self.watermark_font_size is not None: - result["output_watermark_size"] = self.watermark_font_size + if self.watermark_size is not None: + result["output_watermark_size"] = self.watermark_size if self.lock_form is not None: result["lock_form"] = self.lock_form if self.copies is not None: @@ -139,6 +145,9 @@ def as_dict(self) -> Dict: if self.page_margin is not None: # For Cloud Office Print versions later than 21.1.1, output_page_margin will also be supported result["page_margin"] = self.page_margin + if self._landscape is not None: + # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported + result["page_orientation"] = self.page_orientation if self.page_width is not None: result["output_page_width"] = self.page_width if self.page_height is not None: @@ -147,21 +156,43 @@ def as_dict(self) -> Dict: result["output_page_format"] = self.page_format if self.merge is not None: result["output_merge"] = self.merge - if self._landscape is not None: - # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported - result["page_orientation"] = self.page_orientation + if self.split is not None: + result["output_split"] = self.split + if self.identify_form_fields is not None: + result["identify_form_fields"] = self.identify_form_fields if self.sign_certificate is not None: result["output_sign_certificate"] = self.sign_certificate if self.sign_certificate_password is not None: - result['output_sign_certificate_password'] = self.sign_certificate_password - if self.identify_form_fields is not None: - result["identify_form_fields"] = self.identify_form_fields - if self.split is not None: - result['output_split'] = self.split - if self.remove_last_page is not None: - result['output_remove_last_page'] = self.remove_last_page + result["output_sign_certificate_password"] = self.sign_certificate_password + return result + def set_watermark( + self, + text: str = None, + color: str = None, + font: str = None, + opacity: int = None, + size: int = None, + ): + """Set watermark + + Set a diagonal custom watermark on every page in the PDF file with a specific text, color, font, opacity and size. + Setting all to None will remove the watermark. + + Args: + text (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. + """ + self.watermark = text + self.watermark_color = color + self.watermark_font = font + self.watermark_opacity = opacity + self.watermark_size = size + def set_page_margin_at(self, value: int, position: str = None): """Set page_margin @@ -177,9 +208,7 @@ def set_page_margin_at(self, value: int, position: str = None): self.page_margin[position] = value elif self.page_margin is None: # page margin not yet defined, set it to a dict with this position defined - self.page_margin = { - position: value - } + self.page_margin = {position: value} else: # page margin defined but no dict, convert to dict first current = self.page_margin @@ -187,7 +216,7 @@ def set_page_margin_at(self, value: int, position: str = None): "top": current, "bottom": current, "left": current, - "right": current + "right": current, } self.page_margin[position] = value else: @@ -210,3 +239,17 @@ def page_orientation(self, value: str): value (str): the page orientation """ self._landscape = value == "landscape" + + def sign( + self, + certificate: Union[Base64Resource, ServerPathResource, URLResource], + password: str = None, + ): + """Sign the output PDF with a certificate file. + + Args: + certificate (str): Resource of the certificate file. + password (str): password of the certificate. Defaults to None. + """ + self.sign_certificate = certificate.data + self.sign_certificate_password = password diff --git a/cloudofficeprint/config/request_option.py b/cloudofficeprint/config/request_option.py new file mode 100644 index 0000000..04481aa --- /dev/null +++ b/cloudofficeprint/config/request_option.py @@ -0,0 +1,15 @@ +class requestOptions: + def __init__(self, + url: str, + extraHeaders: object, + ): + super() + self.url = url + self.extraHeaders = extraHeaders + + @property + def as_dict(self): + result = {} + result['url'] = self.url + result['extra_headers'] = self.extraHeaders + return result diff --git a/cloudofficeprint/config/server.py b/cloudofficeprint/config/server.py index 2d6645d..003241a 100644 --- a/cloudofficeprint/config/server.py +++ b/cloudofficeprint/config/server.py @@ -47,9 +47,7 @@ def _dict(self) -> Dict[str, str]: class Command: """Command object with a single command for the Cloud Office Print server.""" - def __init__(self, - command: str, - parameters: Mapping[str, str] = None): + def __init__(self, command: str, parameters: Mapping[str, str] = None): """ Args: command (str): The name of the command to execute. This command should be present in the aop_config.json file. @@ -65,9 +63,7 @@ def _dict(self) -> Dict[str, str]: Returns: Dict[str, str]: dict representation of this command """ - result = { - "command": self.command - } + result = {"command": self.command} if self.parameters: result["command_parameters"] = self.parameters @@ -96,13 +92,15 @@ def _dict_post(self) -> Dict[str, str]: class Commands: """Command hook configuration class.""" - def __init__(self, - post_process: Command = None, - post_process_return: bool = None, - post_process_delete_delay: int = None, - pre_conversion: Command = None, - post_conversion: Command = None, - post_merge: Command = None): + def __init__( + self, + post_process: Command = None, + post_process_return: bool = None, + post_process_delete_delay: int = None, + pre_conversion: Command = None, + post_conversion: Command = None, + post_merge: Command = None, + ): """ Args: post_process (Command, optional): Command to run after the given request has been processed but before returning back the output file. Defaults to None. @@ -152,13 +150,15 @@ def _dict(self) -> Dict: class ServerConfig: """Class for configuring the server options.""" - def __init__(self, - api_key: str = None, - logging: Mapping = None, - printer: Printer = None, - commands: Commands = None, - proxies: Dict[str, str] = None, - cop_remote_debug: bool = False): + def __init__( + self, + api_key: str = None, + logging: Mapping = None, + printer: Printer = None, + commands: Commands = None, + proxies: Dict[str, str] = None, + cop_remote_debug: bool = False, + ): """ Args: api_key (str, optional): API key to use for communicating with a Cloud Office Print server. Defaults to None. @@ -226,10 +226,9 @@ def url(self, value: str): Args: value (str): URL at which to contact the server """ - if (urlparse(value).scheme == ''): + if urlparse(value).scheme == "": self._url = "http://" + value - logging.warning( - f'No scheme found in "{value}", assuming "{self._url}".') + logging.warning(f'No scheme found in "{value}", assuming "{self._url}".') else: self._url = value @@ -240,8 +239,10 @@ def is_reachable(self) -> bool: bool: whether the server at `Server.url` is reachable """ try: - r = requests.get(urljoin( - self.url, "marco"), proxies=self.config.proxies if self.config is not None else None) + r = requests.get( + urljoin(self.url, "marco"), + proxies=self.config.proxies if self.config is not None else None, + ) return r.text == "polo" except requests.exceptions.ConnectionError: return False @@ -268,8 +269,7 @@ def _raise_if_unreachable(self): ConnectionError: raise error if server is unreachable """ if not self.is_reachable(): - raise ConnectionError( - f"Could not reach server at {self.url}") + raise ConnectionError(f"Could not reach server at {self.url}") def get_version_soffice(self) -> str: """Sends a GET request to server-url/soffice. @@ -278,7 +278,10 @@ def get_version_soffice(self) -> str: str: current version of Libreoffice installed on the server. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'soffice'), proxies=self.config.proxies if self.config is not None else None).text + return requests.get( + urljoin(self.url, "soffice"), + proxies=self.config.proxies if self.config is not None else None, + ).text def get_version_officetopdf(self) -> str: """Sends a GET request to server-url/officetopdf. @@ -287,7 +290,10 @@ def get_version_officetopdf(self) -> str: str: current version of OfficeToPdf installed on the server. (Only available if the server runs in Windows environment). """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'officetopdf'), proxies=self.config.proxies if self.config is not None else None).text + return requests.get( + urljoin(self.url, "officetopdf"), + proxies=self.config.proxies if self.config is not None else None, + ).text def get_supported_template_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_template_mimetypes. @@ -296,7 +302,12 @@ def get_supported_template_mimetypes(self) -> Dict: Dict: JSON of the mime types of templates that Cloud Office Print supports. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_template_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_template_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_output_mimetypes(self, input_type: str) -> Dict: """Sends a GET request to server-url/supported_output_mimetypes?template=input_type. @@ -309,7 +320,14 @@ def get_supported_output_mimetypes(self, input_type: str) -> Dict: Dict: JSON of the supported output types for the given template extension. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_output_mimetypes' + f'?template={input_type}'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin( + self.url, "supported_output_mimetypes" + f"?template={input_type}" + ), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_prepend_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_prepend_mimetypes. @@ -318,7 +336,12 @@ def get_supported_prepend_mimetypes(self) -> Dict: Dict: JSON of the supported prepend file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_prepend_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_prepend_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_append_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_append_mimetypes. @@ -327,7 +350,29 @@ def get_supported_append_mimetypes(self) -> Dict: Dict: JSON of the supported append file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_append_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_append_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) + + def verify_template_hash(self, hashcode: str) -> bool: + """Sends a GET request to server-url/verify_template_hash?hash=hashcode. + + Args: + hashcode (str): md5 hash of file + + Returns: + bool: whether the hash is valid and present in cache. + """ + self._raise_if_unreachable() + return json.loads( + requests.get( + urljoin(self.url, "verify_template_hash" + f"?hash={hashcode}"), + proxies=self.config.proxies if self.config is not None else None, + ).text + )["valid"] def get_version_cop(self) -> str: """Sends a GET request to server-url/version. @@ -336,4 +381,27 @@ def get_version_cop(self) -> str: str: the version of Cloud Office Print that the server runs. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'version'), proxies=self.config.proxies if self.config is not None else None).text + return requests.get( + urljoin(self.url, "version"), + proxies=self.config.proxies if self.config is not None else None, + ).text + + def check_ipp(self, ipp_url: str, version: str) -> Dict: + """Sends a GET request to server-url/ipp_check?ipp_url=ipp_url&version=version. + + Args: + ippURL (str): the URL of the IPP printer. + version (str): the version of the IPP printer. + + Returns: + Dict: the status of the IPP printer. + """ + self._raise_if_unreachable() + return json.loads( + requests.get( + urljoin( + self.url, "ipp_check" + f"?ipp_url={ipp_url}&version={version}" + ), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) diff --git a/cloudofficeprint/elements/elements.py b/cloudofficeprint/elements/elements.py index fff9c51..8a06339 100644 --- a/cloudofficeprint/elements/elements.py +++ b/cloudofficeprint/elements/elements.py @@ -39,7 +39,9 @@ def _dict_suffixes(self) -> Dict: class CellStyleDocx(CellStyle): """Cell styling settings for docx templates""" - def __init__(self, cell_background_color: str = None, width: Union[int, str] = None): + def __init__( + self, cell_background_color: str = None, width: Union[int, str] = None + ): """ Args: cell_background_color (str, optional): The background color of the cell. Defaults to None. @@ -54,9 +56,9 @@ def _dict_suffixes(self): result = super()._dict_suffixes if self.cell_background_color is not None: - result['_cell_background_color'] = self.cell_background_color + result["_cell_background_color"] = self.cell_background_color if self.width is not None: - result['_width'] = self.width + result["_width"] = self.width return result @@ -91,7 +93,7 @@ def __init__( border_diagonal_color: str = None, text_h_alignment: str = None, text_v_alignment: str = None, - text_rotation: Union[int, str] = None + text_rotation: Union[int, str] = None, ): """ Args: @@ -155,63 +157,63 @@ def _dict_suffixes(self): result = super()._dict_suffixes if self.cell_locked is not None: - result['_cell_locked'] = self.cell_locked + result["_cell_locked"] = self.cell_locked if self.cell_hidden is not None: - result['_cell_hidden'] = self.cell_hidden + result["_cell_hidden"] = self.cell_hidden if self.cell_background is not None: - result['_cell_background'] = self.cell_background + result["_cell_background"] = self.cell_background if self.font_name is not None: - result['_font_name'] = self.font_name + result["_font_name"] = self.font_name if self.font_size is not None: - result['_font_size'] = self.font_size + result["_font_size"] = self.font_size if self.font_color is not None: - result['_font_color'] = self.font_color + result["_font_color"] = self.font_color if self.font_italic is not None: - result['_font_italic'] = self.font_italic + result["_font_italic"] = self.font_italic if self.font_bold is not None: - result['_font_bold'] = self.font_bold + result["_font_bold"] = self.font_bold if self.font_strike is not None: - result['_font_strike'] = self.font_strike + result["_font_strike"] = self.font_strike if self.font_underline is not None: - result['_font_underline'] = self.font_underline + result["_font_underline"] = self.font_underline if self.font_superscript is not None: - result['_font_superscript'] = self.font_superscript + result["_font_superscript"] = self.font_superscript if self.font_subscript is not None: - result['_font_subscript'] = self.font_subscript + result["_font_subscript"] = self.font_subscript if self.border_top is not None: - result['_border_top'] = self.border_top + result["_border_top"] = self.border_top if self.border_top_color is not None: - result['_border_top_color'] = self.border_top_color + result["_border_top_color"] = self.border_top_color if self.border_bottom is not None: - result['_border_bottom'] = self.border_bottom + result["_border_bottom"] = self.border_bottom if self.border_bottom_color is not None: - result['_border_bottom_color'] = self.border_bottom_color + result["_border_bottom_color"] = self.border_bottom_color if self.border_left is not None: - result['_border_left'] = self.border_left + result["_border_left"] = self.border_left if self.border_left_color is not None: - result['_border_left_color'] = self.border_left_color + result["_border_left_color"] = self.border_left_color if self.border_right is not None: - result['_border_right'] = self.border_right + result["_border_right"] = self.border_right if self.border_right_color is not None: - result['_border_right_color'] = self.border_right_color + result["_border_right_color"] = self.border_right_color if self.border_diagonal is not None: - result['_border_diagonal'] = self.border_diagonal + result["_border_diagonal"] = self.border_diagonal if self.border_diagonal_direction is not None: - result['_border_diagonal_direction'] = self.border_diagonal_direction + result["_border_diagonal_direction"] = self.border_diagonal_direction if self.border_diagonal_color is not None: - result['_border_diagonal_color'] = self.border_diagonal_color + result["_border_diagonal_color"] = self.border_diagonal_color if self.text_h_alignment is not None: - result['_text_h_alignment'] = self.text_h_alignment + result["_text_h_alignment"] = self.text_h_alignment if self.text_v_alignment is not None: - result['_text_v_alignment'] = self.text_v_alignment + result["_text_v_alignment"] = self.text_v_alignment if self.text_rotation is not None: - result['_text_rotation'] = self.text_rotation + result["_text_rotation"] = self.text_rotation return result class Element(ABC): - """ The abstract base class for elements.""" + """The abstract base class for elements.""" def __init__(self, name: str): """ @@ -292,9 +294,7 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - return { - self.name: self.value - } + return {self.name: self.value} class CellStyleProperty(Property): @@ -314,9 +314,7 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} for suffix, value in self.cell_style._dict_suffixes.items(): result[self.name + suffix] = value @@ -369,18 +367,20 @@ def available_tags(self) -> FrozenSet[str]: class AutoLink(Property): """ This tag allows you to insert text into the document detecting links. """ + def __init__(self, name: str, value: str): """ Args: name (str): The name for this element. value (str): The value of the autoLink. """ - super().__init__(name,value) + super().__init__(name, value) @property def available_tags(self) -> FrozenSet[str]: return frozenset({"{*auto " + self.name + "}"}) + class Hyperlink(Element): def __init__(self, name: str, url: str, text: str = None): """ @@ -399,9 +399,7 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.url - } + result = {self.name: self.url} if self.text is not None: result[self.name + "_text"] = self.text @@ -410,7 +408,9 @@ def as_dict(self) -> Dict: class TableOfContents(Element): - def __init__(self, name: str, title: str = None, depth: int = None, tab_leader: str = None): + def __init__( + self, name: str, title: str = None, depth: int = None, tab_leader: str = None + ): """ Args: name (str): The name for this element. @@ -477,7 +477,7 @@ def as_dict(self) -> Dict: return { self.name: self.value, self.name + "_row_span": self.rows, - self.name + "_col_span": self.columns + self.name + "_col_span": self.columns, } @@ -496,17 +496,19 @@ def available_tags(self) -> FrozenSet[str]: class StyledProperty(Property): - def __init__(self, - name: str, - value: str, - font: str = None, - font_size: Union[str, int] = None, - font_color: str = None, - bold: bool = None, - italic: bool = None, - underline: bool = None, - strikethrough: bool = None, - highlight_color: str = None): + def __init__( + self, + name: str, + value: str, + font: str = None, + font_size: Union[str, int] = None, + font_color: str = None, + bold: bool = None, + italic: bool = None, + underline: bool = None, + strikethrough: bool = None, + highlight_color: str = None, + ): """ Args: name (str): The name for this property. @@ -536,9 +538,7 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: result[self.name + "_font_family"] = self.font @@ -561,15 +561,17 @@ def as_dict(self) -> Dict: class Watermark(Property): - def __init__(self, - name: str, - text: str, - color: str = None, - font: str = None, - width: Union[int, str] = None, - height: Union[int, str] = None, - opacity: float = None, - rotation: int = None): + def __init__( + self, + name: str, + text: str, + color: str = None, + font: str = None, + width: Union[int, str] = None, + height: Union[int, str] = None, + opacity: float = None, + rotation: int = None, + ): """ Args: name (str): The name for this property. @@ -595,9 +597,7 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.color is not None: result[self.name + "_color"] = self.color @@ -633,12 +633,10 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.code - } + result = {self.name: self.code} if self.data is not None: - result[self.name + '_data'] = self.data + result[self.name + "_data"] = self.data return result @@ -646,15 +644,14 @@ def as_dict(self) -> Dict: class COPChartDateOptions: """Date options for an COPChart (different from ChartDateOptions in charts.py).""" - def __init__(self, - format: str = None, - unit: str = None, - step: Union[int, str] = None): + def __init__( + self, format: str = None, unit: str = None, step: Union[int, str] = None + ): """ Args: format (str, optional): The format to display the date on the chart's axis. Defaults to None. unit (str, optional): The unit to be used for spacing the axis values. Defaults to None. - step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined). + step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined). This option is not supported in LibreOffice. Defaults to None. """ self.format: str = format @@ -678,16 +675,21 @@ def as_dict(self) -> Dict: class COPChart(Element): """The class for an COPChart. This is used for chart templating.""" - def __init__(self, - name: str, - x_data: Iterable[Union[str, int, float, Mapping]], - y_datas: Union[Iterable[Iterable[Union[str, int, float, Mapping]]], Mapping[str, Iterable[Union[str, int, float, Mapping]]]], - date: COPChartDateOptions = None, - title: str = None, - x_title: str = None, - y_title: str = None, - y2_title: str = None, - x2_title: str = None): + def __init__( + self, + name: str, + x_data: Iterable[Union[str, int, float, Mapping]], + y_datas: Union[ + Iterable[Iterable[Union[str, int, float, Mapping]]], + Mapping[str, Iterable[Union[str, int, float, Mapping]]], + ], + date: COPChartDateOptions = None, + title: str = None, + x_title: str = None, + y_title: str = None, + y2_title: str = None, + x2_title: str = None, + ): """ Args: name (str): The name for this element. @@ -711,16 +713,15 @@ def __init__(self, self.y_datas: Dict[str, Iterable[Union[str, int, float]]] = None """If the argument 'y_datas' is of type Iterable[Iterable], then default names (e.g. series 1, series 2, ...) will be used.""" if isinstance(y_datas, Mapping): - self.y_datas = { - name: list(data) for name, data in y_datas.items() - } + self.y_datas = {name: list(data) for name, data in y_datas.items()} elif isinstance(y_datas, Iterable): self.y_datas = { f"series {i+1}": list(data) for i, data in enumerate(y_datas) } else: raise TypeError( - f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"') + f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"' + ) self.date: COPChartDateOptions = date self.title: str = title @@ -730,15 +731,17 @@ def __init__(self, self.y2_title: str = y2_title @classmethod - def from_dataframe(cls, - name: str, - data: 'pandas.DataFrame', - date: COPChartDateOptions = None, - title: str = None, - x_title: str = None, - y_title: str = None, - y2_title: str = None, - x2_title: str = None) -> 'COPChart': + def from_dataframe( + cls, + name: str, + data: "pandas.DataFrame", + date: COPChartDateOptions = None, + title: str = None, + x_title: str = None, + y_title: str = None, + y2_title: str = None, + x2_title: str = None, + ) -> "COPChart": """Construct an COPChart object from a [Pandas dataframe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html). Args: @@ -761,7 +764,9 @@ def from_dataframe(cls, for col_name, col_data in y_frame.iteritems(): y_datas[col_name] = col_data - return cls(name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title) + return cls( + name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title + ) @property def as_dict(self) -> Dict: @@ -770,26 +775,25 @@ def as_dict(self) -> Dict: "data": self.x_data, }, "yAxis": { - "series": [{ - "name": name, - "data": data - } for name, data in self.y_datas.items()] - } + "series": [ + {"name": name, "data": data} for name, data in self.y_datas.items() + ] + }, } if self.title is not None: result["title"] = self.title if self.date is not None: - result['xAxis']['date'] = self.date.as_dict + result["xAxis"]["date"] = self.date.as_dict if self.x_title is not None: result["xAxis"]["title"] = self.x_title if self.y_title is not None: result["yAxis"]["title"] = self.y_title if self.x2_title is not None: - result['x2Axis'] = {} + result["x2Axis"] = {} result["x2Axis"]["title"] = self.x2_title if self.y2_title is not None: - result['y2Axis'] = {} + result["y2Axis"] = {} result["y2Axis"]["title"] = self.y2_title return {self.name: result} @@ -835,15 +839,17 @@ def available_tags(self) -> FrozenSet[str]: class TextBox(Element): """This tag will allow you to insert a text box starting in the cell containing the tag in Excel.""" - def __init__(self, - name: str, - value: str, - font: str = None, - font_color: str = None, - font_size: Union[int, str] = None, - transparency: Union[int, str] = None, - width: Union[int, str] = None, - height: Union[int, str] = None): + def __init__( + self, + name: str, + value: str, + font: str = None, + font_color: str = None, + font_size: Union[int, str] = None, + transparency: Union[int, str] = None, + width: Union[int, str] = None, + height: Union[int, str] = None, + ): """ Args: name (str): The name for this element. @@ -870,22 +876,20 @@ def available_tags(self) -> FrozenSet[str]: @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: - result[self.name + '_font'] = self.font + result[self.name + "_font"] = self.font if self.font_color is not None: - result[self.name + '_font_color'] = self.font_color + result[self.name + "_font_color"] = self.font_color if self.font_size is not None: - result[self.name + '_font_size'] = self.font_size + result[self.name + "_font_size"] = self.font_size if self.transparency is not None: - result[self.name + '_transparency'] = self.transparency + result[self.name + "_transparency"] = self.transparency if self.width is not None: - result[self.name + '_width'] = self.width + result[self.name + "_width"] = self.width if self.height is not None: - result[self.name + '_height'] = self.height + result[self.name + "_height"] = self.height return result @@ -910,21 +914,375 @@ def available_tags(self) -> FrozenSet[str]: class Insert(Property): - """Inside Word and PowerPoint documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents.""" + """Inside Word and PowerPoint and Excel documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents. + Please use `ExcelInsert` element to insert in excel with more flexibility. + """ + + def __init__(self, name: str, value: str): + """ + Args: + name (str): The name for the insert tag. + value (str): Base64 encoded document that needs to be inserted in output docx or pptx. + The documnet can be docx, pptx, xlsx, or pdf documents. + """ + super().__init__(name, value) + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{?insert " + self.name + "}"}) + + +class ExcelInsert(Element): + """Inside Excel it is posiible to insert word, powerpoint, excel and pdf file using AOP tag {?insert fileToInsert}. + Options available are: you can provide dynamic icon and icon position. """ - Args: - name (str): The name for the insert tag. - value (str): Base64 encoded document that needs to be inserted in output docx or pptx. - The documnet can be docx, pptx, xlsx, or pdf documents. + + def __init__(self, + name: str, + value: str, + # isPreview: bool = None, + icon: str = None, + fromRow: int = None, + fromCol: Union[str, int] = None, + fromRowOff: str = None, + fromColOff: str = None, + toRow: int = None, + toCol: Union[str, int] = None, + toRowOff: str = None, + toColOff: str = None + ): + """It is possible to provide dynamic icon and position of icon. + + Args: + name (str): Name of insert tag. Ex(fileToInsert) + value (str): File to insert of path to file. (Source can be FTP, SFTP, URL or base64encoded file.) + icon (str, optional): Icon that links the file to insert. Once clicked on it, opens the file inserted. If it is not provide default icon is used. + fromRow (int, optional): position for top of icon. Defaults to row of the tag. + fromCol (Union[str,int], optional): positon for left of icon. Defaults to column of the tag. + fromRowOff (str, optional): space after the value of from Row. Defaults to 0. + fromColOff (str, optional): space after the value of fromCol. Defaults to 0. + toRow (int, optional): position for bottom of icon. Defaults to row of the tag + 3. + toCol (Union[str,int], optional): position for right side of icon. Defaults to column of the tag. + toRowOff (str, optional): space after toRow value. Defaults to 20px. + toColOff (str, optional): space after toCol value. Defaults to 50px. + """ + super().__init__(name) + self.value: str = value + # self.isPreview: bool = isPreview + self.icon: str = icon + self.fromRow: int = fromRow + self.fromCol: Union[str, int] = fromCol + self.fromRowOff: str = fromRowOff + self.fromColOff: str = fromColOff + self.toRow: int = toRow + self.toCol: Union[str, int] = toCol + self.toRowOff: str = toRowOff + self.toColOff: str = toColOff + + @property + def as_dict(self) -> Dict: + result = { + self.name: self.value + } + # if self.isPreview is not None: + # result[self.name+'_isPreview'] = self.isPreview + if self.icon is not None: + result[self.name+'_icon'] = self.icon + if self.fromRow is not None: + result[self.name+'_fromRow'] = self.fromRow + if self.fromCol is not None: + result[self.name+'_fromCol'] = self.fromCol + if self.fromRowOff is not None: + result[self.name+'_fromRowOff'] = self.fromRowOff + if self.fromColOff is not None: + result[self.name+'_fromColOff'] = self.fromColOff + if self.toRow is not None: + result[self.name+'_toRow'] = self.toRow + if self.toCol is not None: + result[self.name+'_toCol'] = self.toCol + if self.toRowOff is not None: + result[self.name+'_toRowOff'] = self.toRowOff + if self.toColOff is not None: + result[self.name+'_toColOff'] = self.toColOff + + return result + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{?insert fileToInsert}"}) + + +class Embed(Property): + """Inside Word, it is possible to copy the content of one docx file to the template without rendering. + + To do so, you can use AOP embed tag as {?embed fileToEmbed} where fileToEmbed contains the path of file or file itself. + + The content of fileToEmbed replaces the tag + + Only supported in Word and only supports docx file to embed. """ def __init__(self, name: str, value: str): + """It takes the tagName and its value as parameter. + + Args: + name (str): Name of the tag (ex. fileToEmbed) + value (str): File to embed. Source can be FTP, SFTP, URL or base64 encoded file. (ex. base64encoded string) + """ super().__init__(name, value) @property def available_tags(self) -> FrozenSet[str]: - return frozenset({"{?insert " + self.name + "}"}) + return frozenset({"{?embed fileToEmbed}"}) + + +class SheetProtection(Element): + """Inside Excel documents, this tag can be used to make password protected sheets. This tag has the feature of password along with different other features. + + Note: value is considered password, so try to use only one (either value or passowrd). + """ + + def __init__(self, + name: str, + value: str = None, + autoFilter: str = None, + deleteColumns: bool = None, + deleteRows: bool = None, + formatCells: bool = None, + formatColumns: bool = None, + formatRows: bool = None, + insertColumns: bool = None, + insertHyperlinks: bool = None, + insertRows: bool = None, + password: str = None, + pivotTables: bool = None, + selectLockedCells: bool = None, + selectUnlockedCells: bool = None, + sort: bool = None, + ): + """ + Args: + name (str): The name for the sheet protection tag. + value (str): Value for the tag; this is used as password + autoFilter (str): lock auto filter in sheet. + deleteColumns (bool): lock delete columns in sheet. + deleteRows (bool): lock delete rows in sheet. + formatCells (bool): lock format cells. + formatColumns (bool): lock format columns. + formatRows (bool): lock format rows. + insertColumns (bool): lock insert columns. + insertHyperlinks (bool): lock insert hyperlinks. + insertRows (bool): lock insert rows. + password (str): password to lock with. + pivotTables (bool): lock pivot tables. + selectLockedCells (bool): lock select locked cells. + selectUnlockedCells (bool): lock select unlocked cells. + sort (bool): lock sort. + """ + super().__init__(name) + self.value = value + self.autoFilter = autoFilter + self.deleteColumns = deleteColumns + self.deleteRows = deleteRows + self.formatCells = formatCells + self.formatColumns = formatColumns + self.formatRows = formatRows + self.insertColumns = insertColumns + self.insertHyperlinks = insertHyperlinks + self.insertRows = insertRows + self.password = password + self.pivotTables = pivotTables + self.selectLockedCells = selectLockedCells + self.selectUnlockedCells = selectUnlockedCells + self.sort = sort + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{protect " + self.name + "}"}) + + @property + def as_dict(self) -> Dict: + result = {} + if self.value is not None: + result[self.name] = self.value + if self.autoFilter is not None: + result[self.name+'_allow_auto_filter'] = self.autoFilter + if self.deleteColumns is not None: + result[self.name+'_allow_delete_columns'] = self.deleteColumns + if self.deleteRows is not None: + result[self.name+'_allow_delete_rows'] = self.deleteRows + if self.formatCells is not None: + result[self.name+'_allow_format_cells'] = self.formatCells + if self.formatColumns is not None: + result[self.name+'_allow_format_columns'] = self.formatColumns + if self.formatRows is not None: + result[self.name+'_allow_format_rows'] = self.formatRows + if self.insertColumns is not None: + result[self.name+'_allow_insert_columns'] = self.insertColumns + if self.insertHyperlinks is not None: + result[self.name+'_allow_insert_hyperlinks'] = self.insertHyperlinks + if self.insertRows is not None: + result[self.name+'_allow_insert_rows'] = self.insertRows + if self.password is not None: + result[self.name+'_password'] = self.password + if self.pivotTables is not None: + result[self.name+'_allow_pivot_tables'] = self.pivotTables + if self.selectLockedCells is not None: + result[self.name+'_allow_select_locked_cells'] = self.selectLockedCells + if self.selectUnlockedCells is not None: + result[self.name+'_allow_select_unlocked_cells'] = self.selectUnlockedCells + if self.sort is not None: + result[self.name+'_allow_sort'] = self.sort + return result + + +class ValidateCell(Element): + """ + It is possible to insert cell validation in excel using validate tag as {validate validateTag} (validate keyword followed by tagName) + """ + + def __init__(self, + name: str, + ignoreBlank: bool = None, + allow: str = None, + value1: str = None, + value2: str = None, + inCellDropdown: bool = None, + data: str = None, + showInputMessage: bool = None, + inputTitle: str = None, + inputMessage: str = None, + showErrorAlert: bool = None, + errorStyle: str = None, + errorTitle: str = None, + errorMessage: str = None, + ): + """Available option while using validate cell are ( ignoreBlank, allow, value1, value2, inCellDropdown, data, showInputMessage, inputTitle, inputMessage, showErrorAlert, errorStyle, errorTitle,errorMessage ) + + Args: + name (string, optional): Name of the validate tag. For {validate tagName}, tagName is name for this element. + ignoreBlank (bool, optional): Set it to false for not allowing empty values in cell. The value is true by default. + allow (string, optional): Type of data used for validation. Available options are (anyValue, whole, decimal, list, date, time, textLength, custom). Please use camelCase to insert value for allow attribute. + value1 (string, optional): Value to compare with. + value2 (string, optional): Value to compare with.
+ Note: + These two options (_value1, _value2) can be used for any allow/type of validation that require values for comparison, in such case use "_value1" attribute as the first value to be passed and "_value2" attribute as the 2nd value.

+ Some allow type of validation require only one value to compare; in such case use "_value1" attribute.

+ For ex :
+ If allow type of validation is date and you have to check in between two dates.
+ Then you could use "_value1" attribute as start date and "_value2" attribute as end date.

+ If allow type of validation is whole and you have to check for value less than 100.
+ Then you could use "_value1" for that value and do not use "_value2".

+ While using time and date as allow type validation, please provide date/time with correct formatting.
+ for time: hours:minutes:seconds i.e hours , minutes, seconds separated by colon (:)
+ ex : 14:30:00 for 2:30 pm

+ for date: month/day/year i.e day, month , year separated by forward slash(/)
+ ex : 02/07/2023 for Feb 7 2023.

+ for list: you could use normal string with elements separated by comma(,).
+ ex : "first, second, third" for list of three elements.
+ inCellDropdown (bool, optional): Set it to false for not showing dropdown button while validation allow type is list. It is true by default for list allow type. + data (string, optional): Type of comparison to be done for the cell value. Available values are (lessThanOrEqual, notBetween, equal, notEqual, greaterThan, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual). Default value is "between". Please use camelCase for the value as shown in examples. + showInputMessage (bool, optional): Set it to false to hide message shown when the cell to validate is being selected. The value for it is true by default. + inputTitle (string, optional): Title of message to be shown when cell to validate is selected. + inputMessage (string, optional): Message to be shown when cell to validate is selected. + showErrorAlert (bool, optional): Set it to false, if you want to hide error alert once cell validation fails. The value is true by default. + errorStyle (string, optional): Type of error style when cell validation fails. The value is stop by default. Available options are(stop,waring, Information). + errorTitle (string, optional): Title of error to be shown when cell validation fails. + errorMessage (string, optional): Message of error to be shown when cell validation fails. + """ + super().__init__(name) + self.ignoreBlank = ignoreBlank + self.allow = allow + self.value1 = value1 + self.value2 = value2 + self.inCellDropdown = inCellDropdown + self.data = data + self.showInputMessage = showInputMessage + self.inputTitle = inputTitle + self.inputMessage = inputMessage + self.showErrorAlert = showErrorAlert + self.errorStyle = errorStyle + self.errorTitle = errorTitle + self.errorMessage = errorMessage + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{validate " + self.name + "}"}) + + @property + def as_dict(self) -> Dict: + result = {} + if self.ignoreBlank is not None: + result[self.name + '_ignore_blank'] = self.ignoreBlank + if self.allow is not None: + result[self.name + '_allow'] = self.allow + if self.value1 is not None: + result[self.name + '_value1'] = self.value1 + if self.value2 is not None: + result[self.name + '_value2'] = self.value2 + if self.inCellDropdown is not None: + result[self.name + '_in_cell_dropdown'] = self.inCellDropdown + if self.data is not None: + result[self.name + '_data'] = self.data + if self.showInputMessage is not None: + result[self.name + '_show_input_message'] = self.showInputMessage + if self.inputTitle is not None: + result[self.name + '_input_title'] = self.inputTitle + if self.inputMessage is not None: + result[self.name + '_input_message'] = self.inputMessage + if self.showErrorAlert is not None: + result[self.name + '_show_error_alert'] = self.showErrorAlert + if self.errorStyle is not None: + result[self.name + '_error_style'] = self.errorStyle + if self.errorTitle is not None: + result[self.name + '_error_title'] = self.errorTitle + if self.errorMessage is not None: + result[self.name + '_error_message'] = self.errorMessage + return result + + +class Link(Property): + """The class for the link/target tags. + This tags allows you to place a link to a target in the same document. + If the uid is not provided, a new uid will be generated uniquely for every link and target pair. + """ + + def __init__( + self, + name: str, + value: str, + uid_name: str = None, + uid_value: str = None, + ): + """Create a new link/target tag pair. + If the uid is not provided, a new uid will be generated uniquely for each link/target pair. + + Args: + name (str): the name of the link/target tags. + value (str): the value of the link/target tags. + uid_name (str): the name of the uid of the link/target pair. + uid_value (str): the value of the uid of the link/target pair. + """ + super().__init__(name, value) + self.uid_name = uid_name + self.uid_value = uid_value + + @property + def available_tags(self) -> FrozenSet[str]: + if self.uid_name and self.uid_value: + return frozenset( + { + "{link" + self.name + ":" + self.uid_name + "}", + "{target" + self.name + ":" + self.uid_name + "}", + } + ) + return frozenset({"{link" + self.name + "}", "{target" + self.name + "}"}) + + @property + def as_dict(self) -> Dict: + if self.uid_name and self.uid_value: + return {self.name: self.value, self.uid_name: self.uid_value} + return {self.name: self.value} class ElementCollection(list, Element): @@ -956,14 +1314,14 @@ def __repr__(self) -> str: """ return self.json - def copy(self) -> 'ElementCollection': + def copy(self) -> "ElementCollection": """ Returns: ElementCollection: A copy of this element collection. """ return self.__class__(self) - def deepcopy(self) -> 'ElementCollection': + def deepcopy(self) -> "ElementCollection": """ Returns: ElementCollection: A deep copy of this element collection. @@ -982,7 +1340,7 @@ def add(self, element: Element): """ self.append(element) - def add_all(self, obj: 'ElementCollection'): + def add_all(self, obj: "ElementCollection"): """Add all the elements in the given collection to this collection. Args: @@ -998,8 +1356,7 @@ def remove_element_by_name(self, element_name: str): element_name (str): the name of the element that needs to be removed """ self.remove( - next(element for element in self if element.name == element_name) - ) + next(element for element in self if element.name == element_name)) @property def as_dict(self) -> Dict: @@ -1024,7 +1381,9 @@ def available_tags(self) -> FrozenSet[str]: return frozenset(result) @classmethod - def element_to_element_collection(cls, element: Element, name: str = "") -> 'ElementCollection': + def element_to_element_collection( + cls, element: Element, name: str = "" + ) -> "ElementCollection": """Generate an element collection from an element and a name. Args: @@ -1037,7 +1396,7 @@ def element_to_element_collection(cls, element: Element, name: str = "") -> 'Ele return cls.from_mapping(element.as_dict, name) @classmethod - def from_mapping(cls, mapping: Mapping, name: str = "") -> 'ElementCollection': + def from_mapping(cls, mapping: Mapping, name: str = "") -> "ElementCollection": """Generate an element collection from a mapping and a name. Args: @@ -1053,7 +1412,7 @@ def from_mapping(cls, mapping: Mapping, name: str = "") -> 'ElementCollection': return cls(name, result_set) @classmethod - def from_json(cls, json_str: str, name: str = "") -> 'ElementCollection': + def from_json(cls, json_str: str, name: str = "") -> "ElementCollection": """Generate an element collection from a JSON string. Args: diff --git a/cloudofficeprint/printjob.py b/cloudofficeprint/printjob.py index c5be0a4..11ac545 100644 --- a/cloudofficeprint/printjob.py +++ b/cloudofficeprint/printjob.py @@ -2,20 +2,21 @@ Module containing the PrintJob class, which is also exposed at package level. """ -from cloudofficeprint.elements.rest_source import RESTSource import requests import asyncio import json -from .config import OutputConfig, Server -from .exceptions import COPError -from .response import Response -from .resource import Resource -from .elements import Element, ElementCollection + from typing import Union, List, Dict, Mapping from functools import partial -import sys from pprint import pprint +from .config import OutputConfig, Server +from .elements import Element, RESTSource +from .exceptions import COPError +from .resource import Resource +from .template import Template +from .response import Response + STATIC_OPTS = { "tool": "python", # "version": "18.2", # optional: version of Cloud Office Print JSON format @@ -30,31 +31,32 @@ class PrintJob: and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server. """ - def __init__(self, - data: Union[Element, Mapping[str, Element], RESTSource], - server: Server, - template: Resource = None, - output_config: OutputConfig = OutputConfig(), - subtemplates: Dict[str, Resource] = {}, - prepend_files: List[Resource] = [], - append_files: List[Resource] = [], - cop_verbose: bool = False): + def __init__( + self, + data: Union[Element, Mapping[str, Element], RESTSource], + server: Server, + template: Union[Template, Resource] = None, + output_config: OutputConfig = OutputConfig(), + subtemplates: Dict[str, Resource] = {}, + prepend_files: List[Resource] = [], + append_files: List[Resource] = [], + cop_verbose: bool = False, + ): """ Args: data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0". server (Server): Server to be used for this print job. - template (Resource): Template to use for this print job. + template (Union[Template, Resource]): Template to use for this print job. output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`(). subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}. prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to []. append_files (List[Resource], optional): Files to append to the output file. Defaults to []. cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False. """ - self.data: Union[Element, Mapping[str, Element], RESTSource] = data self.server: Server = server self.output_config: OutputConfig = output_config - self.template: Resource = template + self.template: Union[Template, Resource] = template self.subtemplates: Dict[str, Resource] = subtemplates self.prepend_files: List[Resource] = prepend_files self.append_files: List[Resource] = append_files @@ -67,7 +69,18 @@ def execute(self) -> Response: Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response) async def execute_async(self) -> Response: """Async version of `PrintJob.execute` @@ -76,16 +89,22 @@ async def execute_async(self) -> Response: Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) @staticmethod def execute_full_json(json_data: str, server: Server) -> Response: @@ -99,7 +118,14 @@ def execute_full_json(json_data: str, server: Server) -> Response: Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"})) + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response) @staticmethod async def execute_full_json_async(json_data: str, server: Server) -> Response: @@ -113,17 +139,18 @@ async def execute_full_json_async(json_data: str, server: Server) -> Response: Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + return PrintJob._handle_response(response) @staticmethod def _handle_response(res: requests.Response) -> Response: @@ -160,8 +187,8 @@ def as_dict(self) -> Dict: Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -176,43 +203,41 @@ def as_dict(self) -> Dict: # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result diff --git a/cloudofficeprint/resource.py b/cloudofficeprint/resource.py index e39f60f..e57f86c 100644 --- a/cloudofficeprint/resource.py +++ b/cloudofficeprint/resource.py @@ -12,77 +12,67 @@ import json from typing import Dict, Union -from .own_utils import type_utils, file_utils from abc import abstractmethod, ABC +from .own_utils import type_utils, file_utils + class Resource(ABC): """The abstract base class for the resources.""" - def __init__(self, data: Union[str, bytes] = None, filetype: str = None): - """ + def __init__( + self, + data: Union[str, bytes] = None, + filetype: str = None, + ): + """Create a new Resource. + Args: - data (Union[str, bytes], optional): the data for this resource. Defaults to None. - filetype (str, optional): the file type of this resource. Defaults to None. + data (Union[str, bytes], optional): the data for this Resource. Defaults to None. + filetype (str, optional): the file type of this Resource. Defaults to None. """ - self._data: Union[str, bytes] = data + self.data: Union[str, bytes] = data self.filetype: str = filetype @property def mimetype(self) -> str: - """Resource type as a mime type. - - Returns: - str: resource type as a mime type """ - return type_utils.extension_to_mimetype(self.filetype) - - @property - def data(self) -> Union[str, bytes]: - """The data contained in this Resource. - Returns: - Union[str, bytes]: the data contained in this Resource + str: the mime type of the Resource """ - return self._data + return type_utils.extension_to_mimetype(self.filetype) @property def template_json(self) -> str: - """Get the JSON representation when used as a template. - + """ Returns: - str: JSON representation of this resource as a template + str: the JSON representation of this Resource. """ return json.dumps(self.template_dict) @property @abstractmethod def template_dict(self) -> Dict: - """This Resource object as a dict object for use as a template. - This dict and the template JSON representation (`Resource.template_json`) are isomorphic. - + """ Returns: - Dict: dict representation of this resource as a template + Dict: the dictionary representation of this Resource. """ pass @property def secondary_file_json(self) -> str: - """The JSON representation for use as secondary file. - + """ Returns: - str: JSON representation of this resource as a secondary file + str: the JSON representation of this Resource. """ return json.dumps(self.secondary_file_dict) @property @abstractmethod def secondary_file_dict(self) -> Dict: - """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate). - This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic. - + """ Returns: - Dict: dict representation of this resource as a secondary file + Dict: the dictionarty representation of this resource as a secondary file (prepend, append, insert, as subtemplate). """ pass @@ -90,91 +80,91 @@ def __str__(self) -> str: """Override the string representation of this class to return the template-style json. Returns: - str: JSON representation of this resource as a template + str: the JSON representation of this resource as a template. """ return self.template_json @staticmethod - def from_base64(base64string: str, filetype: str) -> 'Base64Resource': - """Create a Base64Resource from a base64 string and a file type (extension). + def from_raw(raw_data: bytes, filetype: str) -> "RawResource": + """Create a RawResource from raw file data. Args: - base64string (str): base64 encoded string - filetype (str): file type (extension) + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). Returns: - Base64Resource: the created Resource + RawResource: the created RawResource. """ - return Base64Resource(base64string, filetype) + return RawResource(raw_data, filetype) @staticmethod - def from_raw(raw_data: bytes, filetype: str) -> 'RawResource': - """Create a RawResource from raw file data and a file type (extension). + def from_base64(base64string: str, filetype: str) -> "Base64Resource": + """Create a Base64Resource from a base64 string. Args: - raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object) - filetype (str): file type (extension) + base64string (str): the base64 encoded representation of a file. + filetype (str): the file type (extension). Returns: - RawResource: the created Resource + Base64Resource: the created Base64Resource. """ - return RawResource(raw_data, filetype) + return Base64Resource(base64string, filetype) @staticmethod - def from_local_file(local_path: str) -> 'Base64Resource': + def from_local_file(local_path: str) -> "Base64Resource": """Create a Base64Resource with the contents of a local file. + The filetype is determined by the extension of the file. Throws IOError if it can't read the file. - The filetype is determined by the extension of the file. Args: - local_path (str): path to local file + local_path (str): the path to local file. Returns: - Base64Resource: the created Resource + Base64Resource: the created Base64Resource. """ - base64string: str = file_utils.read_file_as_base64(local_path) - return Base64Resource(base64string, type_utils.path_to_extension(local_path)) + return Base64Resource( + file_utils.read_file_as_base64(local_path), + type_utils.path_to_extension(local_path), + ) @staticmethod - def from_server_path(path: str) -> 'ServerPathResource': + def from_server_path(path: str) -> "ServerPathResource": """Create a ServerPathResource targeting a file on the server. - The filetype is determined by the extension of the file. Args: - path (str): location of target file on the server + path (str): the location of target file on the server. Returns: - ServerPathResource: the created Resource + ServerPathResource: the created ServerPathResource. """ return ServerPathResource(path) @staticmethod - def from_url(url: str, filetype: str) -> 'URLResource': - """Create an Resource targeting the file at url with given filetype (extension). + def from_url(url: str, filetype: str) -> "URLResource": + """Create an URLResource targeting the file at a given URL. Args: - url (str): file url - filetype (str): file type (extension) + url (str): the file URL. + filetype (str): the file type (extension). Returns: - URLResource: the created Resource + URLResource: the created URLResource. """ return URLResource(url, filetype) @staticmethod - def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource': + def from_html(htmlstring: str, landscape: bool = False) -> "HTMLResource": """Create an HTMLResource with html data in plain text. - Landscape is not supported for prepend/append sources, only for template resources. Args: - htmlstring (str): html content - landscape (bool, optional): whether to use the landscape option. Defaults to False. + htmlstring (str): the html content. + landscape (bool, optional): whether or not to use the landscape option. Defaults to False. Returns: - HTMLResource: the created Resource + HTMLResource: the created HTMLResource. """ return HTMLResource(htmlstring, landscape) @@ -183,62 +173,83 @@ class RawResource(Resource): """A `Resource` containing raw binary data.""" def __init__(self, raw_data: bytes, filetype: str): - """ + """Create a new RawResource. + Args: - raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object) - filetype (str): file type (extension) + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). """ super().__init__(raw_data, filetype) @property def base64(self) -> str: - """Base64 representation of the raw data in `RawResource.data`. - + """ Returns: - str: base64 representation of the raw data in `RawResource.data` + str: the base64 representation of the raw data in `RawResource.data`. """ return file_utils.raw_to_base64(self.data) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "file": self.base64 + "file": self.base64, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "base64", - "file_content": self.base64 + "file_content": self.base64, } class Base64Resource(Resource): """A `Resource` containing base64 data.""" - def __init__(self, base64string: str, filetype: str): - """ + def __init__( + self, + base64string: str, + filetype: str, + ): + """Create a new Base64Resource. + Args: - base64string (str): base64 encoded file - filetype (str): file type (extension) + base64string (str): the base64 encoded data. + filetype (str): the file type (extension). """ super().__init__(base64string, filetype) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "file": self.data + "file": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "base64", - "file_content": self.data + "file_content": self.data, } @@ -246,25 +257,34 @@ class ServerPathResource(Resource): """A `Resource` targeting a file on the server.""" def __init__(self, server_path: str): - """ + """Create a new ServerPathResource. + Args: - server_path (str): path on the server to target + server_path (str): the path on the server to target. """ super().__init__(server_path, type_utils.path_to_extension(server_path)) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "filename": self.data + "filename": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "filename": self.data + "filename": self.data, } @@ -272,37 +292,51 @@ class URLResource(Resource): """A `Resource` targeting a file at a URL.""" def __init__(self, url: str, filetype: str): - """ + """Create a new URLResource. + Args: - url (str): URL location of the file - filetype (str): file type (extension) + url (str): the URL location of the file. + filetype (str): the file type (extension). """ super().__init__(url, filetype) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "url": self.data + "url": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "file_url": self.data + "file_url": self.data, } class HTMLResource(Resource): """A Resource containing HTML data in plain text.""" - def __init__(self, htmlstring: str, landscape: bool = False): - """ + def __init__( + self, + htmlstring: str, + landscape: bool = False, + ): + """Create a new HTMLResource. + Args: - htmlstring (str): HTML input in plain text - landscape (bool, optional): Whether the HTML should be rendered as landscape-oriented page. Defaults to False. + htmlstring (str): the HTML input in plain text. + landscape (bool, optional): whether the HTML should be rendered as landscape-oriented page. Defaults to False. """ super().__init__(htmlstring, "html") self.landscape: bool = landscape @@ -315,26 +349,30 @@ def orientation(self) -> str: Orientation is not supported for prepend/append sources, only for template resources. Returns: - str: orientation + str: the orientation. """ return None if not self.landscape else "landscape" @property def template_dict(self) -> Dict: - result = { + """ + Returns: + str: the JSON representation of this resource. + """ + return { "template_type": self.filetype, - "html_template_content": self.data + "html_template_content": self.data, + "orientation": self.orientation, } - if self.orientation is not None: - result["orientation"] = self.orientation - - return result - @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "file_content": self.data + "file_content": self.data, } diff --git a/cloudofficeprint/template.py b/cloudofficeprint/template.py new file mode 100644 index 0000000..c7c3aaa --- /dev/null +++ b/cloudofficeprint/template.py @@ -0,0 +1,281 @@ +import json +from typing import Dict + +from .resource import Resource + + +class Template: + """The Template class""" + + def __init__( + self, + resource: Resource, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ): + """Create a new Template. + + Args: + resource (Resource): the resource of this template. + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + """ + self.resource = resource + self.start_delimiter = start_delimiter + self.end_delimiter = end_delimiter + self.should_hash = should_hash + self.template_hash = template_hash + + def update_hash(self, template_hash: str): + """Update the Template to store a hash. + On the next request to the server, the file data will not be sent, only the hash of the template. + + Args: + template_hash (str): the hash of the template. + """ + self.template_hash = template_hash + self.should_hash = False + + def reset_hash(self, should_hash: bool = True): + """Reset the stored hash of the template. + + Args: + should_hash (bool, optional): whether the template should be hashed on the server. Defaults to True. + """ + self.template_hash = None + self.should_hash = should_hash + + @property + def mimetype(self) -> str: + """ + Returns: + str: the mime type of the Resource + """ + return self.resource.mimetype + + @property + def template_json(self) -> str: + """ + Returns: + str: the JSON representation of this Resource. + """ + return json.dumps(self.template_dict) + + @property + def template_dict(self) -> Dict: + """ + Returns: + Dict: the dictionary representation of this Resource. + """ + if self.template_hash and not self.should_hash: + dict = { + "template_type": self.resource.filetype, + "template_hash": self.template_hash, + } + if self.start_delimiter: + dict["start_delimiter"] = self.start_delimiter + if self.end_delimiter: + dict["end_delimiter"] = self.end_delimiter + return dict + dict = self.resource.template_dict + if self.start_delimiter: + dict["start_delimiter"] = self.start_delimiter + if self.end_delimiter: + dict["end_delimiter"] = self.end_delimiter + if self.should_hash: + dict["should_hash"] = self.should_hash + if self.template_hash: + dict["template_hash"] = self.template_hash + return dict + + def __str__(self) -> str: + """Override the string representation of this class to return the template-style json. + + Returns: + str: the JSON representation of this resource as a template. + """ + return self.template_json + + @staticmethod + def from_raw( + raw_data: bytes, + filetype: str, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a RawResource from raw file data. + + Args: + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_raw(raw_data, filetype), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) + + @staticmethod + def from_base64( + base64string: str, + filetype: str, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a Base64Resource from a base64 string. + + Args: + base64string (str): the base64 encoded representation of a file. + filetype (str): the file type (extension). + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_base64(base64string, filetype), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) + + @staticmethod + def from_local_file( + local_path: str, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a Base64Resource with the contents of a local file. + The filetype is determined by the extension of the file. + + Throws IOError if it can't read the file. + + Args: + local_path (str): the path to local file. + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_local_file(local_path), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) + + @staticmethod + def from_server_path( + path: str, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a ServerPathResource targeting a file on the server. + The filetype is determined by the extension of the file. + + Args: + path (str): the location of target file on the server. + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_server_path(path), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) + + @staticmethod + def from_url( + url: str, + filetype: str, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a URLResource targeting the file at a given url. + + Args: + url (str): the file URL. + filetype (str): the file type (extension). + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_url(url, filetype), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) + + @staticmethod + def from_html( + htmlstring: str, + landscape: bool = False, + start_delimiter: str = None, + end_delimiter: str = None, + should_hash: bool = None, + template_hash: str = None, + ) -> "Template": + """Create a Template with a HTMLResource with html data in plain text. + + Args: + htmlstring (str): the html content. + landscape (bool, optional): whether or not to use the landscape option. Defaults to False. + start_delimiter (str, optional): the starting delimiter used in the template. + end_delimiter (str, optional): the starting delimiter used in the template. + should_hash (bool, optional): whether the template should be hashed on the server. + template_hash (str, optional): the hash of the template. + + Returns: + Template: the created Template. + """ + return Template( + Resource.from_html(htmlstring, landscape), + start_delimiter, + end_delimiter, + should_hash, + template_hash, + ) diff --git a/docs/cloudofficeprint.html b/docs/cloudofficeprint.html index 9aacb90..61775ac 100644 --- a/docs/cloudofficeprint.html +++ b/docs/cloudofficeprint.html @@ -3,68 +3,40 @@ - + cloudofficeprint API documentation - - - - - - - -
-
+

cloudofficeprint

@@ -183,15 +155,19 @@

Usage

The examples below call this package cop.

-
import cloudofficeprint as cop
-
+
+
import cloudofficeprint as cop
+
+

Templates

Templates are represented by Resource. The simplest way to obtain a Resource is to load from a local path.

-
template = cop.Resource.from_local_file("./path/to/template.docx")
-
+
+
template = cop.Resource.from_local_file("./path/to/template.docx")
+
+

Render elements

@@ -199,7 +175,8 @@

Render elements

Combining a simple line chart and some text tags:

-
line = cop.elements.LineChart(
+
+
line = cop.elements.LineChart(
     "linechart",
     cop.elements.LineSeries([1, 2, 3, 4], [1, 2, 3, 4], color="green"),
     cop.elements.XYSeries([1, 2, 3, 4], ["a", "b", "c", "d"])
@@ -217,554 +194,398 @@ 

Render elements

combined_data.add(line) combined_data.add(text_tag) combined_data.add_all(text_tags) -
+
+

The server

A Cloud Office Print server is configured as a config.Server. It takes a url and an optional config.ServerConfig which allows for various server configuration options. If you're using Cloud Office Print Cloud edition, you will need to use this to declare your API key.

-
server = cop.config.Server(
+
+
server = cop.config.Server(
     "http://server.url.com/",
     cop.config.ServerConfig(api_key = "YOUR_API_KEY")
 )
-
+
+

PrintJob combines template, data, server and an optional output configuration (config.OutputConfig) and can execute itself on the Cloud Office Print server. An example using the variables declared above:

-
printjob = cop.PrintJob(combined_data, server, template)
+
+
printjob = cop.PrintJob(combined_data, server, template)
 printjob.execute()
-
+
+

A print job can be executed asynchronously as well.

-
import asyncio
+
+
import asyncio
 coroutine = printjob.execute_async()
 # simply await your result when you need it
 result = await coroutine
-
+
+

Full JSON available

If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server for you (requests are made using requests).

-
json_data = open("./path/to/data.json", "r").read()
+
+
json_data = open("./path/to/data.json", "r").read()
 cop.PrintJob.execute_full_json(
         json_data, server
     ).to_file("./test/from_full_json_output")
-
+
+

Server errors

In case the Cloud Office Print server returns an error, PrintJob will throw one as well. You can catch it and get either its user-readable message or an encoded stack trace that can be passed to Cloud Office Print support.

-
try:
+
+
try:
     # execute some previously constructed printjob
     printjob.execute()
 except cop.exceptions.COPError as err:
     print("Cloud Office Print error! " + err.user_message)
     print(err.encoded_message)
     ...
-
+
+

Further information

For further information, such as where to find our examples, we refer to our README.md file on our Github page.

-
- View Source -
"""
-This Python package provides a programmatic interface with a [Cloud Office Print](https://www.cloudofficeprint.com) server.
-
-## Usage
-The examples below call this package cop.
-```python
-import cloudofficeprint as cop
-```
-
-### Templates
-Templates are represented by `Resource`. The simplest way to obtain a `Resource` is to load from a local path.
-```python
-template = cop.Resource.from_local_file("./path/to/template.docx")
-```
-
-### Render elements
-Most render elements encapsulate the data for a single tag. An `elements.ElementCollection` is an element which represents a collection of elements.
-
-Combining a simple line chart and some text tags:
-```python
-line = cop.elements.LineChart(
-    "linechart",
-    cop.elements.LineSeries([1, 2, 3, 4], [1, 2, 3, 4], color="green"),
-    cop.elements.XYSeries([1, 2, 3, 4], ["a", "b", "c", "d"])
-)
-
-text_tag = cop.elements.Property("tag-name", "Hello, world!")
-# or multiple at once using ElementCollection.from_mapping
-# and supplying the dictionary representation directly
-text_tags = cop.elements.ElementCollection.from_mapping({
-    "another-tag": "Foo",
-    "one-more-tag": "Bar"
-})
-
-combined_data = cop.elements.ElementCollection()
-combined_data.add(line)
-combined_data.add(text_tag)
-combined_data.add_all(text_tags)
-```
-
-### The server
-A Cloud Office Print server is configured as a `config.Server`. It takes a url and an optional `config.ServerConfig` which allows for various server configuration options. If you're using Cloud Office Print Cloud edition, you will need to use this to declare your API key.
-
-```python
-server = cop.config.Server(
-    "http://server.url.com/",
-    cop.config.ServerConfig(api_key = "YOUR_API_KEY")
-)
-```
-
-### Print job
-`PrintJob` combines template, data, server and an optional output configuration (`config.OutputConfig`) and can execute itself on the Cloud Office Print server. An example using the variables declared above:
-
-```python
-printjob = cop.PrintJob(combined_data, server, template)
-printjob.execute()
-```
-
-A print job can be executed asynchronously as well.
-
-```python
-import asyncio
-coroutine = printjob.execute_async()
-# simply await your result when you need it
-result = await coroutine
-```
-
-### Full JSON available
-If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server for you (requests are made using [requests](https://requests.readthedocs.io/en/master/)).
-```python
-json_data = open("./path/to/data.json", "r").read()
-cop.PrintJob.execute_full_json(
-        json_data, server
-    ).to_file("./test/from_full_json_output")
-```
-
-### Server errors
-In case the Cloud Office Print server returns an error, `PrintJob` will throw one as well.
-You can catch it and get either its user-readable message or an encoded stack trace that can be passed to Cloud Office Print support.
-```python
-try:
-    # execute some previously constructed printjob
-    printjob.execute()
-except cop.exceptions.COPError as err:
-    print("Cloud Office Print error! " + err.user_message)
-    print(err.encoded_message)
-    ...
-```
-
-### Further information
-For further information, such as where to find our examples, we refer to our README.md file on our [Github page](https://github.com/United-Codes/cloudofficeprint-python/).
-"""
-
-from . import exceptions, config, elements, own_utils
-
-from .printjob import PrintJob
-from .resource import Resource
-from .response import Response
-
-# specify what is imported on "from cloudofficeprint import *"
-# but that shouldn't really be used anyway
-__all__ = [
-    "exceptions",
-    "config",
-    "elements",
-    "own_utils",
-    "PrintJob",
-    "Resource",
-    "Response"
-]
-
- -
- -
-
- - -
- View Source -
"""Custom exceptions for cloudofficeprint."""
-
-from typing import List
-
-
-class COPError(Exception):
-    """The error that is thrown when the Cloud Office Print server itself returns an error instead of a result.
-
-    It contains a user message and an encoded message to be handed to Cloud Office Print support if they are contacted.
-    """
-
-    def __init__(self, full_message: str):
-        """
-        Args:
-            full_message (str): the full error message received from the Cloud Office Print server
-        """
-        (self._user_message,
-         self._contact_support_message,
-         self._encoded_message) = self._split_message(full_message)
-        super().__init__(self._user_message)
-
-    @staticmethod
-    def _split_message(message: str) -> List[str]:
-        """Split the Cloud Office Print server error message into different parts: user message, contact support message and encoded message.
-
-        Args:
-            message (str): Cloud Office Print server error message
-
-        Returns:
-            List[str]: a list with the split messages
-        """
-        separated = message.split("\n")
-        # everything before the last 2 lines are considered user message
-        user_message = "\n".join(separated[:-2])
-        # second to last line contains the support message
-        contact_support_message = separated[-2]
-        # last line contains the encoded message
-        encoded_message = separated[-1]
-        return [user_message, contact_support_message, encoded_message]
-
-    @property
-    def encoded_message(self) -> str:
-        """The encrypted and encoded part of the message, for Cloud Office Print support.
-
-        Returns:
-            str: the encrypted and encoded part of the message, for Cloud Office Print support
-        """
-        return self._encoded_message
-
-    @property
-    def user_message(self) -> str:
-        """The user-friendly part of the message.
-
-        Returns:
-            str: the user-friendly part of the message
-        """
-        return self._user_message
-
-    @property
-    def contact_support_message(self) -> str:
-        """The contact support message.
-
-        Returns:
-            str: the contact support message
-        """
-        return self._contact_support_message
-
-    @property
-    def full_message(self) -> str:
-        """The full error message as sent by the server.
-
-        Returns:
-            str: the full error message as sent by the server
-        """
-        return self.user_message + "\n" + self.contact_support_message + "\n" + self.encoded_message
-
- -
- -

Custom exceptions for cloudofficeprint.

-
- - -
-
- - -
- View Source -
"""
-Module for output configurations.
-
-The classes under this module encapsulate various configuration options for a print job.
-They are to be used with `cloudofficeprint.printjob.PrintJob`.
-"""
-
-from .cloud import *
-from .csv import *
-from .output import *
-from .pdf import *
-from .server import *
-
- -
- -

Module for output configurations.

- -

The classes under this module encapsulate various configuration options for a print job. -They are to be used with cloudofficeprint.printjob.PrintJob.

-
- - -
-
- - -
- View Source -
"""
-Elements are used to replace the various tags in a template with actual data.
-"""
-
-from .charts import *
-from .codes import *
-from .elements import *
-from .images import *
-from .loops import *
-from .pdf import *
-from .rest_source import *
-
- -
- -

Elements are used to replace the various tags in a template with actual data.

-
- - -
-
- - -
- View Source -
"""
-Helper functions.
-"""
-
-from .file_utils import *
-from .type_utils import *
-
- -
- -

Helper functions.

-
+ + + + +
  1"""
+  2This Python package provides a programmatic interface with a [Cloud Office Print](https://www.cloudofficeprint.com) server.
+  3
+  4## Usage
+  5The examples below call this package cop.
+  6```python
+  7import cloudofficeprint as cop
+  8```
+  9
+ 10### Templates
+ 11Templates are represented by `Resource`. The simplest way to obtain a `Resource` is to load from a local path.
+ 12```python
+ 13template = cop.Resource.from_local_file("./path/to/template.docx")
+ 14```
+ 15
+ 16### Render elements
+ 17Most render elements encapsulate the data for a single tag. An `elements.ElementCollection` is an element which represents a collection of elements.
+ 18
+ 19Combining a simple line chart and some text tags:
+ 20```python
+ 21line = cop.elements.LineChart(
+ 22    "linechart",
+ 23    cop.elements.LineSeries([1, 2, 3, 4], [1, 2, 3, 4], color="green"),
+ 24    cop.elements.XYSeries([1, 2, 3, 4], ["a", "b", "c", "d"])
+ 25)
+ 26
+ 27text_tag = cop.elements.Property("tag-name", "Hello, world!")
+ 28# or multiple at once using ElementCollection.from_mapping
+ 29# and supplying the dictionary representation directly
+ 30text_tags = cop.elements.ElementCollection.from_mapping({
+ 31    "another-tag": "Foo",
+ 32    "one-more-tag": "Bar"
+ 33})
+ 34
+ 35combined_data = cop.elements.ElementCollection()
+ 36combined_data.add(line)
+ 37combined_data.add(text_tag)
+ 38combined_data.add_all(text_tags)
+ 39```
+ 40
+ 41### The server
+ 42A Cloud Office Print server is configured as a `config.Server`. It takes a url and an optional `config.ServerConfig` which allows for various server configuration options. If you're using Cloud Office Print Cloud edition, you will need to use this to declare your API key.
+ 43
+ 44```python
+ 45server = cop.config.Server(
+ 46    "http://server.url.com/",
+ 47    cop.config.ServerConfig(api_key = "YOUR_API_KEY")
+ 48)
+ 49```
+ 50
+ 51### Print job
+ 52`PrintJob` combines template, data, server and an optional output configuration (`config.OutputConfig`) and can execute itself on the Cloud Office Print server. An example using the variables declared above:
+ 53
+ 54```python
+ 55printjob = cop.PrintJob(combined_data, server, template)
+ 56printjob.execute()
+ 57```
+ 58
+ 59A print job can be executed asynchronously as well.
+ 60
+ 61```python
+ 62import asyncio
+ 63coroutine = printjob.execute_async()
+ 64# simply await your result when you need it
+ 65result = await coroutine
+ 66```
+ 67
+ 68### Full JSON available
+ 69If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server for you (requests are made using [requests](https://requests.readthedocs.io/en/master/)).
+ 70```python
+ 71json_data = open("./path/to/data.json", "r").read()
+ 72cop.PrintJob.execute_full_json(
+ 73        json_data, server
+ 74    ).to_file("./test/from_full_json_output")
+ 75```
+ 76
+ 77### Server errors
+ 78In case the Cloud Office Print server returns an error, `PrintJob` will throw one as well.
+ 79You can catch it and get either its user-readable message or an encoded stack trace that can be passed to Cloud Office Print support.
+ 80```python
+ 81try:
+ 82    # execute some previously constructed printjob
+ 83    printjob.execute()
+ 84except cop.exceptions.COPError as err:
+ 85    print("Cloud Office Print error! " + err.user_message)
+ 86    print(err.encoded_message)
+ 87    ...
+ 88```
+ 89
+ 90### Further information
+ 91For further information, such as where to find our examples, we refer to our README.md file on our [Github page](https://github.com/United-Codes/cloudofficeprint-python/).
+ 92"""
+ 93
+ 94from . import exceptions, config, elements, own_utils
+ 95
+ 96from .printjob import PrintJob
+ 97from .resource import Resource
+ 98from .response import Response
+ 99
+100# specify what is imported on "from cloudofficeprint import *"
+101# but that shouldn't really be used anyway
+102__all__ = [
+103    "exceptions",
+104    "config",
+105    "elements",
+106    "own_utils",
+107    "PrintJob",
+108    "Resource",
+109    "Response"
+110]
+
-
+
-
- #   + +
+ + class + PrintJob: + + - - class - PrintJob:
+ +
 27class PrintJob:
+ 28    """A print job for a Cloud Office Print server.
+ 29
+ 30    This class contains all configuration options, resources, render elements ...
+ 31    and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server.
+ 32    """
+ 33
+ 34    def __init__(self,
+ 35                 data: Union[Element, Mapping[str, Element], RESTSource],
+ 36                 server: Server,
+ 37                 template: Resource = None,
+ 38                 output_config: OutputConfig = OutputConfig(),
+ 39                 subtemplates: Dict[str, Resource] = {},
+ 40                 prepend_files: List[Resource] = [],
+ 41                 append_files: List[Resource] = [],
+ 42                 cop_verbose: bool = False):
+ 43        """
+ 44        Args:
+ 45            data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
+ 46            server (Server): Server to be used for this print job.
+ 47            template (Resource): Template to use for this print job.
+ 48            output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`().
+ 49            subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}.
+ 50            prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to [].
+ 51            append_files (List[Resource], optional): Files to append to the output file. Defaults to [].
+ 52            cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False.
+ 53        """
+ 54
+ 55        self.data: Union[Element, Mapping[str, Element], RESTSource] = data
+ 56        self.server: Server = server
+ 57        self.output_config: OutputConfig = output_config
+ 58        self.template: Resource = template
+ 59        self.subtemplates: Dict[str, Resource] = subtemplates
+ 60        self.prepend_files: List[Resource] = prepend_files
+ 61        self.append_files: List[Resource] = append_files
+ 62        self.cop_verbose: bool = cop_verbose
+ 63
+ 64    def execute(self) -> Response:
+ 65        """Execute this print job.
+ 66
+ 67        Returns:
+ 68            Response: `Response`-object
+ 69        """
+ 70        self.server._raise_if_unreachable()
+ 71        return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"}))
+ 72
+ 73    async def execute_async(self) -> Response:
+ 74        """Async version of `PrintJob.execute`
+ 75
+ 76        Returns:
+ 77            Response: `Response`-object
+ 78        """
+ 79        self.server._raise_if_unreachable()
+ 80        return PrintJob._handle_response(
+ 81            await asyncio.get_event_loop().run_in_executor(
+ 82                None, partial(
+ 83                    requests.post,
+ 84                    self.server.url,
+ 85                    proxies=self.server.config.proxies if self.server.config is not None else None,
+ 86                    json=self.as_dict
+ 87                )
+ 88            )
+ 89        )
+ 90
+ 91    @staticmethod
+ 92    def execute_full_json(json_data: str, server: Server) -> Response:
+ 93        """If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server.
+ 94
+ 95        Args:
+ 96            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
+ 97            server (Server): `Server`-object
+ 98
+ 99        Returns:
+100            Response: `Response`-object
+101        """
+102        server._raise_if_unreachable()
+103        return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"}))
+104
+105    @staticmethod
+106    async def execute_full_json_async(json_data: str, server: Server) -> Response:
+107        """Async version of `Printjob.execute_full_json`
+108
+109        Args:
+110            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
+111            server (Server): `Server`-object
+112
+113        Returns:
+114            Response: `Response`-object
+115        """
+116        server._raise_if_unreachable()
+117        return PrintJob._handle_response(
+118            await asyncio.get_event_loop().run_in_executor(
+119                None, partial(
+120                    requests.post,
+121                    server.url,
+122                    proxies=server.config.proxies if server.config is not None else None,
+123                    data=json_data,
+124                    headers={"Content-type": "application/json"}
+125                )
+126            )
+127        )
+128
+129    @staticmethod
+130    def _handle_response(res: requests.Response) -> Response:
+131        """Converts the HTML response to a `Response`-object
+132
+133        Args:
+134            res (requests.Response): HTML response from the Cloud Office Print server
+135
+136        Raises:
+137            COPError: Error when the HTML status code is not 200
+138
+139        Returns:
+140            Response: `Response`-object of HTML response
+141        """
+142        if res.status_code != 200:
+143            raise COPError(res.text)
+144        else:
+145            return Response(res)
+146
+147    @property
+148    def json(self) -> str:
+149        """JSON equivalent of the dict representation of this print job.
+150        This representation is isomorphic to the dict representation `Printjob.as_dict`.
+151
+152        Returns:
+153            str: JSON equivalent of the dict representation of this print job
+154        """
+155        return json.dumps(self.as_dict)
+156
+157    @property
+158    def as_dict(self) -> Dict:
+159        """Return the dict representation of this print job.
+160
+161        Returns:
+162            Dict: dict representation of this print job
+163        """
+164        result = dict(
+165            STATIC_OPTS)  # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS'
+166        # server config goes in the upper level
+167        if self.server.config:
+168            result.update(self.server.config.as_dict)
+169
+170        # output config goes in "output"
+171        # and decides where its sub-configs go through its as_dict property
+172        # (e.g. PDFConfigs are just appended at this "output" level)
+173        result["output"] = self.output_config.as_dict
+174
+175        if self.template:
+176            result["template"] = self.template.template_dict
+177
+178        # If output_type is not specified, set this to the template filetype
+179        # If no template found: default docx
+180        if 'output_type' not in self.output_config.as_dict.keys():
+181            if self.template:
+182                result['output']['output_type'] = result['template']['template_type']
+183            else:
+184                result['output']['output_type'] = 'docx'
+185
+186        if isinstance(self.data, Mapping):
+187            result["files"] = [{
+188                "filename": name,
+189                "data": data.as_dict
+190            } for name, data in self.data.items()]
+191        elif isinstance(self.data, RESTSource):
+192            result['files'] = [self.data.as_dict]
+193        else:
+194            result["files"] = [{"data": self.data.as_dict}]
+195
+196        if len(self.prepend_files) > 0:
+197            result["prepend_files"] = [
+198                res.secondary_file_dict for res in self.prepend_files
+199            ]
+200
+201        if len(self.append_files) > 0:
+202            result["append_files"] = [
+203                res.secondary_file_dict for res in self.append_files
+204            ]
+205
+206        if len(self.subtemplates) > 0:
+207            templates_list = []
+208            for name, res in self.subtemplates.items():
+209                to_add = res.secondary_file_dict
+210                to_add["name"] = name
+211                templates_list.append(to_add)
+212            result["templates"] = templates_list
+213
+214        # If verbose mode is activated, print the result to the terminal
+215        if self.cop_verbose:
+216            print('The JSON data that is sent to the Cloud Office Print server:\n')
+217            pprint(result)
+218
+219        return result
+
-
- View Source -
class PrintJob:
-    """A print job for a Cloud Office Print server.
-
-    This class contains all configuration options, resources, render elements ...
-    and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server.
-    """
-
-    def __init__(self,
-                 data: Union[Element, Mapping[str, Element], RESTSource],
-                 server: Server,
-                 template: Resource = None,
-                 output_config: OutputConfig = OutputConfig(),
-                 subtemplates: Dict[str, Resource] = {},
-                 prepend_files: List[Resource] = [],
-                 append_files: List[Resource] = [],
-                 cop_verbose: bool = False):
-        """
-        Args:
-            data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
-            server (Server): Server to be used for this print job.
-            template (Resource): Template to use for this print job.
-            output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`().
-            subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}.
-            prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to [].
-            append_files (List[Resource], optional): Files to append to the output file. Defaults to [].
-            cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False.
-        """
-
-        self.data: Union[Element, Mapping[str, Element], RESTSource] = data
-        self.server: Server = server
-        self.output_config: OutputConfig = output_config
-        self.template: Resource = template
-        self.subtemplates: Dict[str, Resource] = subtemplates
-        self.prepend_files: List[Resource] = prepend_files
-        self.append_files: List[Resource] = append_files
-        self.cop_verbose: bool = cop_verbose
-
-    def execute(self) -> Response:
-        """Execute this print job.
-
-        Returns:
-            Response: `Response`-object
-        """
-        self.server._raise_if_unreachable()
-        return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"}))
-
-    async def execute_async(self) -> Response:
-        """Async version of `PrintJob.execute`
-
-        Returns:
-            Response: `Response`-object
-        """
-        self.server._raise_if_unreachable()
-        return PrintJob._handle_response(
-            await asyncio.get_event_loop().run_in_executor(
-                None, partial(
-                    requests.post,
-                    self.server.url,
-                    proxies=self.server.config.proxies if self.server.config is not None else None,
-                    json=self.as_dict
-                )
-            )
-        )
-
-    @staticmethod
-    def execute_full_json(json_data: str, server: Server) -> Response:
-        """If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server.
-
-        Args:
-            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
-            server (Server): `Server`-object
-
-        Returns:
-            Response: `Response`-object
-        """
-        server._raise_if_unreachable()
-        return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"}))
-
-    @staticmethod
-    async def execute_full_json_async(json_data: str, server: Server) -> Response:
-        """Async version of `Printjob.execute_full_json`
-
-        Args:
-            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
-            server (Server): `Server`-object
-
-        Returns:
-            Response: `Response`-object
-        """
-        server._raise_if_unreachable()
-        return PrintJob._handle_response(
-            await asyncio.get_event_loop().run_in_executor(
-                None, partial(
-                    requests.post,
-                    server.url,
-                    proxies=server.config.proxies if server.config is not None else None,
-                    data=json_data,
-                    headers={"Content-type": "application/json"}
-                )
-            )
-        )
-
-    @staticmethod
-    def _handle_response(res: requests.Response) -> Response:
-        """Converts the HTML response to a `Response`-object
-
-        Args:
-            res (requests.Response): HTML response from the Cloud Office Print server
-
-        Raises:
-            COPError: Error when the HTML status code is not 200
-
-        Returns:
-            Response: `Response`-object of HTML response
-        """
-        if res.status_code != 200:
-            raise COPError(res.text)
-        else:
-            return Response(res)
-
-    @property
-    def json(self) -> str:
-        """JSON equivalent of the dict representation of this print job.
-        This representation is isomorphic to the dict representation `Printjob.as_dict`.
-
-        Returns:
-            str: JSON equivalent of the dict representation of this print job
-        """
-        return json.dumps(self.as_dict)
-
-    @property
-    def as_dict(self) -> Dict:
-        """Return the dict representation of this print job.
-
-        Returns:
-            Dict: dict representation of this print job
-        """
-        result = dict(
-            STATIC_OPTS)  # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS'
-        # server config goes in the upper level
-        if self.server.config:
-            result.update(self.server.config.as_dict)
-
-        # output config goes in "output"
-        # and decides where its sub-configs go through its as_dict property
-        # (e.g. PDFConfigs are just appended at this "output" level)
-        result["output"] = self.output_config.as_dict
-
-        if self.template:
-            result["template"] = self.template.template_dict
-
-        # If output_type is not specified, set this to the template filetype
-        # If no template found: default docx
-        if 'output_type' not in self.output_config.as_dict.keys():
-            if self.template:
-                result['output']['output_type'] = result['template']['template_type']
-            else:
-                result['output']['output_type'] = 'docx'
-
-        if isinstance(self.data, Mapping):
-            result["files"] = [{
-                "filename": name,
-                "data": data.as_dict
-            } for name, data in self.data.items()]
-        elif isinstance(self.data, RESTSource):
-            result['files'] = [self.data.as_dict]
-        else:
-            result["files"] = [{"data": self.data.as_dict}]
-
-        if len(self.prepend_files) > 0:
-            result["prepend_files"] = [
-                res.secondary_file_dict for res in self.prepend_files
-            ]
-
-        if len(self.append_files) > 0:
-            result["append_files"] = [
-                res.secondary_file_dict for res in self.append_files
-            ]
-
-        if len(self.subtemplates) > 0:
-            templates_list = []
-            for name, res in self.subtemplates.items():
-                to_add = res.secondary_file_dict
-                to_add["name"] = name
-                templates_list.append(to_add)
-            result["templates"] = templates_list
-
-        # If verbose mode is activated, print the result to the terminal
-        if self.cop_verbose:
-            print('The JSON data that is sent to the Cloud Office Print server:\n')
-            pprint(result)
-
-        return result
-
- -

A print job for a Cloud Office Print server.

@@ -774,55 +595,46 @@

Further information

-
#   + + + +
34    def __init__(self,
+35                 data: Union[Element, Mapping[str, Element], RESTSource],
+36                 server: Server,
+37                 template: Resource = None,
+38                 output_config: OutputConfig = OutputConfig(),
+39                 subtemplates: Dict[str, Resource] = {},
+40                 prepend_files: List[Resource] = [],
+41                 append_files: List[Resource] = [],
+42                 cop_verbose: bool = False):
+43        """
+44        Args:
+45            data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
+46            server (Server): Server to be used for this print job.
+47            template (Resource): Template to use for this print job.
+48            output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`().
+49            subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}.
+50            prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to [].
+51            append_files (List[Resource], optional): Files to append to the output file. Defaults to [].
+52            cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False.
+53        """
+54
+55        self.data: Union[Element, Mapping[str, Element], RESTSource] = data
+56        self.server: Server = server
+57        self.output_config: OutputConfig = output_config
+58        self.template: Resource = template
+59        self.subtemplates: Dict[str, Resource] = subtemplates
+60        self.prepend_files: List[Resource] = prepend_files
+61        self.append_files: List[Resource] = append_files
+62        self.cop_verbose: bool = cop_verbose
+
-
- View Source -
    def __init__(self,
-                 data: Union[Element, Mapping[str, Element], RESTSource],
-                 server: Server,
-                 template: Resource = None,
-                 output_config: OutputConfig = OutputConfig(),
-                 subtemplates: Dict[str, Resource] = {},
-                 prepend_files: List[Resource] = [],
-                 append_files: List[Resource] = [],
-                 cop_verbose: bool = False):
-        """
-        Args:
-            data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
-            server (Server): Server to be used for this print job.
-            template (Resource): Template to use for this print job.
-            output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`().
-            subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}.
-            prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to [].
-            append_files (List[Resource], optional): Files to append to the output file. Defaults to [].
-            cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False.
-        """
-
-        self.data: Union[Element, Mapping[str, Element], RESTSource] = data
-        self.server: Server = server
-        self.output_config: OutputConfig = output_config
-        self.template: Resource = template
-        self.subtemplates: Dict[str, Resource] = subtemplates
-        self.prepend_files: List[Resource] = prepend_files
-        self.append_files: List[Resource] = append_files
-        self.cop_verbose: bool = cop_verbose
-
- -

Args: data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An Element (e.g. an ElementCollection); A mapping, containing file names as keys and an Element as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0". @@ -838,26 +650,26 @@

Further information

-
#   - - - def - execute(self) -> cloudofficeprint.response.Response: -
+ +
+ + def + execute(self) -> cloudofficeprint.Response: -
- View Source -
    def execute(self) -> Response:
-        """Execute this print job.
+                
 
-        Returns:
-            Response: `Response`-object
-        """
-        self.server._raise_if_unreachable()
-        return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"}))
-
+
+ +
64    def execute(self) -> Response:
+65        """Execute this print job.
+66
+67        Returns:
+68            Response: `Response`-object
+69        """
+70        self.server._raise_if_unreachable()
+71        return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"}))
+
-

Execute this print job.

@@ -868,35 +680,35 @@

Further information

-
#   + +
+ + async def + execute_async(self) -> cloudofficeprint.Response: + + - - async def - execute_async(self) -> cloudofficeprint.response.Response:
+ +
73    async def execute_async(self) -> Response:
+74        """Async version of `PrintJob.execute`
+75
+76        Returns:
+77            Response: `Response`-object
+78        """
+79        self.server._raise_if_unreachable()
+80        return PrintJob._handle_response(
+81            await asyncio.get_event_loop().run_in_executor(
+82                None, partial(
+83                    requests.post,
+84                    self.server.url,
+85                    proxies=self.server.config.proxies if self.server.config is not None else None,
+86                    json=self.as_dict
+87                )
+88            )
+89        )
+
-
- View Source -
    async def execute_async(self) -> Response:
-        """Async version of `PrintJob.execute`
-
-        Returns:
-            Response: `Response`-object
-        """
-        self.server._raise_if_unreachable()
-        return PrintJob._handle_response(
-            await asyncio.get_event_loop().run_in_executor(
-                None, partial(
-                    requests.post,
-                    self.server.url,
-                    proxies=self.server.config.proxies if self.server.config is not None else None,
-                    json=self.as_dict
-                )
-            )
-        )
-
- -

Async version of PrintJob.execute

@@ -907,35 +719,32 @@

Further information

-
#   + +
+
@staticmethod
-
@staticmethod
+ def + execute_full_json( json_data: str, server: cloudofficeprint.config.server.Server) -> cloudofficeprint.Response: - def - execute_full_json( - json_data: str, - server: cloudofficeprint.config.server.Server -) -> cloudofficeprint.response.Response: -
+ -
- View Source -
    @staticmethod
-    def execute_full_json(json_data: str, server: Server) -> Response:
-        """If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server.
-
-        Args:
-            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
-            server (Server): `Server`-object
-
-        Returns:
-            Response: `Response`-object
-        """
-        server._raise_if_unreachable()
-        return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"}))
-
+
+ +
 91    @staticmethod
+ 92    def execute_full_json(json_data: str, server: Server) -> Response:
+ 93        """If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server.
+ 94
+ 95        Args:
+ 96            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
+ 97            server (Server): `Server`-object
+ 98
+ 99        Returns:
+100            Response: `Response`-object
+101        """
+102        server._raise_if_unreachable()
+103        return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"}))
+
-

If you already have the JSON to be sent to the server (not just the data, but the entire JSON body including your API key and template), this package will wrap the request to the server.

@@ -950,45 +759,42 @@

Further information

-
#   + +
+
@staticmethod
+ + async def + execute_full_json_async( json_data: str, server: cloudofficeprint.config.server.Server) -> cloudofficeprint.Response: -
@staticmethod
+ - async def - execute_full_json_async( - json_data: str, - server: cloudofficeprint.config.server.Server -) -> cloudofficeprint.response.Response:
+ +
105    @staticmethod
+106    async def execute_full_json_async(json_data: str, server: Server) -> Response:
+107        """Async version of `Printjob.execute_full_json`
+108
+109        Args:
+110            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
+111            server (Server): `Server`-object
+112
+113        Returns:
+114            Response: `Response`-object
+115        """
+116        server._raise_if_unreachable()
+117        return PrintJob._handle_response(
+118            await asyncio.get_event_loop().run_in_executor(
+119                None, partial(
+120                    requests.post,
+121                    server.url,
+122                    proxies=server.config.proxies if server.config is not None else None,
+123                    data=json_data,
+124                    headers={"Content-type": "application/json"}
+125                )
+126            )
+127        )
+
-
- View Source -
    @staticmethod
-    async def execute_full_json_async(json_data: str, server: Server) -> Response:
-        """Async version of `Printjob.execute_full_json`
-
-        Args:
-            json_data (str): full JSON data that needs to be sent to a Cloud Office Print server
-            server (Server): `Server`-object
-
-        Returns:
-            Response: `Response`-object
-        """
-        server._raise_if_unreachable()
-        return PrintJob._handle_response(
-            await asyncio.get_event_loop().run_in_executor(
-                None, partial(
-                    requests.post,
-                    server.url,
-                    proxies=server.config.proxies if server.config is not None else None,
-                    data=json_data,
-                    headers={"Content-type": "application/json"}
-                )
-            )
-        )
-
- -

Async version of Printjob.execute_full_json

@@ -1003,11 +809,13 @@

Further information

-
#   +
+ json: str - json: str +
- + +

JSON equivalent of the dict representation of this print job. This representation is isomorphic to the dict representation Printjob.as_dict.

@@ -1018,11 +826,13 @@

Further information

-
#   +
+ as_dict: Dict - as_dict: Dict +
- + +

Return the dict representation of this print job.

Returns: @@ -1033,205 +843,204 @@

Further information

-
- #   - - - class - Resource(abc.ABC): -
- -
- View Source -
class Resource(ABC):
-    """The abstract base class for the resources."""
-
-    def __init__(self, data: Union[str, bytes] = None, filetype: str = None):
-        """
-        Args:
-            data (Union[str, bytes], optional): the data for this resource. Defaults to None.
-            filetype (str, optional): the file type of this resource. Defaults to None.
-        """
-        self._data: Union[str, bytes] = data
-        self.filetype: str = filetype
-
-    @property
-    def mimetype(self) -> str:
-        """Resource type as a mime type.
-
-        Returns:
-            str: resource type as a mime type
-        """
-        return type_utils.extension_to_mimetype(self.filetype)
-
-    @property
-    def data(self) -> Union[str, bytes]:
-        """The data contained in this Resource.
-
-        Returns:
-            Union[str, bytes]: the data contained in this Resource
-        """
-        return self._data
-
-    @property
-    def template_json(self) -> str:
-        """Get the JSON representation when used as a template.
-
-        Returns:
-            str: JSON representation of this resource as a template
-        """
-        return json.dumps(self.template_dict)
-
-    @property
-    @abstractmethod
-    def template_dict(self) -> Dict:
-        """This Resource object as a dict object for use as a template.
-        This dict and the template JSON representation (`Resource.template_json`) are isomorphic.
-
-        Returns:
-            Dict: dict representation of this resource as a template
-        """
-        pass
-
-    @property
-    def secondary_file_json(self) -> str:
-        """The JSON representation for use as secondary file.
-
-        Returns:
-            str: JSON representation of this resource as a secondary file
-        """
-        return json.dumps(self.secondary_file_dict)
-
-    @property
-    @abstractmethod
-    def secondary_file_dict(self) -> Dict:
-        """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate).
-        This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic.
-
-        Returns:
-            Dict: dict representation of this resource as a secondary file
-        """
-        pass
-
-    def __str__(self) -> str:
-        """Override the string representation of this class to return the template-style json.
-
-        Returns:
-            str: JSON representation of this resource as a template
-        """
-        return self.template_json
-
-    @staticmethod
-    def from_base64(base64string: str, filetype: str) -> 'Base64Resource':
-        """Create a Base64Resource from a base64 string and a file type (extension).
-
-        Args:
-            base64string (str): base64 encoded string
-            filetype (str): file type (extension)
-
-        Returns:
-            Base64Resource: the created Resource
-        """
-        return Base64Resource(base64string, filetype)
-
-    @staticmethod
-    def from_raw(raw_data: bytes, filetype: str) -> 'RawResource':
-        """Create a RawResource from raw file data and a file type (extension).
-
-        Args:
-            raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)
-            filetype (str): file type (extension)
-
-        Returns:
-            RawResource: the created Resource
-        """
-        return RawResource(raw_data, filetype)
-
-    @staticmethod
-    def from_local_file(local_path: str) -> 'Base64Resource':
-        """Create a Base64Resource with the contents of a local file.
-
-        Throws IOError if it can't read the file.
-        The filetype is determined by the extension of the file.
-
-        Args:
-            local_path (str): path to local file
-
-        Returns:
-            Base64Resource: the created Resource
-        """
-        base64string: str = file_utils.read_file_as_base64(local_path)
-        return Base64Resource(base64string, type_utils.path_to_extension(local_path))
-
-    @staticmethod
-    def from_server_path(path: str) -> 'ServerPathResource':
-        """Create a ServerPathResource targeting a file on the server.
-
-        The filetype is determined by the extension of the file.
-
-        Args:
-            path (str): location of target file on the server
-
-        Returns:
-            ServerPathResource: the created Resource
-        """
-        return ServerPathResource(path)
-
-    @staticmethod
-    def from_url(url: str, filetype: str) -> 'URLResource':
-        """Create an Resource targeting the file at url with given filetype (extension).
-
-        Args:
-            url (str): file url
-            filetype (str): file type (extension)
-
-        Returns:
-            URLResource: the created Resource
-        """
-        return URLResource(url, filetype)
+                            
+
+ + class + Resource(abc.ABC): - @staticmethod - def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource': - """Create an HTMLResource with html data in plain text. + - Landscape is not supported for prepend/append sources, only for template resources. - - Args: - htmlstring (str): html content - landscape (bool, optional): whether to use the landscape option. Defaults to False. - - Returns: - HTMLResource: the created Resource - """ - return HTMLResource(htmlstring, landscape) -
+ + +
 20class Resource(ABC):
+ 21    """The abstract base class for the resources."""
+ 22
+ 23    def __init__(self, data: Union[str, bytes] = None, filetype: str = None):
+ 24        """
+ 25        Args:
+ 26            data (Union[str, bytes], optional): the data for this resource. Defaults to None.
+ 27            filetype (str, optional): the file type of this resource. Defaults to None.
+ 28        """
+ 29        self._data: Union[str, bytes] = data
+ 30        self.filetype: str = filetype
+ 31
+ 32    @property
+ 33    def mimetype(self) -> str:
+ 34        """Resource type as a mime type.
+ 35
+ 36        Returns:
+ 37            str: resource type as a mime type
+ 38        """
+ 39        return type_utils.extension_to_mimetype(self.filetype)
+ 40
+ 41    @property
+ 42    def data(self) -> Union[str, bytes]:
+ 43        """The data contained in this Resource.
+ 44
+ 45        Returns:
+ 46            Union[str, bytes]: the data contained in this Resource
+ 47        """
+ 48        return self._data
+ 49
+ 50    @property
+ 51    def template_json(self) -> str:
+ 52        """Get the JSON representation when used as a template.
+ 53
+ 54        Returns:
+ 55            str: JSON representation of this resource as a template
+ 56        """
+ 57        return json.dumps(self.template_dict)
+ 58
+ 59    @property
+ 60    @abstractmethod
+ 61    def template_dict(self) -> Dict:
+ 62        """This Resource object as a dict object for use as a template.
+ 63        This dict and the template JSON representation (`Resource.template_json`) are isomorphic.
+ 64
+ 65        Returns:
+ 66            Dict: dict representation of this resource as a template
+ 67        """
+ 68        pass
+ 69
+ 70    @property
+ 71    def secondary_file_json(self) -> str:
+ 72        """The JSON representation for use as secondary file.
+ 73
+ 74        Returns:
+ 75            str: JSON representation of this resource as a secondary file
+ 76        """
+ 77        return json.dumps(self.secondary_file_dict)
+ 78
+ 79    @property
+ 80    @abstractmethod
+ 81    def secondary_file_dict(self) -> Dict:
+ 82        """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate).
+ 83        This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic.
+ 84
+ 85        Returns:
+ 86            Dict: dict representation of this resource as a secondary file
+ 87        """
+ 88        pass
+ 89
+ 90    def __str__(self) -> str:
+ 91        """Override the string representation of this class to return the template-style json.
+ 92
+ 93        Returns:
+ 94            str: JSON representation of this resource as a template
+ 95        """
+ 96        return self.template_json
+ 97
+ 98    @staticmethod
+ 99    def from_base64(base64string: str, filetype: str) -> 'Base64Resource':
+100        """Create a Base64Resource from a base64 string and a file type (extension).
+101
+102        Args:
+103            base64string (str): base64 encoded string
+104            filetype (str): file type (extension)
+105
+106        Returns:
+107            Base64Resource: the created Resource
+108        """
+109        return Base64Resource(base64string, filetype)
+110
+111    @staticmethod
+112    def from_raw(raw_data: bytes, filetype: str) -> 'RawResource':
+113        """Create a RawResource from raw file data and a file type (extension).
+114
+115        Args:
+116            raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)
+117            filetype (str): file type (extension)
+118
+119        Returns:
+120            RawResource: the created Resource
+121        """
+122        return RawResource(raw_data, filetype)
+123
+124    @staticmethod
+125    def from_local_file(local_path: str) -> 'Base64Resource':
+126        """Create a Base64Resource with the contents of a local file.
+127
+128        Throws IOError if it can't read the file.
+129        The filetype is determined by the extension of the file.
+130
+131        Args:
+132            local_path (str): path to local file
+133
+134        Returns:
+135            Base64Resource: the created Resource
+136        """
+137        base64string: str = file_utils.read_file_as_base64(local_path)
+138        return Base64Resource(base64string, type_utils.path_to_extension(local_path))
+139
+140    @staticmethod
+141    def from_server_path(path: str) -> 'ServerPathResource':
+142        """Create a ServerPathResource targeting a file on the server.
+143
+144        The filetype is determined by the extension of the file.
+145
+146        Args:
+147            path (str): location of target file on the server
+148
+149        Returns:
+150            ServerPathResource: the created Resource
+151        """
+152        return ServerPathResource(path)
+153
+154    @staticmethod
+155    def from_url(url: str, filetype: str) -> 'URLResource':
+156        """Create an Resource targeting the file at url with given filetype (extension).
+157
+158        Args:
+159            url (str): file url
+160            filetype (str): file type (extension)
+161
+162        Returns:
+163            URLResource: the created Resource
+164        """
+165        return URLResource(url, filetype)
+166
+167    @staticmethod
+168    def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource':
+169        """Create an HTMLResource with html data in plain text.
+170
+171        Landscape is not supported for prepend/append sources, only for template resources.
+172
+173        Args:
+174            htmlstring (str): html content
+175            landscape (bool, optional): whether to use the landscape option. Defaults to False.
+176
+177        Returns:
+178            HTMLResource: the created Resource
+179        """
+180        return HTMLResource(htmlstring, landscape)
+
-

The abstract base class for the resources.

-
#   + +
+ + Resource(data: Union[str, bytes] = None, filetype: str = None) - - Resource(data: Union[str, bytes] = None, filetype: str = None) -
+ -
- View Source -
    def __init__(self, data: Union[str, bytes] = None, filetype: str = None):
-        """
-        Args:
-            data (Union[str, bytes], optional): the data for this resource. Defaults to None.
-            filetype (str, optional): the file type of this resource. Defaults to None.
-        """
-        self._data: Union[str, bytes] = data
-        self.filetype: str = filetype
-
+
+ +
23    def __init__(self, data: Union[str, bytes] = None, filetype: str = None):
+24        """
+25        Args:
+26            data (Union[str, bytes], optional): the data for this resource. Defaults to None.
+27            filetype (str, optional): the file type of this resource. Defaults to None.
+28        """
+29        self._data: Union[str, bytes] = data
+30        self.filetype: str = filetype
+
-

Args: data (Union[str, bytes], optional): the data for this resource. Defaults to None. @@ -1241,11 +1050,13 @@

Further information

-
#   +
+ mimetype: str - mimetype: str +
- + +

Resource type as a mime type.

Returns: @@ -1255,11 +1066,13 @@

Further information

-
#   +
+ data: Union[str, bytes] - data: Union[str, bytes] +
- + +

The data contained in this Resource.

Returns: @@ -1269,11 +1082,13 @@

Further information

-
#   +
+ template_json: str - template_json: str +
- + +

Get the JSON representation when used as a template.

Returns: @@ -1283,11 +1098,13 @@

Further information

-
#   +
+ template_dict: Dict - template_dict: Dict +
- + +

This Resource object as a dict object for use as a template. This dict and the template JSON representation (Resource.template_json) are isomorphic.

@@ -1298,11 +1115,13 @@

Further information

-
#   +
+ secondary_file_json: str - secondary_file_json: str +
- + +

The JSON representation for use as secondary file.

Returns: @@ -1312,11 +1131,13 @@

Further information

-
#   +
+ secondary_file_dict: Dict - secondary_file_dict: Dict +
- + +

This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate). This dict and the "concat file" JSON representation (Resource.secondary_file_json) are isomorphic.

@@ -1327,34 +1148,31 @@

Further information

-
#   - -
@staticmethod
+ +
+
@staticmethod
- def - from_base64( - base64string: str, - filetype: str -) -> cloudofficeprint.resource.Base64Resource: -
+ def + from_base64( base64string: str, filetype: str) -> cloudofficeprint.resource.Base64Resource: -
- View Source -
    @staticmethod
-    def from_base64(base64string: str, filetype: str) -> 'Base64Resource':
-        """Create a Base64Resource from a base64 string and a file type (extension).
+                
 
-        Args:
-            base64string (str): base64 encoded string
-            filetype (str): file type (extension)
-
-        Returns:
-            Base64Resource: the created Resource
-        """
-        return Base64Resource(base64string, filetype)
-
+
+ +
 98    @staticmethod
+ 99    def from_base64(base64string: str, filetype: str) -> 'Base64Resource':
+100        """Create a Base64Resource from a base64 string and a file type (extension).
+101
+102        Args:
+103            base64string (str): base64 encoded string
+104            filetype (str): file type (extension)
+105
+106        Returns:
+107            Base64Resource: the created Resource
+108        """
+109        return Base64Resource(base64string, filetype)
+
-

Create a Base64Resource from a base64 string and a file type (extension).

@@ -1369,34 +1187,31 @@

Further information

-
#   + +
+
@staticmethod
-
@staticmethod
+ def + from_raw(raw_data: bytes, filetype: str) -> cloudofficeprint.resource.RawResource: - def - from_raw( - raw_data: bytes, - filetype: str -) -> cloudofficeprint.resource.RawResource: -
- -
- View Source -
    @staticmethod
-    def from_raw(raw_data: bytes, filetype: str) -> 'RawResource':
-        """Create a RawResource from raw file data and a file type (extension).
+                
 
-        Args:
-            raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)
-            filetype (str): file type (extension)
-
-        Returns:
-            RawResource: the created Resource
-        """
-        return RawResource(raw_data, filetype)
-
+
+ +
111    @staticmethod
+112    def from_raw(raw_data: bytes, filetype: str) -> 'RawResource':
+113        """Create a RawResource from raw file data and a file type (extension).
+114
+115        Args:
+116            raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)
+117            filetype (str): file type (extension)
+118
+119        Returns:
+120            RawResource: the created Resource
+121        """
+122        return RawResource(raw_data, filetype)
+
-

Create a RawResource from raw file data and a file type (extension).

@@ -1411,34 +1226,34 @@

Further information

-
#   + +
+
@staticmethod
-
@staticmethod
+ def + from_local_file(local_path: str) -> cloudofficeprint.resource.Base64Resource: - def - from_local_file(local_path: str) -> cloudofficeprint.resource.Base64Resource: -
- -
- View Source -
    @staticmethod
-    def from_local_file(local_path: str) -> 'Base64Resource':
-        """Create a Base64Resource with the contents of a local file.
-
-        Throws IOError if it can't read the file.
-        The filetype is determined by the extension of the file.
-
-        Args:
-            local_path (str): path to local file
+                
 
-        Returns:
-            Base64Resource: the created Resource
-        """
-        base64string: str = file_utils.read_file_as_base64(local_path)
-        return Base64Resource(base64string, type_utils.path_to_extension(local_path))
-
+
+ +
124    @staticmethod
+125    def from_local_file(local_path: str) -> 'Base64Resource':
+126        """Create a Base64Resource with the contents of a local file.
+127
+128        Throws IOError if it can't read the file.
+129        The filetype is determined by the extension of the file.
+130
+131        Args:
+132            local_path (str): path to local file
+133
+134        Returns:
+135            Base64Resource: the created Resource
+136        """
+137        base64string: str = file_utils.read_file_as_base64(local_path)
+138        return Base64Resource(base64string, type_utils.path_to_extension(local_path))
+
-

Create a Base64Resource with the contents of a local file.

@@ -1455,32 +1270,32 @@

Further information

-
#   - -
@staticmethod
- - def - from_server_path(path: str) -> cloudofficeprint.resource.ServerPathResource: -
+ +
+
@staticmethod
-
- View Source -
    @staticmethod
-    def from_server_path(path: str) -> 'ServerPathResource':
-        """Create a ServerPathResource targeting a file on the server.
+        def
+        from_server_path(path: str) -> cloudofficeprint.resource.ServerPathResource:
 
-        The filetype is determined by the extension of the file.
+                
 
-        Args:
-            path (str): location of target file on the server
-
-        Returns:
-            ServerPathResource: the created Resource
-        """
-        return ServerPathResource(path)
-
+
+ +
140    @staticmethod
+141    def from_server_path(path: str) -> 'ServerPathResource':
+142        """Create a ServerPathResource targeting a file on the server.
+143
+144        The filetype is determined by the extension of the file.
+145
+146        Args:
+147            path (str): location of target file on the server
+148
+149        Returns:
+150            ServerPathResource: the created Resource
+151        """
+152        return ServerPathResource(path)
+
-

Create a ServerPathResource targeting a file on the server.

@@ -1496,31 +1311,31 @@

Further information

-
#   - -
@staticmethod
- - def - from_url(url: str, filetype: str) -> cloudofficeprint.resource.URLResource: -
+ +
+
@staticmethod
-
- View Source -
    @staticmethod
-    def from_url(url: str, filetype: str) -> 'URLResource':
-        """Create an Resource targeting the file at url with given filetype (extension).
+        def
+        from_url(url: str, filetype: str) -> cloudofficeprint.resource.URLResource:
 
-        Args:
-            url (str): file url
-            filetype (str): file type (extension)
+                
 
-        Returns:
-            URLResource: the created Resource
-        """
-        return URLResource(url, filetype)
-
+
+ +
154    @staticmethod
+155    def from_url(url: str, filetype: str) -> 'URLResource':
+156        """Create an Resource targeting the file at url with given filetype (extension).
+157
+158        Args:
+159            url (str): file url
+160            filetype (str): file type (extension)
+161
+162        Returns:
+163            URLResource: the created Resource
+164        """
+165        return URLResource(url, filetype)
+
-

Create an Resource targeting the file at url with given filetype (extension).

@@ -1535,36 +1350,33 @@

Further information

-
#   - -
@staticmethod
- - def - from_html( - htmlstring: str, - landscape: bool = False -) -> cloudofficeprint.resource.HTMLResource: -
+ +
+
@staticmethod
-
- View Source -
    @staticmethod
-    def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource':
-        """Create an HTMLResource with html data in plain text.
+        def
+        from_html(	htmlstring: str,	landscape: bool = False) -> cloudofficeprint.resource.HTMLResource:
 
-        Landscape is not supported for prepend/append sources, only for template resources.
+                
 
-        Args:
-            htmlstring (str): html content
-            landscape (bool, optional): whether to use the landscape option. Defaults to False.
-
-        Returns:
-            HTMLResource: the created Resource
-        """
-        return HTMLResource(htmlstring, landscape)
-
+
+ +
167    @staticmethod
+168    def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource':
+169        """Create an HTMLResource with html data in plain text.
+170
+171        Landscape is not supported for prepend/append sources, only for template resources.
+172
+173        Args:
+174            htmlstring (str): html content
+175            landscape (bool, optional): whether to use the landscape option. Defaults to False.
+176
+177        Returns:
+178            HTMLResource: the created Resource
+179        """
+180        return HTMLResource(htmlstring, landscape)
+
-

Create an HTMLResource with html data in plain text.

@@ -1582,101 +1394,100 @@

Further information

-
- #   + +
+ + class + Response: + + - - class - Response:
+ +
11class Response():
+12    """The Response class serves as a container for and interface with the Cloud Office Print server's response to a printjob request.
+13
+14    The Cloud Office Print server can also throw an error, in which case you will be dealing with a cloudofficeprint.exceptions.COPError instead of this class.
+15    """
+16
+17    def __init__(self, response: requests.Response):
+18        """You should never need to construct a Response manually.
+19
+20        Args:
+21            response (requests.Response): Response object from the requests package
+22        """
+23        self._mimetype = response.headers["Content-Type"]
+24        self._bytes = response.content
+25
+26    @property
+27    def mimetype(self) -> str:
+28        """Mime type of this response.
+29
+30        Returns:
+31            str: mime type of this response
+32        """
+33        return self._mimetype
+34
+35    @property
+36    def filetype(self) -> str:
+37        """File type (extension) of this response. E.g. "docx".
+38
+39        Returns:
+40            str: file type of this response
+41        """
+42        return type_utils.mimetype_to_extension(self.mimetype)
+43
+44    @property
+45    def binary(self) -> bytes:
+46        """Binary representation of the output file.
+47
+48        Response.to_file can be used to output to a file,
+49        alternatively, use this property to do something else with the binary data.
+50
+51        Returns:
+52            bytes: response file as binary
+53        """
+54        return self._bytes
+55
+56    def to_string(self) -> str:
+57        """Return the string representation of this buffer.
+58        Useful if the server returns a JSON (e.g. for output_type 'count_tags').
+59
+60        Raises:
+61            err: raise error is bytes cannot be decoded in utf-8
+62
+63        Returns:
+64            str: string representation of this buffer
+65        """
+66        try:
+67            return self._bytes.decode('utf-8')
+68        except UnicodeDecodeError as err:
+69            print("""The method 'to_string()' cannot be called on this object.
+70            The server response is probably not a string (e.g. JSON).
+71            To get the bytes of the response, use the property 'binary' instead.""")
+72            raise err
+73
+74    def to_file(self, path: str):
+75        """Write the response to a file at the given path without extension.
+76
+77        If the given file path does not contain an extension,
+78        the correct path is automatically added from the response data.
+79        That is how this method is intended to be used.
+80        You should only specify the extension in the path if you have some reason to specify the extension manually.
+81
+82        Args:
+83            path (str): path without extension
+84        """
+85
+86        if not splitext(path)[1]:
+87            path += "." + self.filetype
+88
+89        # open the file in binary ("b") and write ("w") mode
+90        outfile = open(path, "wb")
+91        outfile.write(self.binary)
+92        outfile.close()
+
-
- View Source -
class Response():
-    """The Response class serves as a container for and interface with the Cloud Office Print server's response to a printjob request.
-
-    The Cloud Office Print server can also throw an error, in which case you will be dealing with a cloudofficeprint.exceptions.COPError instead of this class.
-    """
-
-    def __init__(self, response: requests.Response):
-        """You should never need to construct a Response manually.
-
-        Args:
-            response (requests.Response): Response object from the requests package
-        """
-        self._mimetype = response.headers["Content-Type"]
-        self._bytes = response.content
-
-    @property
-    def mimetype(self) -> str:
-        """Mime type of this response.
-
-        Returns:
-            str: mime type of this response
-        """
-        return self._mimetype
-
-    @property
-    def filetype(self) -> str:
-        """File type (extension) of this response. E.g. "docx".
-
-        Returns:
-            str: file type of this response
-        """
-        return type_utils.mimetype_to_extension(self.mimetype)
-
-    @property
-    def binary(self) -> bytes:
-        """Binary representation of the output file.
-
-        Response.to_file can be used to output to a file,
-        alternatively, use this property to do something else with the binary data.
-
-        Returns:
-            bytes: response file as binary
-        """
-        return self._bytes
-
-    def to_string(self) -> str:
-        """Return the string representation of this buffer.
-        Useful if the server returns a JSON (e.g. for output_type 'count_tags').
-
-        Raises:
-            err: raise error is bytes cannot be decoded in utf-8
-
-        Returns:
-            str: string representation of this buffer
-        """
-        try:
-            return self._bytes.decode('utf-8')
-        except UnicodeDecodeError as err:
-            print("""The method 'to_string()' cannot be called on this object.
-            The server response is probably not a string (e.g. JSON).
-            To get the bytes of the response, use the property 'binary' instead.""")
-            raise err
-
-    def to_file(self, path: str):
-        """Write the response to a file at the given path without extension.
-
-        If the given file path does not contain an extension,
-        the correct path is automatically added from the response data.
-        That is how this method is intended to be used.
-        You should only specify the extension in the path if you have some reason to specify the extension manually.
-
-        Args:
-            path (str): path without extension
-        """
-
-        if not splitext(path)[1]:
-            path += "." + self.filetype
-
-        # open the file in binary ("b") and write ("w") mode
-        outfile = open(path, "wb")
-        outfile.write(self.binary)
-        outfile.close()
-
- -

The Response class serves as a container for and interface with the Cloud Office Print server's response to a printjob request.

@@ -1685,25 +1496,25 @@

Further information

-
#   + +
+ + Response(response: requests.models.Response) - - Response(response: requests.models.Response) -
+ -
- View Source -
    def __init__(self, response: requests.Response):
-        """You should never need to construct a Response manually.
-
-        Args:
-            response (requests.Response): Response object from the requests package
-        """
-        self._mimetype = response.headers["Content-Type"]
-        self._bytes = response.content
-
+
+ +
17    def __init__(self, response: requests.Response):
+18        """You should never need to construct a Response manually.
+19
+20        Args:
+21            response (requests.Response): Response object from the requests package
+22        """
+23        self._mimetype = response.headers["Content-Type"]
+24        self._bytes = response.content
+
-

You should never need to construct a Response manually.

@@ -1714,11 +1525,13 @@

Further information

-
#   +
+ mimetype: str - mimetype: str +
- + +

Mime type of this response.

Returns: @@ -1728,11 +1541,13 @@

Further information

-
#   +
+ filetype: str - filetype: str +
- + +

File type (extension) of this response. E.g. "docx".

Returns: @@ -1742,11 +1557,13 @@

Further information

-
#   +
+ binary: bytes - binary: bytes +
- + +

Binary representation of the output file.

Response.to_file can be used to output to a file, @@ -1759,35 +1576,35 @@

Further information

-
#   + +
+ + def + to_string(self) -> str: + + - - def - to_string(self) -> str:
+ +
56    def to_string(self) -> str:
+57        """Return the string representation of this buffer.
+58        Useful if the server returns a JSON (e.g. for output_type 'count_tags').
+59
+60        Raises:
+61            err: raise error is bytes cannot be decoded in utf-8
+62
+63        Returns:
+64            str: string representation of this buffer
+65        """
+66        try:
+67            return self._bytes.decode('utf-8')
+68        except UnicodeDecodeError as err:
+69            print("""The method 'to_string()' cannot be called on this object.
+70            The server response is probably not a string (e.g. JSON).
+71            To get the bytes of the response, use the property 'binary' instead.""")
+72            raise err
+
-
- View Source -
    def to_string(self) -> str:
-        """Return the string representation of this buffer.
-        Useful if the server returns a JSON (e.g. for output_type 'count_tags').
-
-        Raises:
-            err: raise error is bytes cannot be decoded in utf-8
-
-        Returns:
-            str: string representation of this buffer
-        """
-        try:
-            return self._bytes.decode('utf-8')
-        except UnicodeDecodeError as err:
-            print("""The method 'to_string()' cannot be called on this object.
-            The server response is probably not a string (e.g. JSON).
-            To get the bytes of the response, use the property 'binary' instead.""")
-            raise err
-
- -

Return the string representation of this buffer. Useful if the server returns a JSON (e.g. for output_type 'count_tags').

@@ -1802,37 +1619,37 @@

Further information

-
#   + +
+ + def + to_file(self, path: str): - - def - to_file(self, path: str): -
- -
- View Source -
    def to_file(self, path: str):
-        """Write the response to a file at the given path without extension.
-
-        If the given file path does not contain an extension,
-        the correct path is automatically added from the response data.
-        That is how this method is intended to be used.
-        You should only specify the extension in the path if you have some reason to specify the extension manually.
-
-        Args:
-            path (str): path without extension
-        """
+                
 
-        if not splitext(path)[1]:
-            path += "." + self.filetype
-
-        # open the file in binary ("b") and write ("w") mode
-        outfile = open(path, "wb")
-        outfile.write(self.binary)
-        outfile.close()
-
+
+ +
74    def to_file(self, path: str):
+75        """Write the response to a file at the given path without extension.
+76
+77        If the given file path does not contain an extension,
+78        the correct path is automatically added from the response data.
+79        That is how this method is intended to be used.
+80        You should only specify the extension in the path if you have some reason to specify the extension manually.
+81
+82        Args:
+83            path (str): path without extension
+84        """
+85
+86        if not splitext(path)[1]:
+87            path += "." + self.filetype
+88
+89        # open the file in binary ("b") and write ("w") mode
+90        outfile = open(path, "wb")
+91        outfile.write(self.binary)
+92        outfile.close()
+
-

Write the response to a file at the given path without extension.

@@ -1949,12 +1766,26 @@

Further information

} let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}(${doc.parameters.join(", ")})`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; + if (doc.bases) + heading += `(${doc.bases})`; + heading += `:`; + break; + case "variable": + heading = `${doc.fullname}`; + if (doc.annotation) + heading += `${doc.annotation}`; + if (doc.default_value) + heading += `${doc.default_value}`; break; default: heading = `${doc.fullname}`; @@ -1962,7 +1793,7 @@

Further information

} html += `
- ${heading} + ${heading}
${doc.doc}
`; diff --git a/docs/cloudofficeprint/config.html b/docs/cloudofficeprint/config.html index 2d7edbb..563f4ff 100644 --- a/docs/cloudofficeprint/config.html +++ b/docs/cloudofficeprint/config.html @@ -3,76 +3,79 @@ - + cloudofficeprint.config API documentation - - - - - - - -
-
+

cloudofficeprint.config

Module for output configurations.

The classes under this module encapsulate various configuration options for a print job. -They are to be used with cloudofficeprint.printjob.PrintJob.

+They are to be used with cloudofficeprint.printjob.PrintJob.

-
- View Source -
"""
-Module for output configurations.
+                        
 
-The classes under this module encapsulate various configuration options for a print job.
-They are to be used with `cloudofficeprint.printjob.PrintJob`.
-"""
+                        
 
-from .cloud import *
-from .csv import *
-from .output import *
-from .pdf import *
-from .server import *
-
+
 1"""
+ 2Module for output configurations.
+ 3
+ 4The classes under this module encapsulate various configuration options for a print job.
+ 5They are to be used with `cloudofficeprint.printjob.PrintJob`.
+ 6"""
+ 7
+ 8from .cloud import *
+ 9from .csv import *
+10from .output import *
+11from .pdf import *
+12from .server import *
+13from .request_option import *
+
-
@@ -176,12 +179,26 @@

} let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}(${doc.parameters.join(", ")})`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; + if (doc.bases) + heading += `(${doc.bases})`; + heading += `:`; + break; + case "variable": + heading = `${doc.fullname}`; + if (doc.annotation) + heading += `${doc.annotation}`; + if (doc.default_value) + heading += `${doc.default_value}`; break; default: heading = `${doc.fullname}`; @@ -189,7 +206,7 @@

} html += `
- ${heading} + ${heading}
${doc.doc}
`; diff --git a/docs/cloudofficeprint/config/index.html b/docs/cloudofficeprint/config/index.html index 0e317eb..0725f90 100644 --- a/docs/cloudofficeprint/config/index.html +++ b/docs/cloudofficeprint/config/index.html @@ -40,7 +40,8 @@

Module cloudofficeprint.config

from .csv import * from .output import * from .pdf import * -from .server import * +from .server import * +from .request_option import *
@@ -62,6 +63,10 @@

Sub-modules

+
cloudofficeprint.config.request_option
+
+
+
cloudofficeprint.config.server
@@ -92,6 +97,7 @@

Index

  • cloudofficeprint.config.csv
  • cloudofficeprint.config.output
  • cloudofficeprint.config.pdf
  • +
  • cloudofficeprint.config.request_option
  • cloudofficeprint.config.server
  • diff --git a/docs/cloudofficeprint/config/output.html b/docs/cloudofficeprint/config/output.html index c2e61e4..8ea30cf 100644 --- a/docs/cloudofficeprint/config/output.html +++ b/docs/cloudofficeprint/config/output.html @@ -30,6 +30,7 @@

    Module cloudofficeprint.config.output

    from typing import Dict from .cloud import CloudAccessToken from .pdf import PDFOptions +from .request_option import requestOptions class OutputConfig: @@ -45,16 +46,25 @@

    Module cloudofficeprint.config.output

    cloud_access_token: CloudAccessToken = None, server_directory: str = None, pdf_options: PDFOptions = None, - append_per_page: bool = None,): - """ + append_per_page: bool = None, + prepend_per_page: bool = None, + output_polling: bool = None, + secret_key: str = None, + request_option: requestOptions = None): + """If the parameters are not provided default value will be used. + Args: - filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). + filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). Defaults to None. encoding (str, optional): Encoding of output file. Either "raw" or "base64". Defaults to "raw". converter (str, optional): The pdf converter to use. Can be "libreoffice", "officetopdf" or any custom defined converter. Custom converters are configurated in the Cloud Office Print server's `aop_config.json` file. Defaults to "libreoffice". cloud_access_token (CloudAccessToken, optional): Access token used to access various cloud services for output storage. Defaults to None. server_directory (str, optional): Base directory to save output files into. Can only be used if the server allows to save on disk. The specific output path for each file is appended to the base path. Defaults to None. pdf_options (PDFOptions, optional): Optional PDF options. Defaults to None. - append_per_page (bool, optional): Ability to prepend/append file after each page of output. + append_per_page (bool, optional): Ability to append file after each page of output. Defaults to None. + prepend_per_page (bool, optional): Ability to prepend file after each page of output. Defaults to None. + output_polling (bool, optional): A unique link for each request is sent back, which can be used later to download the output file. Defaults to None. + secret_key (str, optional): A secret key can be specified to encrypt the file stored on the server (ussed with output polling). Defaults to None. + request_option (requestOptions, optional): AOP makes a call to the given option with response/output of the current request. Defaults to None. """ self.filetype: str = filetype self.converter: str = converter @@ -63,6 +73,10 @@

    Module cloudofficeprint.config.output

    self.pdf_options: PDFOptions = pdf_options self.encoding = encoding self.append_per_page = append_per_page + self.prepend_per_page = prepend_per_page + self.output_polling = output_polling + self.secret_key = secret_key + self.request_option = request_option @property def json(self) -> str: @@ -97,6 +111,14 @@

    Module cloudofficeprint.config.output

    result.update(self.pdf_options.as_dict) if self.append_per_page is not None: result["output_append_per_page"] = self.append_per_page + if self.prepend_per_page is not None: + result["output_prepend_per_page"] = self.prepend_per_page + if self.output_polling is not None: + result['output_polling'] = self.output_polling + if self.secret_key is not None: + result['secret_key'] = self.secret_key + if self.request_option is not None: + result['request_option'] = self.request_option.as_dict return result @property @@ -135,15 +157,16 @@

    Classes

    class OutputConfig -(filetype: str = None, encoding: str = 'raw', converter: str = 'libreoffice', cloud_access_token: CloudAccessToken = None, server_directory: str = None, pdf_options: PDFOptions = None, append_per_page: bool = None) +(filetype: str = None, encoding: str = 'raw', converter: str = 'libreoffice', cloud_access_token: CloudAccessToken = None, server_directory: str = None, pdf_options: PDFOptions = None, append_per_page: bool = None, prepend_per_page: bool = None, output_polling: bool = None, secret_key: str = None, request_option: requestOptions = None)

    Class to specify output configuration for a request.

    This configuration is general and for the entire list of output files.

    +

    If the parameters are not provided default value will be used.

    Args

    filetype : str, optional
    -
    The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py).
    +
    The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). Defaults to None.
    encoding : str, optional
    Encoding of output file. Either "raw" or "base64". Defaults to "raw".
    converter : str, optional
    @@ -155,7 +178,15 @@

    Args

    pdf_options : PDFOptions, optional
    Optional PDF options. Defaults to None.
    append_per_page : bool, optional
    -
    Ability to prepend/append file after each page of output.
    +
    Ability to append file after each page of output. Defaults to None.
    +
    prepend_per_page : bool, optional
    +
    Ability to prepend file after each page of output. Defaults to None.
    +
    output_polling : bool, optional
    +
    A unique link for each request is sent back, which can be used later to download the output file. Defaults to None.
    +
    secret_key : str, optional
    +
    A secret key can be specified to encrypt the file stored on the server (ussed with output polling). Defaults to None.
    +
    request_option : requestOptions, optional
    +
    AOP makes a call to the given option with response/output of the current request. Defaults to None.
    @@ -174,16 +205,25 @@

    Args

    cloud_access_token: CloudAccessToken = None, server_directory: str = None, pdf_options: PDFOptions = None, - append_per_page: bool = None,): - """ + append_per_page: bool = None, + prepend_per_page: bool = None, + output_polling: bool = None, + secret_key: str = None, + request_option: requestOptions = None): + """If the parameters are not provided default value will be used. + Args: - filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). + filetype (str, optional): The file type (as extension) to use for the output. Defaults to None (set to template-type in printjob.py). Defaults to None. encoding (str, optional): Encoding of output file. Either "raw" or "base64". Defaults to "raw". converter (str, optional): The pdf converter to use. Can be "libreoffice", "officetopdf" or any custom defined converter. Custom converters are configurated in the Cloud Office Print server's `aop_config.json` file. Defaults to "libreoffice". cloud_access_token (CloudAccessToken, optional): Access token used to access various cloud services for output storage. Defaults to None. server_directory (str, optional): Base directory to save output files into. Can only be used if the server allows to save on disk. The specific output path for each file is appended to the base path. Defaults to None. pdf_options (PDFOptions, optional): Optional PDF options. Defaults to None. - append_per_page (bool, optional): Ability to prepend/append file after each page of output. + append_per_page (bool, optional): Ability to append file after each page of output. Defaults to None. + prepend_per_page (bool, optional): Ability to prepend file after each page of output. Defaults to None. + output_polling (bool, optional): A unique link for each request is sent back, which can be used later to download the output file. Defaults to None. + secret_key (str, optional): A secret key can be specified to encrypt the file stored on the server (ussed with output polling). Defaults to None. + request_option (requestOptions, optional): AOP makes a call to the given option with response/output of the current request. Defaults to None. """ self.filetype: str = filetype self.converter: str = converter @@ -192,6 +232,10 @@

    Args

    self.pdf_options: PDFOptions = pdf_options self.encoding = encoding self.append_per_page = append_per_page + self.prepend_per_page = prepend_per_page + self.output_polling = output_polling + self.secret_key = secret_key + self.request_option = request_option @property def json(self) -> str: @@ -226,6 +270,14 @@

    Args

    result.update(self.pdf_options.as_dict) if self.append_per_page is not None: result["output_append_per_page"] = self.append_per_page + if self.prepend_per_page is not None: + result["output_prepend_per_page"] = self.prepend_per_page + if self.output_polling is not None: + result['output_polling'] = self.output_polling + if self.secret_key is not None: + result['secret_key'] = self.secret_key + if self.request_option is not None: + result['request_option'] = self.request_option.as_dict return result @property @@ -288,6 +340,14 @@

    Returns

    result.update(self.pdf_options.as_dict) if self.append_per_page is not None: result["output_append_per_page"] = self.append_per_page + if self.prepend_per_page is not None: + result["output_prepend_per_page"] = self.prepend_per_page + if self.output_polling is not None: + result['output_polling'] = self.output_polling + if self.secret_key is not None: + result['secret_key'] = self.secret_key + if self.request_option is not None: + result['request_option'] = self.request_option.as_dict return result
    diff --git a/docs/cloudofficeprint/config/pdf.html b/docs/cloudofficeprint/config/pdf.html index 8d88da6..e66fb1a 100644 --- a/docs/cloudofficeprint/config/pdf.html +++ b/docs/cloudofficeprint/config/pdf.html @@ -27,7 +27,9 @@

    Module cloudofficeprint.config.pdf

    Expand source code
    import json
    -from typing import Union, Iterable, Dict, Mapping
    +from typing import Union, Dict, Mapping
    +
    +from ..resource import Base64Resource, ServerPathResource, URLResource
     
     
     class PDFOptions:
    @@ -37,79 +39,81 @@ 

    Module cloudofficeprint.config.pdf

    All of them are optional, which is why passing an instance of this class in an OutputConfig is also optional. """ - def __init__(self, - read_password: str = None, - watermark: str = None, - watermark_font_size: int = None, - watermark_opacity: int = None, - watermark_color: str = None, - watermark_font: str = None, - page_width: Union[str, int] = None, - page_height: Union[str, int] = None, - even_page: bool = None, - merge_making_even: bool = None, - modify_password: str = None, - password_protection_flag: int = None, - lock_form: bool = None, - copies: int = None, - page_margin: Union[int, dict] = None, - landscape: bool = None, - page_format: str = None, - merge: bool = None, - sign_certificate: str = None, - sign_certificate_password: str = None, - identify_form_fields: bool = None, - split: bool = None, - remove_last_page: bool = None): + def __init__( + self, + even_page: bool = None, + merge_making_even: bool = None, + remove_last_page: bool = None, + modify_password: str = None, + read_password: str = None, + password_protection_flag: int = None, + watermark: str = None, + watermark_color: str = None, + watermark_font: str = None, + watermark_opacity: int = None, + watermark_size: int = None, + lock_form: bool = None, + copies: int = None, + page_margin: Union[int, dict] = None, + landscape: bool = None, + page_width: Union[str, int] = None, + page_height: Union[str, int] = None, + page_format: str = None, + merge: bool = None, + split: bool = None, + identify_form_fields: bool = None, + sign_certificate: str = None, + sign_certificate_password: str = None, + ): """ Args: - read_password (str, optional): The password needed to open the PDF. Defaults to None. - watermark (str, optional): Setting this generates a diagonal custom watermark on every page in the PDF file. Defaults to None. - watermark_color (str, optional): You can specify to change watermark color. Accepts css colors. Defaults to black. - watermark_font (str, optional): You can specify to change the font of watermark. Defaults to Aerial. - watermark_opacity (int, optional): You can specify to change the opacity of watermark. Should be in percentage - watermark_font_size (int, optional): You can specify to change the font size of watemark. Should be a number(px) ie: 45 . - page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. - page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. even_page (bool, optional): If you want your output to have even pages, for example printing on both sides after merging, you can set this to be true. Defaults to None. merge_making_even (bool, optional): Merge each given document making even paged. Defaults to None. + remove_last_page (bool, optional): Remove the last page from the given PDF document. Defaults to None. modify_password (str, optional): The password needed to modify the PDF. Defaults to None. + read_password (str, optional): The password needed to open the PDF. Defaults to None. password_protection_flag (int, optional): Bit field explained in the PDF specs in table 3.20 in section 3.5.2, should be given as an integer. [More info](https://pdfhummus.com/post/147451287581/hummus-1058-and-pdf-writer-updates-encryption). Defaults to None. + watermark (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + watermark_color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + watermark_font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + watermark_opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + watermark_size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. lock_form (bool, optional): Locks / flattens the forms in the PDF. Defaults to None. copies (int, optional): Repeats the output pdf for the given number of times. Defaults to None. page_margin (Union[int, dict], optional): Only for HTML to PDF. Margin in px. Returns either a dict containing: { "top": int, "bottom": int, "left": int, "right": int } or just an int to be used on all sides. Defaults to None. landscape (bool, optional): Only for HTML to PDF. If True: the orientation of the output file is landscape; else portrait (default). Defaults to None. + page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. + page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. page_format (str, optional): Only for HTML to PDF. The page format: "a4" (default) or "letter". Defaults to None. merge (bool, optional): If True: instead of returning back a zip file for multiple output, merge it. Defaults to None. - sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. - sign_certificate_password (str, optional): It is possible to sign certificate with password. - identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. split (bool, optional): You can specify to split a PDF in separate files. You will get one file per page in a zip file. Defaults to None. - remove_last_page (bool, optional): You can specify to remove the last page from output file, this is helpful when the last page of output is blank. + identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. + sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. + sign_certificate_password (str, optional): If you are signing with a password protected certificate, you can specify the password as a plain string. Defaults to None. """ - self.read_password: str = read_password - self.watermark: str = watermark - self.watermark_font: str = watermark_font - self.watermark_font_size: str = watermark_font_size - self.watermark_color: str = watermark_color - self.watermark_opacity: str = watermark_opacity - self.page_width: Union[str, int] = page_width - self.page_height: Union[str, int] = page_height self.even_page: bool = even_page self.merge_making_even: bool = merge_making_even + self.remove_last_page: bool = remove_last_page self.modify_password: str = modify_password + self.read_password: str = read_password self.password_protection_flag: int = password_protection_flag + self.watermark: str = watermark + self.watermark_color: str = watermark_color + self.watermark_font: str = watermark_font + self.watermark_opacity: int = watermark_opacity + self.watermark_size: int = watermark_size self.lock_form: bool = lock_form self.copies: int = copies + self.page_margin: Union[int, dict] = page_margin + self._landscape: bool = landscape + self.page_width: Union[str, int] = page_width + self.page_height: Union[str, int] = page_height self.page_format: str = page_format self.merge: bool = merge - self.page_margin: Union[int, dict] = page_margin + self.split: bool = split + self.identify_form_fields: bool = identify_form_fields self.sign_certificate: str = sign_certificate self.sign_certificate_password: str = sign_certificate_password - self._landscape: bool = landscape - self.identify_form_fields: bool = identify_form_fields - self.split: bool = split - self.remove_last_page = remove_last_page def __str__(self) -> str: """Get the string representation of these PDF options. @@ -144,6 +148,8 @@

    Module cloudofficeprint.config.pdf

    result["output_even_page"] = self.even_page if self.merge_making_even is not None: result["output_merge_making_even"] = self.merge_making_even + if self.remove_last_page is not None: + result["output_remove_last_page"] = self.remove_last_page if self.modify_password is not None: result["output_modify_password"] = self.modify_password if self.read_password is not None: @@ -158,8 +164,8 @@

    Module cloudofficeprint.config.pdf

    result["output_watermark_font"] = self.watermark_font if self.watermark_opacity is not None: result["output_watermark_opacity"] = self.watermark_opacity - if self.watermark_font_size is not None: - result["output_watermark_size"] = self.watermark_font_size + if self.watermark_size is not None: + result["output_watermark_size"] = self.watermark_size if self.lock_form is not None: result["lock_form"] = self.lock_form if self.copies is not None: @@ -167,6 +173,9 @@

    Module cloudofficeprint.config.pdf

    if self.page_margin is not None: # For Cloud Office Print versions later than 21.1.1, output_page_margin will also be supported result["page_margin"] = self.page_margin + if self._landscape is not None: + # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported + result["page_orientation"] = self.page_orientation if self.page_width is not None: result["output_page_width"] = self.page_width if self.page_height is not None: @@ -175,21 +184,43 @@

    Module cloudofficeprint.config.pdf

    result["output_page_format"] = self.page_format if self.merge is not None: result["output_merge"] = self.merge - if self._landscape is not None: - # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported - result["page_orientation"] = self.page_orientation + if self.split is not None: + result["output_split"] = self.split + if self.identify_form_fields is not None: + result["identify_form_fields"] = self.identify_form_fields if self.sign_certificate is not None: result["output_sign_certificate"] = self.sign_certificate if self.sign_certificate_password is not None: - result['output_sign_certificate_password'] = self.sign_certificate_password - if self.identify_form_fields is not None: - result["identify_form_fields"] = self.identify_form_fields - if self.split is not None: - result['output_split'] = self.split - if self.remove_last_page is not None: - result['output_remove_last_page'] = self.remove_last_page + result["output_sign_certificate_password"] = self.sign_certificate_password + return result + def set_watermark( + self, + text: str = None, + color: str = None, + font: str = None, + opacity: int = None, + size: int = None, + ): + """Set watermark + + Set a diagonal custom watermark on every page in the PDF file with a specific text, color, font, opacity and size. + Setting all to None will remove the watermark. + + Args: + text (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. + """ + self.watermark = text + self.watermark_color = color + self.watermark_font = font + self.watermark_opacity = opacity + self.watermark_size = size + def set_page_margin_at(self, value: int, position: str = None): """Set page_margin @@ -205,9 +236,7 @@

    Module cloudofficeprint.config.pdf

    self.page_margin[position] = value elif self.page_margin is None: # page margin not yet defined, set it to a dict with this position defined - self.page_margin = { - position: value - } + self.page_margin = {position: value} else: # page margin defined but no dict, convert to dict first current = self.page_margin @@ -215,7 +244,7 @@

    Module cloudofficeprint.config.pdf

    "top": current, "bottom": current, "left": current, - "right": current + "right": current, } self.page_margin[position] = value else: @@ -237,7 +266,21 @@

    Module cloudofficeprint.config.pdf

    Args: value (str): the page orientation """ - self._landscape = value == "landscape"
    + self._landscape = value == "landscape" + + def sign( + self, + certificate: Union[Base64Resource, ServerPathResource, URLResource], + password: str = None, + ): + """Sign the output PDF with a certificate file. + + Args: + certificate (str): Resource of the certificate file. + password (str): password of the certificate. Defaults to None. + """ + self.sign_certificate = certificate.data + self.sign_certificate_password = password
    @@ -251,7 +294,7 @@

    Classes

    class PDFOptions -(read_password: str = None, watermark: str = None, watermark_font_size: int = None, watermark_opacity: int = None, watermark_color: str = None, watermark_font: str = None, page_width: Union[str, int] = None, page_height: Union[str, int] = None, even_page: bool = None, merge_making_even: bool = None, modify_password: str = None, password_protection_flag: int = None, lock_form: bool = None, copies: int = None, page_margin: Union[int, dict] = None, landscape: bool = None, page_format: str = None, merge: bool = None, sign_certificate: str = None, sign_certificate_password: str = None, identify_form_fields: bool = None, split: bool = None, remove_last_page: bool = None) +(even_page: bool = None, merge_making_even: bool = None, remove_last_page: bool = None, modify_password: str = None, read_password: str = None, password_protection_flag: int = None, watermark: str = None, watermark_color: str = None, watermark_font: str = None, watermark_opacity: int = None, watermark_size: int = None, lock_form: bool = None, copies: int = None, page_margin: Union[int, dict] = None, landscape: bool = None, page_width: Union[str, int] = None, page_height: Union[str, int] = None, page_format: str = None, merge: bool = None, split: bool = None, identify_form_fields: bool = None, sign_certificate: str = None, sign_certificate_password: str = None)

    Class of optional PDF options.

    @@ -259,30 +302,28 @@

    Classes

    All of them are optional, which is why passing an instance of this class in an OutputConfig is also optional.

    Args

    -
    read_password : str, optional
    -
    The password needed to open the PDF. Defaults to None.
    -
    watermark : str, optional
    -
    Setting this generates a diagonal custom watermark on every page in the PDF file. Defaults to None.
    -
    watermark_color : str, optional
    -
    You can specify to change watermark color. Accepts css colors. Defaults to black.
    -
    watermark_font : str, optional
    -
    You can specify to change the font of watermark. Defaults to Aerial.
    -
    watermark_opacity : int, optional
    -
    You can specify to change the opacity of watermark. Should be in percentage
    -
    watermark_font_size : int, optional
    -
    You can specify to change the font size of watemark. Should be a number(px) ie: 45 .
    -
    page_width : Union[str, int], optional
    -
    Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None.
    -
    page_height : Union[str, int], optional
    -
    Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None.
    even_page : bool, optional
    If you want your output to have even pages, for example printing on both sides after merging, you can set this to be true. Defaults to None.
    merge_making_even : bool, optional
    Merge each given document making even paged. Defaults to None.
    +
    remove_last_page : bool, optional
    +
    Remove the last page from the given PDF document. Defaults to None.
    modify_password : str, optional
    The password needed to modify the PDF. Defaults to None.
    +
    read_password : str, optional
    +
    The password needed to open the PDF. Defaults to None.
    password_protection_flag : int, optional
    Bit field explained in the PDF specs in table 3.20 in section 3.5.2, should be given as an integer. More info. Defaults to None.
    +
    watermark : str, optional
    +
    Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None.
    +
    watermark_color : str, optional
    +
    Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None.
    +
    watermark_font : str, optional
    +
    Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None.
    +
    watermark_opacity : int, optional
    +
    Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None.
    +
    watermark_size : int, optional
    +
    Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None.
    lock_form : bool, optional
    Locks / flattens the forms in the PDF. Defaults to None.
    copies : int, optional
    @@ -291,20 +332,22 @@

    Args

    Only for HTML to PDF. Margin in px. Returns either a dict containing: { "top": int, "bottom": int, "left": int, "right": int } or just an int to be used on all sides. Defaults to None.
    landscape : bool, optional
    Only for HTML to PDF. If True: the orientation of the output file is landscape; else portrait (default). Defaults to None.
    +
    page_width : Union[str, int], optional
    +
    Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None.
    +
    page_height : Union[str, int], optional
    +
    Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None.
    page_format : str, optional
    Only for HTML to PDF. The page format: "a4" (default) or "letter". Defaults to None.
    merge : bool, optional
    If True: instead of returning back a zip file for multiple output, merge it. Defaults to None.
    +
    split : bool, optional
    +
    You can specify to split a PDF in separate files. You will get one file per page in a zip file. Defaults to None.
    +
    identify_form_fields : bool, optional
    +
    Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None.
    sign_certificate : str, optional
    Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None.
    sign_certificate_password : str, optional
    -
    It is possible to sign certificate with password.
    -
    identify_form_fields : bool, optional
    -
    Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None.
    -
    split : bool, optional
    -
    You can specify to split a PDF in separate files. You will get one file per page in a zip file. Defaults to None.
    -
    remove_last_page : bool, optional
    -
    You can specify to remove the last page from output file, this is helpful when the last page of output is blank.
    +
    If you are signing with a password protected certificate, you can specify the password as a plain string. Defaults to None.
    @@ -317,79 +360,81 @@

    Args

    All of them are optional, which is why passing an instance of this class in an OutputConfig is also optional. """ - def __init__(self, - read_password: str = None, - watermark: str = None, - watermark_font_size: int = None, - watermark_opacity: int = None, - watermark_color: str = None, - watermark_font: str = None, - page_width: Union[str, int] = None, - page_height: Union[str, int] = None, - even_page: bool = None, - merge_making_even: bool = None, - modify_password: str = None, - password_protection_flag: int = None, - lock_form: bool = None, - copies: int = None, - page_margin: Union[int, dict] = None, - landscape: bool = None, - page_format: str = None, - merge: bool = None, - sign_certificate: str = None, - sign_certificate_password: str = None, - identify_form_fields: bool = None, - split: bool = None, - remove_last_page: bool = None): + def __init__( + self, + even_page: bool = None, + merge_making_even: bool = None, + remove_last_page: bool = None, + modify_password: str = None, + read_password: str = None, + password_protection_flag: int = None, + watermark: str = None, + watermark_color: str = None, + watermark_font: str = None, + watermark_opacity: int = None, + watermark_size: int = None, + lock_form: bool = None, + copies: int = None, + page_margin: Union[int, dict] = None, + landscape: bool = None, + page_width: Union[str, int] = None, + page_height: Union[str, int] = None, + page_format: str = None, + merge: bool = None, + split: bool = None, + identify_form_fields: bool = None, + sign_certificate: str = None, + sign_certificate_password: str = None, + ): """ Args: - read_password (str, optional): The password needed to open the PDF. Defaults to None. - watermark (str, optional): Setting this generates a diagonal custom watermark on every page in the PDF file. Defaults to None. - watermark_color (str, optional): You can specify to change watermark color. Accepts css colors. Defaults to black. - watermark_font (str, optional): You can specify to change the font of watermark. Defaults to Aerial. - watermark_opacity (int, optional): You can specify to change the opacity of watermark. Should be in percentage - watermark_font_size (int, optional): You can specify to change the font size of watemark. Should be a number(px) ie: 45 . - page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. - page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. even_page (bool, optional): If you want your output to have even pages, for example printing on both sides after merging, you can set this to be true. Defaults to None. merge_making_even (bool, optional): Merge each given document making even paged. Defaults to None. + remove_last_page (bool, optional): Remove the last page from the given PDF document. Defaults to None. modify_password (str, optional): The password needed to modify the PDF. Defaults to None. + read_password (str, optional): The password needed to open the PDF. Defaults to None. password_protection_flag (int, optional): Bit field explained in the PDF specs in table 3.20 in section 3.5.2, should be given as an integer. [More info](https://pdfhummus.com/post/147451287581/hummus-1058-and-pdf-writer-updates-encryption). Defaults to None. + watermark (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + watermark_color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + watermark_font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + watermark_opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + watermark_size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. lock_form (bool, optional): Locks / flattens the forms in the PDF. Defaults to None. copies (int, optional): Repeats the output pdf for the given number of times. Defaults to None. page_margin (Union[int, dict], optional): Only for HTML to PDF. Margin in px. Returns either a dict containing: { "top": int, "bottom": int, "left": int, "right": int } or just an int to be used on all sides. Defaults to None. landscape (bool, optional): Only for HTML to PDF. If True: the orientation of the output file is landscape; else portrait (default). Defaults to None. + page_width (Union[str, int], optional): Only for HTML to PDF. Page width in px, mm, cm, in. No unit means px. Defaults to None. + page_height (Union[str, int], optional): Only for HTML to PDF. Page height in px, mm, cm, in. No unit means px. Defaults to None. page_format (str, optional): Only for HTML to PDF. The page format: "a4" (default) or "letter". Defaults to None. merge (bool, optional): If True: instead of returning back a zip file for multiple output, merge it. Defaults to None. - sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. - sign_certificate_password (str, optional): It is possible to sign certificate with password. - identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. split (bool, optional): You can specify to split a PDF in separate files. You will get one file per page in a zip file. Defaults to None. - remove_last_page (bool, optional): You can specify to remove the last page from output file, this is helpful when the last page of output is blank. + identify_form_fields (bool, optional): Identify the form fields in a PDF-form by filling the name of each field into the respective field. Defaults to None. + sign_certificate (str, optional): Signing certificate for the output PDF (pkcs #12 .p12/.pfx) as a base64 string, URL, FTP location or a server path. The function read_file_as_base64() from file_utils.py can be used to read local .p12 or .pfx file as base64. Defaults to None. + sign_certificate_password (str, optional): If you are signing with a password protected certificate, you can specify the password as a plain string. Defaults to None. """ - self.read_password: str = read_password - self.watermark: str = watermark - self.watermark_font: str = watermark_font - self.watermark_font_size: str = watermark_font_size - self.watermark_color: str = watermark_color - self.watermark_opacity: str = watermark_opacity - self.page_width: Union[str, int] = page_width - self.page_height: Union[str, int] = page_height self.even_page: bool = even_page self.merge_making_even: bool = merge_making_even + self.remove_last_page: bool = remove_last_page self.modify_password: str = modify_password + self.read_password: str = read_password self.password_protection_flag: int = password_protection_flag + self.watermark: str = watermark + self.watermark_color: str = watermark_color + self.watermark_font: str = watermark_font + self.watermark_opacity: int = watermark_opacity + self.watermark_size: int = watermark_size self.lock_form: bool = lock_form self.copies: int = copies + self.page_margin: Union[int, dict] = page_margin + self._landscape: bool = landscape + self.page_width: Union[str, int] = page_width + self.page_height: Union[str, int] = page_height self.page_format: str = page_format self.merge: bool = merge - self.page_margin: Union[int, dict] = page_margin + self.split: bool = split + self.identify_form_fields: bool = identify_form_fields self.sign_certificate: str = sign_certificate self.sign_certificate_password: str = sign_certificate_password - self._landscape: bool = landscape - self.identify_form_fields: bool = identify_form_fields - self.split: bool = split - self.remove_last_page = remove_last_page def __str__(self) -> str: """Get the string representation of these PDF options. @@ -424,6 +469,8 @@

    Args

    result["output_even_page"] = self.even_page if self.merge_making_even is not None: result["output_merge_making_even"] = self.merge_making_even + if self.remove_last_page is not None: + result["output_remove_last_page"] = self.remove_last_page if self.modify_password is not None: result["output_modify_password"] = self.modify_password if self.read_password is not None: @@ -438,8 +485,8 @@

    Args

    result["output_watermark_font"] = self.watermark_font if self.watermark_opacity is not None: result["output_watermark_opacity"] = self.watermark_opacity - if self.watermark_font_size is not None: - result["output_watermark_size"] = self.watermark_font_size + if self.watermark_size is not None: + result["output_watermark_size"] = self.watermark_size if self.lock_form is not None: result["lock_form"] = self.lock_form if self.copies is not None: @@ -447,6 +494,9 @@

    Args

    if self.page_margin is not None: # For Cloud Office Print versions later than 21.1.1, output_page_margin will also be supported result["page_margin"] = self.page_margin + if self._landscape is not None: + # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported + result["page_orientation"] = self.page_orientation if self.page_width is not None: result["output_page_width"] = self.page_width if self.page_height is not None: @@ -455,21 +505,43 @@

    Args

    result["output_page_format"] = self.page_format if self.merge is not None: result["output_merge"] = self.merge - if self._landscape is not None: - # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported - result["page_orientation"] = self.page_orientation + if self.split is not None: + result["output_split"] = self.split + if self.identify_form_fields is not None: + result["identify_form_fields"] = self.identify_form_fields if self.sign_certificate is not None: result["output_sign_certificate"] = self.sign_certificate if self.sign_certificate_password is not None: - result['output_sign_certificate_password'] = self.sign_certificate_password - if self.identify_form_fields is not None: - result["identify_form_fields"] = self.identify_form_fields - if self.split is not None: - result['output_split'] = self.split - if self.remove_last_page is not None: - result['output_remove_last_page'] = self.remove_last_page + result["output_sign_certificate_password"] = self.sign_certificate_password + return result + def set_watermark( + self, + text: str = None, + color: str = None, + font: str = None, + opacity: int = None, + size: int = None, + ): + """Set watermark + + Set a diagonal custom watermark on every page in the PDF file with a specific text, color, font, opacity and size. + Setting all to None will remove the watermark. + + Args: + text (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None. + color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None. + font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None. + opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None. + size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None. + """ + self.watermark = text + self.watermark_color = color + self.watermark_font = font + self.watermark_opacity = opacity + self.watermark_size = size + def set_page_margin_at(self, value: int, position: str = None): """Set page_margin @@ -485,9 +557,7 @@

    Args

    self.page_margin[position] = value elif self.page_margin is None: # page margin not yet defined, set it to a dict with this position defined - self.page_margin = { - position: value - } + self.page_margin = {position: value} else: # page margin defined but no dict, convert to dict first current = self.page_margin @@ -495,7 +565,7 @@

    Args

    "top": current, "bottom": current, "left": current, - "right": current + "right": current, } self.page_margin[position] = value else: @@ -517,7 +587,21 @@

    Args

    Args: value (str): the page orientation """ - self._landscape = value == "landscape" + self._landscape = value == "landscape" + + def sign( + self, + certificate: Union[Base64Resource, ServerPathResource, URLResource], + password: str = None, + ): + """Sign the output PDF with a certificate file. + + Args: + certificate (str): Resource of the certificate file. + password (str): password of the certificate. Defaults to None. + """ + self.sign_certificate = certificate.data + self.sign_certificate_password = password

    Instance variables

    @@ -546,6 +630,8 @@

    Returns

    result["output_even_page"] = self.even_page if self.merge_making_even is not None: result["output_merge_making_even"] = self.merge_making_even + if self.remove_last_page is not None: + result["output_remove_last_page"] = self.remove_last_page if self.modify_password is not None: result["output_modify_password"] = self.modify_password if self.read_password is not None: @@ -560,8 +646,8 @@

    Returns

    result["output_watermark_font"] = self.watermark_font if self.watermark_opacity is not None: result["output_watermark_opacity"] = self.watermark_opacity - if self.watermark_font_size is not None: - result["output_watermark_size"] = self.watermark_font_size + if self.watermark_size is not None: + result["output_watermark_size"] = self.watermark_size if self.lock_form is not None: result["lock_form"] = self.lock_form if self.copies is not None: @@ -569,6 +655,9 @@

    Returns

    if self.page_margin is not None: # For Cloud Office Print versions later than 21.1.1, output_page_margin will also be supported result["page_margin"] = self.page_margin + if self._landscape is not None: + # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported + result["page_orientation"] = self.page_orientation if self.page_width is not None: result["output_page_width"] = self.page_width if self.page_height is not None: @@ -577,19 +666,15 @@

    Returns

    result["output_page_format"] = self.page_format if self.merge is not None: result["output_merge"] = self.merge - if self._landscape is not None: - # For Cloud Office Print versions later than 21.1.1, output_page_orientation will also be supported - result["page_orientation"] = self.page_orientation + if self.split is not None: + result["output_split"] = self.split + if self.identify_form_fields is not None: + result["identify_form_fields"] = self.identify_form_fields if self.sign_certificate is not None: result["output_sign_certificate"] = self.sign_certificate if self.sign_certificate_password is not None: - result['output_sign_certificate_password'] = self.sign_certificate_password - if self.identify_form_fields is not None: - result["identify_form_fields"] = self.identify_form_fields - if self.split is not None: - result['output_split'] = self.split - if self.remove_last_page is not None: - result['output_remove_last_page'] = self.remove_last_page + result["output_sign_certificate_password"] = self.sign_certificate_password + return result
    @@ -677,9 +762,7 @@

    Args

    self.page_margin[position] = value elif self.page_margin is None: # page margin not yet defined, set it to a dict with this position defined - self.page_margin = { - position: value - } + self.page_margin = {position: value} else: # page margin defined but no dict, convert to dict first current = self.page_margin @@ -687,13 +770,95 @@

    Args

    "top": current, "bottom": current, "left": current, - "right": current + "right": current, } self.page_margin[position] = value else: self.page_margin = value +
    +def set_watermark(self, text: str = None, color: str = None, font: str = None, opacity: int = None, size: int = None) +
    +
    +

    Set watermark

    +

    Set a diagonal custom watermark on every page in the PDF file with a specific text, color, font, opacity and size. +Setting all to None will remove the watermark.

    +

    Args

    +
    +
    text : str, optional
    +
    Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None.
    +
    color : str, optional
    +
    Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None.
    +
    font : str, optional
    +
    Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None.
    +
    opacity : int, optional
    +
    Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None.
    +
    size : int, optional
    +
    Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None.
    +
    +
    + +Expand source code + +
    def set_watermark(
    +    self,
    +    text: str = None,
    +    color: str = None,
    +    font: str = None,
    +    opacity: int = None,
    +    size: int = None,
    +):
    +    """Set watermark
    +
    +    Set a diagonal custom watermark on every page in the PDF file with a specific text, color, font, opacity and size.
    +    Setting all to None will remove the watermark.
    +
    +    Args:
    +        text (str, optional): Requires PDF output, generates a diagonal custom watermark on every page of the PDF file. Defaults to None.
    +        color (str, optional): Requires PDF output, specifies the font of the watermark specified, with a default of "black". Defaults to None.
    +        font (str, optional): Requires PDF output, specifies the font of the watermark text specified, with a default of "Arial". Defaults to None.
    +        opacity (int, optional): Requires PDF output, specifies the opacity of the watermark text specified, should be as a percentage, i.e. 45. Defaults to None.
    +        size (int, optional): Requires PDF output, specifies the size of watermark text specified, should be a number in px, i.e. 45. Defaults to None.
    +    """
    +    self.watermark = text
    +    self.watermark_color = color
    +    self.watermark_font = font
    +    self.watermark_opacity = opacity
    +    self.watermark_size = size
    +
    +
    +
    +def sign(self, certificate: Union[Base64Resource, ServerPathResource, URLResource], password: str = None) +
    +
    +

    Sign the output PDF with a certificate file.

    +

    Args

    +
    +
    certificate : str
    +
    Resource of the certificate file.
    +
    password : str
    +
    password of the certificate. Defaults to None.
    +
    +
    + +Expand source code + +
    def sign(
    +    self,
    +    certificate: Union[Base64Resource, ServerPathResource, URLResource],
    +    password: str = None,
    +):
    +    """Sign the output PDF with a certificate file.
    +
    +    Args:
    +        certificate (str): Resource of the certificate file.
    +        password (str): password of the certificate. Defaults to None.
    +    """
    +    self.sign_certificate = certificate.data
    +    self.sign_certificate_password = password
    +
    +
    @@ -714,11 +879,13 @@

    Index

    @@ -396,9 +464,7 @@

    Args

    class Command:
         """Command object with a single command for the Cloud Office Print server."""
     
    -    def __init__(self,
    -                 command: str,
    -                 parameters: Mapping[str, str] = None):
    +    def __init__(self, command: str, parameters: Mapping[str, str] = None):
             """
             Args:
                 command (str): The name of the command to execute. This command should be present in the aop_config.json file.
    @@ -414,9 +480,7 @@ 

    Args

    Returns: Dict[str, str]: dict representation of this command """ - result = { - "command": self.command - } + result = {"command": self.command} if self.parameters: result["command_parameters"] = self.parameters @@ -470,13 +534,15 @@

    Args

    class Commands:
         """Command hook configuration class."""
     
    -    def __init__(self,
    -                 post_process: Command = None,
    -                 post_process_return: bool = None,
    -                 post_process_delete_delay: int = None,
    -                 pre_conversion: Command = None,
    -                 post_conversion: Command = None,
    -                 post_merge: Command = None):
    +    def __init__(
    +        self,
    +        post_process: Command = None,
    +        post_process_return: bool = None,
    +        post_process_delete_delay: int = None,
    +        pre_conversion: Command = None,
    +        post_conversion: Command = None,
    +        post_merge: Command = None,
    +    ):
             """
             Args:
                 post_process (Command, optional): Command to run after the given request has been processed but before returning back the output file. Defaults to None.
    @@ -630,10 +696,9 @@ 

    Args

    Args: value (str): URL at which to contact the server """ - if (urlparse(value).scheme == ''): + if urlparse(value).scheme == "": self._url = "http://" + value - logging.warning( - f'No scheme found in "{value}", assuming "{self._url}".') + logging.warning(f'No scheme found in "{value}", assuming "{self._url}".') else: self._url = value @@ -644,8 +709,10 @@

    Args

    bool: whether the server at `Server.url` is reachable """ try: - r = requests.get(urljoin( - self.url, "marco"), proxies=self.config.proxies if self.config is not None else None) + r = requests.get( + urljoin(self.url, "marco"), + proxies=self.config.proxies if self.config is not None else None, + ) return r.text == "polo" except requests.exceptions.ConnectionError: return False @@ -672,8 +739,7 @@

    Args

    ConnectionError: raise error if server is unreachable """ if not self.is_reachable(): - raise ConnectionError( - f"Could not reach server at {self.url}") + raise ConnectionError(f"Could not reach server at {self.url}") def get_version_soffice(self) -> str: """Sends a GET request to server-url/soffice. @@ -682,7 +748,10 @@

    Args

    str: current version of Libreoffice installed on the server. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'soffice'), proxies=self.config.proxies if self.config is not None else None).text + return requests.get( + urljoin(self.url, "soffice"), + proxies=self.config.proxies if self.config is not None else None, + ).text def get_version_officetopdf(self) -> str: """Sends a GET request to server-url/officetopdf. @@ -691,7 +760,10 @@

    Args

    str: current version of OfficeToPdf installed on the server. (Only available if the server runs in Windows environment). """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'officetopdf'), proxies=self.config.proxies if self.config is not None else None).text + return requests.get( + urljoin(self.url, "officetopdf"), + proxies=self.config.proxies if self.config is not None else None, + ).text def get_supported_template_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_template_mimetypes. @@ -700,7 +772,12 @@

    Args

    Dict: JSON of the mime types of templates that Cloud Office Print supports. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_template_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_template_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_output_mimetypes(self, input_type: str) -> Dict: """Sends a GET request to server-url/supported_output_mimetypes?template=input_type. @@ -713,7 +790,14 @@

    Args

    Dict: JSON of the supported output types for the given template extension. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_output_mimetypes' + f'?template={input_type}'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin( + self.url, "supported_output_mimetypes" + f"?template={input_type}" + ), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_prepend_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_prepend_mimetypes. @@ -722,7 +806,12 @@

    Args

    Dict: JSON of the supported prepend file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_prepend_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_prepend_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) def get_supported_append_mimetypes(self) -> Dict: """Sends a GET request to server-url/supported_append_mimetypes. @@ -731,7 +820,29 @@

    Args

    Dict: JSON of the supported append file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_append_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_append_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + ) + + def verify_template_hash(self, hashcode: str) -> bool: + """Sends a GET request to server-url/verify_template_hash?hash=hashcode. + + Args: + hashcode (str): md5 hash of file + + Returns: + bool: whether the hash is valid and present in cache. + """ + self._raise_if_unreachable() + return json.loads( + requests.get( + urljoin(self.url, "verify_template_hash" + f"?hash={hashcode}"), + proxies=self.config.proxies if self.config is not None else None, + ).text + )["valid"] def get_version_cop(self) -> str: """Sends a GET request to server-url/version. @@ -740,7 +851,30 @@

    Args

    str: the version of Cloud Office Print that the server runs. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'version'), proxies=self.config.proxies if self.config is not None else None).text
    + return requests.get( + urljoin(self.url, "version"), + proxies=self.config.proxies if self.config is not None else None, + ).text + + def check_ipp(self, ipp_url: str, version: str) -> Dict: + """Sends a GET request to server-url/ipp_check?ipp_url=ipp_url&version=version. + + Args: + ippURL (str): the URL of the IPP printer. + version (str): the version of the IPP printer. + + Returns: + Dict: the status of the IPP printer. + """ + self._raise_if_unreachable() + return json.loads( + requests.get( + urljoin( + self.url, "ipp_check" + f"?ipp_url={ipp_url}&version={version}" + ), + proxies=self.config.proxies if self.config is not None else None, + ).text + )

    Instance variables

    @@ -769,6 +903,48 @@

    Returns

    Methods

    +
    +def check_ipp(self, ipp_url: str, version: str) ‑> Dict +
    +
    +

    Sends a GET request to server-url/ipp_check?ipp_url=ipp_url&version=version.

    +

    Args

    +
    +
    ippURL : str
    +
    the URL of the IPP printer.
    +
    version : str
    +
    the version of the IPP printer.
    +
    +

    Returns

    +
    +
    Dict
    +
    the status of the IPP printer.
    +
    +
    + +Expand source code + +
    def check_ipp(self, ipp_url: str, version: str) -> Dict:
    +    """Sends a GET request to server-url/ipp_check?ipp_url=ipp_url&version=version.
    +
    +    Args:
    +        ippURL (str): the URL of the IPP printer.
    +        version (str): the version of the IPP printer.
    +
    +    Returns:
    +        Dict: the status of the IPP printer.
    +    """
    +    self._raise_if_unreachable()
    +    return json.loads(
    +        requests.get(
    +            urljoin(
    +                self.url, "ipp_check" + f"?ipp_url={ipp_url}&version={version}"
    +            ),
    +            proxies=self.config.proxies if self.config is not None else None,
    +        ).text
    +    )
    +
    +
    def get_supported_append_mimetypes(self) ‑> Dict
    @@ -790,7 +966,12 @@

    Returns

    Dict: JSON of the supported append file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_append_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text) + return json.loads( + requests.get( + urljoin(self.url, "supported_append_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + )
    @@ -824,7 +1005,14 @@

    Returns

    Dict: JSON of the supported output types for the given template extension. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_output_mimetypes' + f'?template={input_type}'), proxies=self.config.proxies if self.config is not None else None).text)
    + return json.loads( + requests.get( + urljoin( + self.url, "supported_output_mimetypes" + f"?template={input_type}" + ), + proxies=self.config.proxies if self.config is not None else None, + ).text + )
    @@ -848,7 +1036,12 @@

    Returns

    Dict: JSON of the supported prepend file mime types. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_prepend_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text)
    + return json.loads( + requests.get( + urljoin(self.url, "supported_prepend_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + )
    @@ -872,7 +1065,12 @@

    Returns

    Dict: JSON of the mime types of templates that Cloud Office Print supports. """ self._raise_if_unreachable() - return json.loads(requests.get(urljoin(self.url, 'supported_template_mimetypes'), proxies=self.config.proxies if self.config is not None else None).text)
    + return json.loads( + requests.get( + urljoin(self.url, "supported_template_mimetypes"), + proxies=self.config.proxies if self.config is not None else None, + ).text + )
    @@ -896,7 +1094,10 @@

    Returns

    str: the version of Cloud Office Print that the server runs. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'version'), proxies=self.config.proxies if self.config is not None else None).text
    + return requests.get( + urljoin(self.url, "version"), + proxies=self.config.proxies if self.config is not None else None, + ).text
    @@ -920,7 +1121,10 @@

    Returns

    str: current version of OfficeToPdf installed on the server. (Only available if the server runs in Windows environment). """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'officetopdf'), proxies=self.config.proxies if self.config is not None else None).text
    + return requests.get( + urljoin(self.url, "officetopdf"), + proxies=self.config.proxies if self.config is not None else None, + ).text
    @@ -944,7 +1148,10 @@

    Returns

    str: current version of Libreoffice installed on the server. """ self._raise_if_unreachable() - return requests.get(urljoin(self.url, 'soffice'), proxies=self.config.proxies if self.config is not None else None).text
    + return requests.get( + urljoin(self.url, "soffice"), + proxies=self.config.proxies if self.config is not None else None, + ).text
    @@ -998,13 +1205,52 @@

    Returns

    bool: whether the server at `Server.url` is reachable """ try: - r = requests.get(urljoin( - self.url, "marco"), proxies=self.config.proxies if self.config is not None else None) + r = requests.get( + urljoin(self.url, "marco"), + proxies=self.config.proxies if self.config is not None else None, + ) return r.text == "polo" except requests.exceptions.ConnectionError: return False
    +
    +def verify_template_hash(self, hashcode: str) ‑> bool +
    +
    +

    Sends a GET request to server-url/verify_template_hash?hash=hashcode.

    +

    Args

    +
    +
    hashcode : str
    +
    md5 hash of file
    +
    +

    Returns

    +
    +
    bool
    +
    whether the hash is valid and present in cache.
    +
    +
    + +Expand source code + +
    def verify_template_hash(self, hashcode: str) -> bool:
    +    """Sends a GET request to server-url/verify_template_hash?hash=hashcode.
    +
    +    Args:
    +        hashcode (str): md5 hash of file
    +
    +    Returns:
    +        bool: whether the hash is valid and present in cache.
    +    """
    +    self._raise_if_unreachable()
    +    return json.loads(
    +        requests.get(
    +            urljoin(self.url, "verify_template_hash" + f"?hash={hashcode}"),
    +            proxies=self.config.proxies if self.config is not None else None,
    +        ).text
    +    )["valid"]
    +
    +
    @@ -1035,13 +1281,15 @@

    Args

    class ServerConfig:
         """Class for configuring the server options."""
     
    -    def __init__(self,
    -                 api_key: str = None,
    -                 logging: Mapping = None,
    -                 printer: Printer = None,
    -                 commands: Commands = None,
    -                 proxies: Dict[str, str] = None,
    -                 cop_remote_debug: bool = False):
    +    def __init__(
    +        self,
    +        api_key: str = None,
    +        logging: Mapping = None,
    +        printer: Printer = None,
    +        commands: Commands = None,
    +        proxies: Dict[str, str] = None,
    +        cop_remote_debug: bool = False,
    +    ):
             """
             Args:
                 api_key (str, optional): API key to use for communicating with a Cloud Office Print server. Defaults to None.
    @@ -1147,6 +1395,7 @@ 

    Server

  • diff --git a/docs/cloudofficeprint/elements.html b/docs/cloudofficeprint/elements.html index 8f1842a..ef5f313 100644 --- a/docs/cloudofficeprint/elements.html +++ b/docs/cloudofficeprint/elements.html @@ -3,74 +3,75 @@ - + cloudofficeprint.elements API documentation - - - - - - - -
    -
    +

    cloudofficeprint.elements

    Elements are used to replace the various tags in a template with actual data.

    -
    - View Source -
    """
    -Elements are used to replace the various tags in a template with actual data.
    -"""
    +                        
    +
    +                        
     
    -from .charts import *
    -from .codes import *
    -from .elements import *
    -from .images import *
    -from .loops import *
    -from .pdf import *
    -from .rest_source import *
    -
    +
     1"""
    + 2Elements are used to replace the various tags in a template with actual data.
    + 3"""
    + 4
    + 5from .charts import *
    + 6from .codes import *
    + 7from .elements import *
    + 8from .images import *
    + 9from .loops import *
    +10from .pdf import *
    +11from .rest_source import *
    +
    -
    @@ -174,12 +175,26 @@

    } let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}(${doc.parameters.join(", ")})`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; + if (doc.bases) + heading += `(${doc.bases})`; + heading += `:`; + break; + case "variable": + heading = `${doc.fullname}`; + if (doc.annotation) + heading += `${doc.annotation}`; + if (doc.default_value) + heading += `${doc.default_value}`; break; default: heading = `${doc.fullname}`; @@ -187,7 +202,7 @@

    } html += `
    - ${heading} + ${heading}
    ${doc.doc}
    `; diff --git a/docs/cloudofficeprint/elements/elements.html b/docs/cloudofficeprint/elements/elements.html index 77ab7be..76eba2a 100644 --- a/docs/cloudofficeprint/elements/elements.html +++ b/docs/cloudofficeprint/elements/elements.html @@ -67,7 +67,9 @@

    Module cloudofficeprint.elements.elements

    class CellStyleDocx(CellStyle): """Cell styling settings for docx templates""" - def __init__(self, cell_background_color: str = None, width: Union[int, str] = None): + def __init__( + self, cell_background_color: str = None, width: Union[int, str] = None + ): """ Args: cell_background_color (str, optional): The background color of the cell. Defaults to None. @@ -82,9 +84,9 @@

    Module cloudofficeprint.elements.elements

    result = super()._dict_suffixes if self.cell_background_color is not None: - result['_cell_background_color'] = self.cell_background_color + result["_cell_background_color"] = self.cell_background_color if self.width is not None: - result['_width'] = self.width + result["_width"] = self.width return result @@ -119,7 +121,7 @@

    Module cloudofficeprint.elements.elements

    border_diagonal_color: str = None, text_h_alignment: str = None, text_v_alignment: str = None, - text_rotation: Union[int, str] = None + text_rotation: Union[int, str] = None, ): """ Args: @@ -183,63 +185,63 @@

    Module cloudofficeprint.elements.elements

    result = super()._dict_suffixes if self.cell_locked is not None: - result['_cell_locked'] = self.cell_locked + result["_cell_locked"] = self.cell_locked if self.cell_hidden is not None: - result['_cell_hidden'] = self.cell_hidden + result["_cell_hidden"] = self.cell_hidden if self.cell_background is not None: - result['_cell_background'] = self.cell_background + result["_cell_background"] = self.cell_background if self.font_name is not None: - result['_font_name'] = self.font_name + result["_font_name"] = self.font_name if self.font_size is not None: - result['_font_size'] = self.font_size + result["_font_size"] = self.font_size if self.font_color is not None: - result['_font_color'] = self.font_color + result["_font_color"] = self.font_color if self.font_italic is not None: - result['_font_italic'] = self.font_italic + result["_font_italic"] = self.font_italic if self.font_bold is not None: - result['_font_bold'] = self.font_bold + result["_font_bold"] = self.font_bold if self.font_strike is not None: - result['_font_strike'] = self.font_strike + result["_font_strike"] = self.font_strike if self.font_underline is not None: - result['_font_underline'] = self.font_underline + result["_font_underline"] = self.font_underline if self.font_superscript is not None: - result['_font_superscript'] = self.font_superscript + result["_font_superscript"] = self.font_superscript if self.font_subscript is not None: - result['_font_subscript'] = self.font_subscript + result["_font_subscript"] = self.font_subscript if self.border_top is not None: - result['_border_top'] = self.border_top + result["_border_top"] = self.border_top if self.border_top_color is not None: - result['_border_top_color'] = self.border_top_color + result["_border_top_color"] = self.border_top_color if self.border_bottom is not None: - result['_border_bottom'] = self.border_bottom + result["_border_bottom"] = self.border_bottom if self.border_bottom_color is not None: - result['_border_bottom_color'] = self.border_bottom_color + result["_border_bottom_color"] = self.border_bottom_color if self.border_left is not None: - result['_border_left'] = self.border_left + result["_border_left"] = self.border_left if self.border_left_color is not None: - result['_border_left_color'] = self.border_left_color + result["_border_left_color"] = self.border_left_color if self.border_right is not None: - result['_border_right'] = self.border_right + result["_border_right"] = self.border_right if self.border_right_color is not None: - result['_border_right_color'] = self.border_right_color + result["_border_right_color"] = self.border_right_color if self.border_diagonal is not None: - result['_border_diagonal'] = self.border_diagonal + result["_border_diagonal"] = self.border_diagonal if self.border_diagonal_direction is not None: - result['_border_diagonal_direction'] = self.border_diagonal_direction + result["_border_diagonal_direction"] = self.border_diagonal_direction if self.border_diagonal_color is not None: - result['_border_diagonal_color'] = self.border_diagonal_color + result["_border_diagonal_color"] = self.border_diagonal_color if self.text_h_alignment is not None: - result['_text_h_alignment'] = self.text_h_alignment + result["_text_h_alignment"] = self.text_h_alignment if self.text_v_alignment is not None: - result['_text_v_alignment'] = self.text_v_alignment + result["_text_v_alignment"] = self.text_v_alignment if self.text_rotation is not None: - result['_text_rotation'] = self.text_rotation + result["_text_rotation"] = self.text_rotation return result class Element(ABC): - """ The abstract base class for elements.""" + """The abstract base class for elements.""" def __init__(self, name: str): """ @@ -320,9 +322,7 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - return { - self.name: self.value - } + return {self.name: self.value} class CellStyleProperty(Property): @@ -342,9 +342,7 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} for suffix, value in self.cell_style._dict_suffixes.items(): result[self.name + suffix] = value @@ -397,18 +395,20 @@

    Module cloudofficeprint.elements.elements

    class AutoLink(Property): """ This tag allows you to insert text into the document detecting links. """ + def __init__(self, name: str, value: str): """ Args: name (str): The name for this element. value (str): The value of the autoLink. """ - super().__init__(name,value) + super().__init__(name, value) @property def available_tags(self) -> FrozenSet[str]: return frozenset({"{*auto " + self.name + "}"}) + class Hyperlink(Element): def __init__(self, name: str, url: str, text: str = None): """ @@ -427,9 +427,7 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.url - } + result = {self.name: self.url} if self.text is not None: result[self.name + "_text"] = self.text @@ -438,7 +436,9 @@

    Module cloudofficeprint.elements.elements

    class TableOfContents(Element): - def __init__(self, name: str, title: str = None, depth: int = None, tab_leader: str = None): + def __init__( + self, name: str, title: str = None, depth: int = None, tab_leader: str = None + ): """ Args: name (str): The name for this element. @@ -505,7 +505,7 @@

    Module cloudofficeprint.elements.elements

    return { self.name: self.value, self.name + "_row_span": self.rows, - self.name + "_col_span": self.columns + self.name + "_col_span": self.columns, } @@ -524,17 +524,19 @@

    Module cloudofficeprint.elements.elements

    class StyledProperty(Property): - def __init__(self, - name: str, - value: str, - font: str = None, - font_size: Union[str, int] = None, - font_color: str = None, - bold: bool = None, - italic: bool = None, - underline: bool = None, - strikethrough: bool = None, - highlight_color: str = None): + def __init__( + self, + name: str, + value: str, + font: str = None, + font_size: Union[str, int] = None, + font_color: str = None, + bold: bool = None, + italic: bool = None, + underline: bool = None, + strikethrough: bool = None, + highlight_color: str = None, + ): """ Args: name (str): The name for this property. @@ -564,9 +566,7 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: result[self.name + "_font_family"] = self.font @@ -589,15 +589,17 @@

    Module cloudofficeprint.elements.elements

    class Watermark(Property): - def __init__(self, - name: str, - text: str, - color: str = None, - font: str = None, - width: Union[int, str] = None, - height: Union[int, str] = None, - opacity: float = None, - rotation: int = None): + def __init__( + self, + name: str, + text: str, + color: str = None, + font: str = None, + width: Union[int, str] = None, + height: Union[int, str] = None, + opacity: float = None, + rotation: int = None, + ): """ Args: name (str): The name for this property. @@ -623,9 +625,7 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.color is not None: result[self.name + "_color"] = self.color @@ -661,12 +661,10 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.code - } + result = {self.name: self.code} if self.data is not None: - result[self.name + '_data'] = self.data + result[self.name + "_data"] = self.data return result @@ -674,15 +672,14 @@

    Module cloudofficeprint.elements.elements

    class COPChartDateOptions: """Date options for an COPChart (different from ChartDateOptions in charts.py).""" - def __init__(self, - format: str = None, - unit: str = None, - step: Union[int, str] = None): + def __init__( + self, format: str = None, unit: str = None, step: Union[int, str] = None + ): """ Args: format (str, optional): The format to display the date on the chart's axis. Defaults to None. unit (str, optional): The unit to be used for spacing the axis values. Defaults to None. - step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined). + step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined). This option is not supported in LibreOffice. Defaults to None. """ self.format: str = format @@ -706,16 +703,21 @@

    Module cloudofficeprint.elements.elements

    class COPChart(Element): """The class for an COPChart. This is used for chart templating.""" - def __init__(self, - name: str, - x_data: Iterable[Union[str, int, float, Mapping]], - y_datas: Union[Iterable[Iterable[Union[str, int, float, Mapping]]], Mapping[str, Iterable[Union[str, int, float, Mapping]]]], - date: COPChartDateOptions = None, - title: str = None, - x_title: str = None, - y_title: str = None, - y2_title: str = None, - x2_title: str = None): + def __init__( + self, + name: str, + x_data: Iterable[Union[str, int, float, Mapping]], + y_datas: Union[ + Iterable[Iterable[Union[str, int, float, Mapping]]], + Mapping[str, Iterable[Union[str, int, float, Mapping]]], + ], + date: COPChartDateOptions = None, + title: str = None, + x_title: str = None, + y_title: str = None, + y2_title: str = None, + x2_title: str = None, + ): """ Args: name (str): The name for this element. @@ -739,16 +741,15 @@

    Module cloudofficeprint.elements.elements

    self.y_datas: Dict[str, Iterable[Union[str, int, float]]] = None """If the argument 'y_datas' is of type Iterable[Iterable], then default names (e.g. series 1, series 2, ...) will be used.""" if isinstance(y_datas, Mapping): - self.y_datas = { - name: list(data) for name, data in y_datas.items() - } + self.y_datas = {name: list(data) for name, data in y_datas.items()} elif isinstance(y_datas, Iterable): self.y_datas = { f"series {i+1}": list(data) for i, data in enumerate(y_datas) } else: raise TypeError( - f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"') + f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"' + ) self.date: COPChartDateOptions = date self.title: str = title @@ -758,15 +759,17 @@

    Module cloudofficeprint.elements.elements

    self.y2_title: str = y2_title @classmethod - def from_dataframe(cls, - name: str, - data: 'pandas.DataFrame', - date: COPChartDateOptions = None, - title: str = None, - x_title: str = None, - y_title: str = None, - y2_title: str = None, - x2_title: str = None) -> 'COPChart': + def from_dataframe( + cls, + name: str, + data: "pandas.DataFrame", + date: COPChartDateOptions = None, + title: str = None, + x_title: str = None, + y_title: str = None, + y2_title: str = None, + x2_title: str = None, + ) -> "COPChart": """Construct an COPChart object from a [Pandas dataframe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html). Args: @@ -789,7 +792,9 @@

    Module cloudofficeprint.elements.elements

    for col_name, col_data in y_frame.iteritems(): y_datas[col_name] = col_data - return cls(name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title) + return cls( + name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title + ) @property def as_dict(self) -> Dict: @@ -798,26 +803,25 @@

    Module cloudofficeprint.elements.elements

    "data": self.x_data, }, "yAxis": { - "series": [{ - "name": name, - "data": data - } for name, data in self.y_datas.items()] - } + "series": [ + {"name": name, "data": data} for name, data in self.y_datas.items() + ] + }, } if self.title is not None: result["title"] = self.title if self.date is not None: - result['xAxis']['date'] = self.date.as_dict + result["xAxis"]["date"] = self.date.as_dict if self.x_title is not None: result["xAxis"]["title"] = self.x_title if self.y_title is not None: result["yAxis"]["title"] = self.y_title if self.x2_title is not None: - result['x2Axis'] = {} + result["x2Axis"] = {} result["x2Axis"]["title"] = self.x2_title if self.y2_title is not None: - result['y2Axis'] = {} + result["y2Axis"] = {} result["y2Axis"]["title"] = self.y2_title return {self.name: result} @@ -863,15 +867,17 @@

    Module cloudofficeprint.elements.elements

    class TextBox(Element): """This tag will allow you to insert a text box starting in the cell containing the tag in Excel.""" - def __init__(self, - name: str, - value: str, - font: str = None, - font_color: str = None, - font_size: Union[int, str] = None, - transparency: Union[int, str] = None, - width: Union[int, str] = None, - height: Union[int, str] = None): + def __init__( + self, + name: str, + value: str, + font: str = None, + font_color: str = None, + font_size: Union[int, str] = None, + transparency: Union[int, str] = None, + width: Union[int, str] = None, + height: Union[int, str] = None, + ): """ Args: name (str): The name for this element. @@ -898,22 +904,20 @@

    Module cloudofficeprint.elements.elements

    @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: - result[self.name + '_font'] = self.font + result[self.name + "_font"] = self.font if self.font_color is not None: - result[self.name + '_font_color'] = self.font_color + result[self.name + "_font_color"] = self.font_color if self.font_size is not None: - result[self.name + '_font_size'] = self.font_size + result[self.name + "_font_size"] = self.font_size if self.transparency is not None: - result[self.name + '_transparency'] = self.transparency + result[self.name + "_transparency"] = self.transparency if self.width is not None: - result[self.name + '_width'] = self.width + result[self.name + "_width"] = self.width if self.height is not None: - result[self.name + '_height'] = self.height + result[self.name + "_height"] = self.height return result @@ -938,21 +942,373 @@

    Module cloudofficeprint.elements.elements

    class Insert(Property): - """Inside Word and PowerPoint documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents.""" + """Inside Word and PowerPoint and Excel documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents. + Please use `ExcelInsert` element to insert in excel with more flexibility. + """ + + def __init__(self, name: str, value: str): + """ + Args: + name (str): The name for the insert tag. + value (str): Base64 encoded document that needs to be inserted in output docx or pptx. + The documnet can be docx, pptx, xlsx, or pdf documents. + """ + super().__init__(name, value) + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{?insert " + self.name + "}"}) + +class ExcelInsert(Element): + """Inside Excel it is posiible to insert word, powerpoint, excel and pdf file using AOP tag {?insert fileToInsert}. + Options available are: you can provide dynamic icon and icon position. """ - Args: - name (str): The name for the insert tag. - value (str): Base64 encoded document that needs to be inserted in output docx or pptx. - The documnet can be docx, pptx, xlsx, or pdf documents. + + def __init__(self, + name: str, + value: str, + # isPreview: bool = None, + icon: str = None, + fromRow: int = None, + fromCol: Union[str, int] = None, + fromRowOff: str = None, + fromColOff: str = None, + toRow: int = None, + toCol: Union[str, int] = None, + toRowOff: str = None, + toColOff: str = None + ): + """It is possible to provide dynamic icon and position of icon. + + Args: + name (str): Name of insert tag. Ex(fileToInsert) + value (str): File to insert of path to file. (Source can be FTP, SFTP, URL or base64encoded file.) + icon (str, optional): Icon that links the file to insert. Once clicked on it, opens the file inserted. If it is not provide default icon is used. + fromRow (int, optional): position for top of icon. Defaults to row of the tag. + fromCol (Union[str,int], optional): positon for left of icon. Defaults to column of the tag. + fromRowOff (str, optional): space after the value of from Row. Defaults to 0. + fromColOff (str, optional): space after the value of fromCol. Defaults to 0. + toRow (int, optional): position for bottom of icon. Defaults to row of the tag + 3. + toCol (Union[str,int], optional): position for right side of icon. Defaults to column of the tag. + toRowOff (str, optional): space after toRow value. Defaults to 20px. + toColOff (str, optional): space after toCol value. Defaults to 50px. + """ + super().__init__(name) + self.value: str = value + # self.isPreview: bool = isPreview + self.icon: str = icon + self.fromRow: int = fromRow + self.fromCol: Union[str, int] = fromCol + self.fromRowOff: str = fromRowOff + self.fromColOff: str = fromColOff + self.toRow: int = toRow + self.toCol: Union[str, int] = toCol + self.toRowOff: str = toRowOff + self.toColOff: str = toColOff + + @property + def as_dict(self) -> Dict: + result = { + self.name: self.value + } + # if self.isPreview is not None: + # result[self.name+'_isPreview'] = self.isPreview + if self.icon is not None: + result[self.name+'_icon'] = self.icon + if self.fromRow is not None: + result[self.name+'_fromRow'] = self.fromRow + if self.fromCol is not None: + result[self.name+'_fromCol'] = self.fromCol + if self.fromRowOff is not None: + result[self.name+'_fromRowOff'] = self.fromRowOff + if self.fromColOff is not None: + result[self.name+'_fromColOff'] = self.fromColOff + if self.toRow is not None: + result[self.name+'_toRow'] = self.toRow + if self.toCol is not None: + result[self.name+'_toCol'] = self.toCol + if self.toRowOff is not None: + result[self.name+'_toRowOff'] = self.toRowOff + if self.toColOff is not None: + result[self.name+'_toColOff'] = self.toColOff + + return result + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{?insert fileToInsert}"}) + + +class Embed(Property): + """Inside Word, it is possible to copy the content of one docx file to the template without rendering. + + To do so, you can use AOP embed tag as {?embed fileToEmbed} where fileToEmbed contains the path of file or file itself. + + The content of fileToEmbed replaces the tag + + Only supported in Word and only supports docx file to embed. """ def __init__(self, name: str, value: str): + """It takes the tagName and its value as parameter. + + Args: + name (str): Name of the tag (ex. fileToEmbed) + value (str): File to embed. Source can be FTP, SFTP, URL or base64 encoded file. (ex. base64encoded string) + """ super().__init__(name, value) @property def available_tags(self) -> FrozenSet[str]: - return frozenset({"{?insert " + self.name + "}"}) + return frozenset({"{?embed fileToEmbed}"}) + + +class SheetProtection(Element): + """Inside Excel documents, this tag can be used to make password protected sheets. This tag has the feature of password along with different other features. + + Note: value is considered password, so try to use only one (either value or passowrd). + """ + + def __init__(self, + name: str, + value: str = None, + autoFilter: str = None, + deleteColumns: bool = None, + deleteRows: bool = None, + formatCells: bool = None, + formatColumns: bool = None, + formatRows: bool = None, + insertColumns: bool = None, + insertHyperlinks: bool = None, + insertRows: bool = None, + password: str = None, + pivotTables: bool = None, + selectLockedCells: bool = None, + selectUnlockedCells: bool = None, + sort: bool = None, + ): + """ + Args: + name (str): The name for the sheet protection tag. + value (str): Value for the tag; this is used as password + autoFilter (str): lock auto filter in sheet. + deleteColumns (bool): lock delete columns in sheet. + deleteRows (bool): lock delete rows in sheet. + formatCells (bool): lock format cells. + formatColumns (bool): lock format columns. + formatRows (bool): lock format rows. + insertColumns (bool): lock insert columns. + insertHyperlinks (bool): lock insert hyperlinks. + insertRows (bool): lock insert rows. + password (str): password to lock with. + pivotTables (bool): lock pivot tables. + selectLockedCells (bool): lock select locked cells. + selectUnlockedCells (bool): lock select unlocked cells. + sort (bool): lock sort. + """ + super().__init__(name) + self.value = value + self.autoFilter = autoFilter + self.deleteColumns = deleteColumns + self.deleteRows = deleteRows + self.formatCells = formatCells + self.formatColumns = formatColumns + self.formatRows = formatRows + self.insertColumns = insertColumns + self.insertHyperlinks = insertHyperlinks + self.insertRows = insertRows + self.password = password + self.pivotTables = pivotTables + self.selectLockedCells = selectLockedCells + self.selectUnlockedCells = selectUnlockedCells + self.sort = sort + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{protect " + self.name + "}"}) + + @property + def as_dict(self) -> Dict: + result = {} + if self.value is not None: + result[self.name] = self.value + if self.autoFilter is not None: + result[self.name+'_allow_auto_filter'] = self.autoFilter + if self.deleteColumns is not None: + result[self.name+'_allow_delete_columns'] = self.deleteColumns + if self.deleteRows is not None: + result[self.name+'_allow_delete_rows'] = self.deleteRows + if self.formatCells is not None: + result[self.name+'_allow_format_cells'] = self.formatCells + if self.formatColumns is not None: + result[self.name+'_allow_format_columns'] = self.formatColumns + if self.formatRows is not None: + result[self.name+'_allow_format_rows'] = self.formatRows + if self.insertColumns is not None: + result[self.name+'_allow_insert_columns'] = self.insertColumns + if self.insertHyperlinks is not None: + result[self.name+'_allow_insert_hyperlinks'] = self.insertHyperlinks + if self.insertRows is not None: + result[self.name+'_allow_insert_rows'] = self.insertRows + if self.password is not None: + result[self.name+'_password'] = self.password + if self.pivotTables is not None: + result[self.name+'_allow_pivot_tables'] = self.pivotTables + if self.selectLockedCells is not None: + result[self.name+'_allow_select_locked_cells'] = self.selectLockedCells + if self.selectUnlockedCells is not None: + result[self.name+'_allow_select_unlocked_cells'] = self.selectUnlockedCells + if self.sort is not None: + result[self.name+'_allow_sort'] = self.sort + return result + + +class ValidateCell(Element): + """ + It is possible to insert cell validation in excel using validate tag as {validate validateTag} (validate keyword followed by tagName) + """ + def __init__(self, + name: str, + ignoreBlank: bool = None, + allow: str = None, + value1: str = None, + value2: str = None, + inCellDropdown: bool = None, + data: str = None, + showInputMessage: bool = None, + inputTitle: str = None, + inputMessage: str = None, + showErrorAlert: bool = None, + errorStyle: str = None, + errorTitle: str = None, + errorMessage: str = None, + ): + """Available option while using validate cell are ( ignoreBlank, allow, value1, value2, inCellDropdown, data, showInputMessage, inputTitle, inputMessage, showErrorAlert, errorStyle, errorTitle,errorMessage ) + + Args: + name (string, optional): Name of the validate tag. For {validate tagName}, tagName is name for this element. + ignoreBlank (bool, optional): Set it to false for not allowing empty values in cell. The value is true by default. + allow (string, optional): Type of data used for validation. Available options are (anyValue, whole, decimal, list, date, time, textLength, custom). Please use camelCase to insert value for allow attribute. + value1 (string, optional): Value to compare with. + value2 (string, optional): Value to compare with.<br> + <i>Note: + These two options <strong>(_value1, _value2)</strong> can be used for any allow/type of validation that require values for comparison, in such case use <strong>"_value1"</strong> attribute as the first value to be passed and <strong>"_value2"</strong> attribute as the 2nd value.<br><br> + Some allow type of validation require only one value to compare; in such case use <strong>"_value1"</strong> attribute.<br><br> + For ex :<br> + If allow type of validation is date and you have to check in between two dates.<br> + Then you could use <strong>"_value1"</strong> attribute as start date and <strong>"_value2"</strong> attribute as end date.<br><br> + If allow type of validation is whole and you have to check for value less than 100.<br> + Then you could use <strong>"_value1"</strong> for that value and do not use "<strong>_value2".</strong><br><br> + While using time and date as allow type validation, please provide date/time with correct formatting.<br> + for time: <strong>hours:minutes:seconds</strong> i.e hours , minutes, seconds separated by colon (:)<br> + ex : 14:30:00 for 2:30 pm<br><br> + for date: <strong>month/day/year</strong> i.e day, month , year separated by forward slash(/)<br> + ex : 02/07/2023 for Feb 7 2023.<br><br> + for list: you could use normal string with elements separated by comma(,).<br> + ex : "first, second, third" for list of three elements.<br></i> + inCellDropdown (bool, optional): Set it to false for not showing dropdown button while validation allow type is list. It is true by default for list allow type. + data (string, optional): Type of comparison to be done for the cell value. Available values are (lessThanOrEqual, notBetween, equal, notEqual, greaterThan, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual). Default value is "between". Please use camelCase for the value as shown in examples. + showInputMessage (bool, optional): Set it to false to hide message shown when the cell to validate is being selected. The value for it is true by default. + inputTitle (string, optional): Title of message to be shown when cell to validate is selected. + inputMessage (string, optional): Message to be shown when cell to validate is selected. + showErrorAlert (bool, optional): Set it to false, if you want to hide error alert once cell validation fails. The value is true by default. + errorStyle (string, optional): Type of error style when cell validation fails. The value is stop by default. Available options are(stop,waring, Information). + errorTitle (string, optional): Title of error to be shown when cell validation fails. + errorMessage (string, optional): Message of error to be shown when cell validation fails. + """ + super().__init__(name) + self.ignoreBlank = ignoreBlank + self.allow = allow + self.value1 = value1 + self.value2 = value2 + self.inCellDropdown = inCellDropdown + self.data = data + self.showInputMessage = showInputMessage + self.inputTitle = inputTitle + self.inputMessage = inputMessage + self.showErrorAlert = showErrorAlert + self.errorStyle = errorStyle + self.errorTitle = errorTitle + self.errorMessage = errorMessage + + @property + def available_tags(self) -> FrozenSet[str]: + return frozenset({"{validate " + self.name + "}"}) + + def as_dict(self) -> Dict: + result = {} + if self.ignoreBlank is not None: + result[self.name + '_ignore_blank'] = self.ignoreBlank + if self.allow is not None: + result[self.name + '_allow'] = self.allow + if self.value1 is not None: + result[self.name + '_value1'] = self.value1 + if self.value2 is not None: + result[self.name + '_value2'] = self.value2 + if self.inCellDropdown is not None: + result[self.name + '_in_cell_dropdown'] = self.inCellDropdown + if self.data is not None: + result[self.name + '_data'] = self.data + if self.showInputMessage is not None: + result[self.name + '_show_input_message'] = self.showInputMessage + if self.inputTitle is not None: + result[self.name + '_input_title'] = self.inputTitle + if self.inputMessage is not None: + result[self.name + '_input_message'] = self.inputMessage + if self.showErrorAlert is not None: + result[self.name + '_show_error_alert'] = self.showErrorAlert + if self.errorStyle is not None: + result[self.name + '_error_style'] = self.errorStyle + if self.errorTitle is not None: + result[self.name + '_error_title'] = self.errorTitle + if self.errorMessage is not None: + result[self.name + '_error_message'] = self.errorMessage + return result + + +class Link(Property): + """The class for the link/target tags. + This tags allows you to place a link to a target in the same document. + If the uid is not provided, a new uid will be generated uniquely for every link and target pair. + """ + + def __init__( + self, + name: str, + value: str, + uid_name: str = None, + uid_value: str = None, + ): + """Create a new link/target tag pair. + If the uid is not provided, a new uid will be generated uniquely for each link/target pair. + + Args: + name (str): the name of the link/target tags. + value (str): the value of the link/target tags. + uid_name (str): the name of the uid of the link/target pair. + uid_value (str): the value of the uid of the link/target pair. + """ + super().__init__(name, value) + self.uid_name = uid_name + self.uid_value = uid_value + + @property + def available_tags(self) -> FrozenSet[str]: + if self.uid_name and self.uid_value: + return frozenset( + { + "{link" + self.name + ":" + self.uid_name + "}", + "{target" + self.name + ":" + self.uid_name + "}", + } + ) + return frozenset({"{link" + self.name + "}", "{target" + self.name + "}"}) + + @property + def as_dict(self) -> Dict: + if self.uid_name and self.uid_value: + return {self.name: self.value, self.uid_name: self.uid_value} + return {self.name: self.value} class ElementCollection(list, Element): @@ -984,14 +1340,14 @@

    Module cloudofficeprint.elements.elements

    """ return self.json - def copy(self) -> 'ElementCollection': + def copy(self) -> "ElementCollection": """ Returns: ElementCollection: A copy of this element collection. """ return self.__class__(self) - def deepcopy(self) -> 'ElementCollection': + def deepcopy(self) -> "ElementCollection": """ Returns: ElementCollection: A deep copy of this element collection. @@ -1010,7 +1366,7 @@

    Module cloudofficeprint.elements.elements

    """ self.append(element) - def add_all(self, obj: 'ElementCollection'): + def add_all(self, obj: "ElementCollection"): """Add all the elements in the given collection to this collection. Args: @@ -1026,8 +1382,7 @@

    Module cloudofficeprint.elements.elements

    element_name (str): the name of the element that needs to be removed """ self.remove( - next(element for element in self if element.name == element_name) - ) + next(element for element in self if element.name == element_name)) @property def as_dict(self) -> Dict: @@ -1052,7 +1407,9 @@

    Module cloudofficeprint.elements.elements

    return frozenset(result) @classmethod - def element_to_element_collection(cls, element: Element, name: str = "") -> 'ElementCollection': + def element_to_element_collection( + cls, element: Element, name: str = "" + ) -> "ElementCollection": """Generate an element collection from an element and a name. Args: @@ -1065,7 +1422,7 @@

    Module cloudofficeprint.elements.elements

    return cls.from_mapping(element.as_dict, name) @classmethod - def from_mapping(cls, mapping: Mapping, name: str = "") -> 'ElementCollection': + def from_mapping(cls, mapping: Mapping, name: str = "") -> "ElementCollection": """Generate an element collection from a mapping and a name. Args: @@ -1081,7 +1438,7 @@

    Module cloudofficeprint.elements.elements

    return cls(name, result_set) @classmethod - def from_json(cls, json_str: str, name: str = "") -> 'ElementCollection': + def from_json(cls, json_str: str, name: str = "") -> "ElementCollection": """Generate an element collection from a JSON string. Args: @@ -1123,13 +1480,14 @@

    Args

    class AutoLink(Property):
         """ This tag allows you to insert text into the document detecting links. 
         """
    +
         def __init__(self, name: str, value: str):
             """
             Args:
                 name (str): The name for this element.
                 value (str): The value of the autoLink.
             """
    -        super().__init__(name,value)
    +        super().__init__(name, value)
     
         @property
         def available_tags(self) -> FrozenSet[str]:
    @@ -1192,16 +1550,21 @@ 

    Raises

    class COPChart(Element):
         """The class for an COPChart. This is used for chart templating."""
     
    -    def __init__(self,
    -                 name: str,
    -                 x_data: Iterable[Union[str, int, float, Mapping]],
    -                 y_datas: Union[Iterable[Iterable[Union[str, int, float, Mapping]]], Mapping[str, Iterable[Union[str, int, float, Mapping]]]],
    -                 date: COPChartDateOptions = None,
    -                 title: str = None,
    -                 x_title: str = None,
    -                 y_title: str = None,
    -                 y2_title: str = None,
    -                 x2_title: str = None):
    +    def __init__(
    +        self,
    +        name: str,
    +        x_data: Iterable[Union[str, int, float, Mapping]],
    +        y_datas: Union[
    +            Iterable[Iterable[Union[str, int, float, Mapping]]],
    +            Mapping[str, Iterable[Union[str, int, float, Mapping]]],
    +        ],
    +        date: COPChartDateOptions = None,
    +        title: str = None,
    +        x_title: str = None,
    +        y_title: str = None,
    +        y2_title: str = None,
    +        x2_title: str = None,
    +    ):
             """
             Args:
                 name (str): The name for this element.
    @@ -1225,16 +1588,15 @@ 

    Raises

    self.y_datas: Dict[str, Iterable[Union[str, int, float]]] = None """If the argument 'y_datas' is of type Iterable[Iterable], then default names (e.g. series 1, series 2, ...) will be used.""" if isinstance(y_datas, Mapping): - self.y_datas = { - name: list(data) for name, data in y_datas.items() - } + self.y_datas = {name: list(data) for name, data in y_datas.items()} elif isinstance(y_datas, Iterable): self.y_datas = { f"series {i+1}": list(data) for i, data in enumerate(y_datas) } else: raise TypeError( - f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"') + f'Expected Mapping or Iterable for y_data, got "{type(y_datas)}"' + ) self.date: COPChartDateOptions = date self.title: str = title @@ -1244,15 +1606,17 @@

    Raises

    self.y2_title: str = y2_title @classmethod - def from_dataframe(cls, - name: str, - data: 'pandas.DataFrame', - date: COPChartDateOptions = None, - title: str = None, - x_title: str = None, - y_title: str = None, - y2_title: str = None, - x2_title: str = None) -> 'COPChart': + def from_dataframe( + cls, + name: str, + data: "pandas.DataFrame", + date: COPChartDateOptions = None, + title: str = None, + x_title: str = None, + y_title: str = None, + y2_title: str = None, + x2_title: str = None, + ) -> "COPChart": """Construct an COPChart object from a [Pandas dataframe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html). Args: @@ -1275,7 +1639,9 @@

    Raises

    for col_name, col_data in y_frame.iteritems(): y_datas[col_name] = col_data - return cls(name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title) + return cls( + name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title + ) @property def as_dict(self) -> Dict: @@ -1284,26 +1650,25 @@

    Raises

    "data": self.x_data, }, "yAxis": { - "series": [{ - "name": name, - "data": data - } for name, data in self.y_datas.items()] - } + "series": [ + {"name": name, "data": data} for name, data in self.y_datas.items() + ] + }, } if self.title is not None: result["title"] = self.title if self.date is not None: - result['xAxis']['date'] = self.date.as_dict + result["xAxis"]["date"] = self.date.as_dict if self.x_title is not None: result["xAxis"]["title"] = self.x_title if self.y_title is not None: result["yAxis"]["title"] = self.y_title if self.x2_title is not None: - result['x2Axis'] = {} + result["x2Axis"] = {} result["x2Axis"]["title"] = self.x2_title if self.y2_title is not None: - result['y2Axis'] = {} + result["y2Axis"] = {} result["y2Axis"]["title"] = self.y2_title return {self.name: result} @@ -1353,15 +1718,17 @@

    Returns

    Expand source code
    @classmethod
    -def from_dataframe(cls,
    -                   name: str,
    -                   data: 'pandas.DataFrame',
    -                   date: COPChartDateOptions = None,
    -                   title: str = None,
    -                   x_title: str = None,
    -                   y_title: str = None,
    -                   y2_title: str = None,
    -                   x2_title: str = None) -> 'COPChart':
    +def from_dataframe(
    +    cls,
    +    name: str,
    +    data: "pandas.DataFrame",
    +    date: COPChartDateOptions = None,
    +    title: str = None,
    +    x_title: str = None,
    +    y_title: str = None,
    +    y2_title: str = None,
    +    x2_title: str = None,
    +) -> "COPChart":
         """Construct an COPChart object from a [Pandas dataframe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html).
     
         Args:
    @@ -1384,7 +1751,9 @@ 

    Returns

    for col_name, col_data in y_frame.iteritems(): y_datas[col_name] = col_data - return cls(name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title)
    + return cls( + name, x_data, y_datas, date, title, x_title, y_title, y2_title, x2_title + )
    @@ -1429,15 +1798,14 @@

    Args

    class COPChartDateOptions:
         """Date options for an COPChart (different from ChartDateOptions in charts.py)."""
     
    -    def __init__(self,
    -                 format: str = None,
    -                 unit: str = None,
    -                 step: Union[int, str] = None):
    +    def __init__(
    +        self, format: str = None, unit: str = None, step: Union[int, str] = None
    +    ):
             """
             Args:
                 format (str, optional): The format to display the date on the chart's axis. Defaults to None.
                 unit (str, optional): The unit to be used for spacing the axis values. Defaults to None.
    -            step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined). 
    +            step (Union[int, str], optional): How many of the above unit should be used for spacing the axis values (automatic if undefined).
                     This option is not supported in LibreOffice. Defaults to None.
             """
             self.format: str = format
    @@ -1588,7 +1956,9 @@ 

    Args

    class CellStyleDocx(CellStyle):
         """Cell styling settings for docx templates"""
     
    -    def __init__(self, cell_background_color: str = None, width: Union[int, str] = None):
    +    def __init__(
    +        self, cell_background_color: str = None, width: Union[int, str] = None
    +    ):
             """
             Args:
                 cell_background_color (str, optional): The background color of the cell. Defaults to None.
    @@ -1603,9 +1973,9 @@ 

    Args

    result = super()._dict_suffixes if self.cell_background_color is not None: - result['_cell_background_color'] = self.cell_background_color + result["_cell_background_color"] = self.cell_background_color if self.width is not None: - result['_width'] = self.width + result["_width"] = self.width return result
    @@ -1660,9 +2030,7 @@

    Args

    @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} for suffix, value in self.cell_style._dict_suffixes.items(): result[self.name + suffix] = value @@ -1781,7 +2149,7 @@

    Args

    border_diagonal_color: str = None, text_h_alignment: str = None, text_v_alignment: str = None, - text_rotation: Union[int, str] = None + text_rotation: Union[int, str] = None, ): """ Args: @@ -1845,57 +2213,57 @@

    Args

    result = super()._dict_suffixes if self.cell_locked is not None: - result['_cell_locked'] = self.cell_locked + result["_cell_locked"] = self.cell_locked if self.cell_hidden is not None: - result['_cell_hidden'] = self.cell_hidden + result["_cell_hidden"] = self.cell_hidden if self.cell_background is not None: - result['_cell_background'] = self.cell_background + result["_cell_background"] = self.cell_background if self.font_name is not None: - result['_font_name'] = self.font_name + result["_font_name"] = self.font_name if self.font_size is not None: - result['_font_size'] = self.font_size + result["_font_size"] = self.font_size if self.font_color is not None: - result['_font_color'] = self.font_color + result["_font_color"] = self.font_color if self.font_italic is not None: - result['_font_italic'] = self.font_italic + result["_font_italic"] = self.font_italic if self.font_bold is not None: - result['_font_bold'] = self.font_bold + result["_font_bold"] = self.font_bold if self.font_strike is not None: - result['_font_strike'] = self.font_strike + result["_font_strike"] = self.font_strike if self.font_underline is not None: - result['_font_underline'] = self.font_underline + result["_font_underline"] = self.font_underline if self.font_superscript is not None: - result['_font_superscript'] = self.font_superscript + result["_font_superscript"] = self.font_superscript if self.font_subscript is not None: - result['_font_subscript'] = self.font_subscript + result["_font_subscript"] = self.font_subscript if self.border_top is not None: - result['_border_top'] = self.border_top + result["_border_top"] = self.border_top if self.border_top_color is not None: - result['_border_top_color'] = self.border_top_color + result["_border_top_color"] = self.border_top_color if self.border_bottom is not None: - result['_border_bottom'] = self.border_bottom + result["_border_bottom"] = self.border_bottom if self.border_bottom_color is not None: - result['_border_bottom_color'] = self.border_bottom_color + result["_border_bottom_color"] = self.border_bottom_color if self.border_left is not None: - result['_border_left'] = self.border_left + result["_border_left"] = self.border_left if self.border_left_color is not None: - result['_border_left_color'] = self.border_left_color + result["_border_left_color"] = self.border_left_color if self.border_right is not None: - result['_border_right'] = self.border_right + result["_border_right"] = self.border_right if self.border_right_color is not None: - result['_border_right_color'] = self.border_right_color + result["_border_right_color"] = self.border_right_color if self.border_diagonal is not None: - result['_border_diagonal'] = self.border_diagonal + result["_border_diagonal"] = self.border_diagonal if self.border_diagonal_direction is not None: - result['_border_diagonal_direction'] = self.border_diagonal_direction + result["_border_diagonal_direction"] = self.border_diagonal_direction if self.border_diagonal_color is not None: - result['_border_diagonal_color'] = self.border_diagonal_color + result["_border_diagonal_color"] = self.border_diagonal_color if self.text_h_alignment is not None: - result['_text_h_alignment'] = self.text_h_alignment + result["_text_h_alignment"] = self.text_h_alignment if self.text_v_alignment is not None: - result['_text_v_alignment'] = self.text_v_alignment + result["_text_v_alignment"] = self.text_v_alignment if self.text_rotation is not None: - result['_text_rotation'] = self.text_rotation + result["_text_rotation"] = self.text_rotation return result
    @@ -1950,12 +2318,10 @@

    Args

    @property def as_dict(self) -> Dict: - result = { - self.name: self.code - } + result = {self.name: self.code} if self.data is not None: - result[self.name + '_data'] = self.data + result[self.name + "_data"] = self.data return result
    @@ -1991,7 +2357,7 @@

    Args

    Expand source code
    class Element(ABC):
    -    """ The abstract base class for elements."""
    +    """The abstract base class for elements."""
     
         def __init__(self, name: str):
             """
    @@ -2060,10 +2426,13 @@ 

    Subclasses

  • COPChart
  • D3Code
  • ElementCollection
  • +
  • ExcelInsert
  • Hyperlink
  • Property
  • +
  • SheetProtection
  • TableOfContents
  • TextBox
  • +
  • ValidateCell
  • Image
  • ForEach
  • PDFFormData
  • @@ -2196,14 +2565,14 @@

    Args

    """ return self.json - def copy(self) -> 'ElementCollection': + def copy(self) -> "ElementCollection": """ Returns: ElementCollection: A copy of this element collection. """ return self.__class__(self) - def deepcopy(self) -> 'ElementCollection': + def deepcopy(self) -> "ElementCollection": """ Returns: ElementCollection: A deep copy of this element collection. @@ -2222,7 +2591,7 @@

    Args

    """ self.append(element) - def add_all(self, obj: 'ElementCollection'): + def add_all(self, obj: "ElementCollection"): """Add all the elements in the given collection to this collection. Args: @@ -2238,8 +2607,7 @@

    Args

    element_name (str): the name of the element that needs to be removed """ self.remove( - next(element for element in self if element.name == element_name) - ) + next(element for element in self if element.name == element_name)) @property def as_dict(self) -> Dict: @@ -2264,7 +2632,9 @@

    Args

    return frozenset(result) @classmethod - def element_to_element_collection(cls, element: Element, name: str = "") -> 'ElementCollection': + def element_to_element_collection( + cls, element: Element, name: str = "" + ) -> "ElementCollection": """Generate an element collection from an element and a name. Args: @@ -2277,7 +2647,7 @@

    Args

    return cls.from_mapping(element.as_dict, name) @classmethod - def from_mapping(cls, mapping: Mapping, name: str = "") -> 'ElementCollection': + def from_mapping(cls, mapping: Mapping, name: str = "") -> "ElementCollection": """Generate an element collection from a mapping and a name. Args: @@ -2293,7 +2663,7 @@

    Args

    return cls(name, result_set) @classmethod - def from_json(cls, json_str: str, name: str = "") -> 'ElementCollection': + def from_json(cls, json_str: str, name: str = "") -> "ElementCollection": """Generate an element collection from a JSON string. Args: @@ -2335,7 +2705,9 @@

    Returns

    Expand source code
    @classmethod
    -def element_to_element_collection(cls, element: Element, name: str = "") -> 'ElementCollection':
    +def element_to_element_collection(
    +    cls, element: Element, name: str = ""
    +) -> "ElementCollection":
         """Generate an element collection from an element and a name.
     
         Args:
    @@ -2370,7 +2742,7 @@ 

    Returns

    Expand source code
    @classmethod
    -def from_json(cls, json_str: str, name: str = "") -> 'ElementCollection':
    +def from_json(cls, json_str: str, name: str = "") -> "ElementCollection":
         """Generate an element collection from a JSON string.
     
         Args:
    @@ -2405,7 +2777,7 @@ 

    Returns

    Expand source code
    @classmethod
    -def from_mapping(cls, mapping: Mapping, name: str = "") -> 'ElementCollection':
    +def from_mapping(cls, mapping: Mapping, name: str = "") -> "ElementCollection":
         """Generate an element collection from a mapping and a name.
     
         Args:
    @@ -2492,7 +2864,7 @@ 

    Args

    Expand source code -
    def add_all(self, obj: 'ElementCollection'):
    +
    def add_all(self, obj: "ElementCollection"):
         """Add all the elements in the given collection to this collection.
     
         Args:
    @@ -2515,7 +2887,7 @@ 

    Args

    Expand source code -
    def copy(self) -> 'ElementCollection':
    +
    def copy(self) -> "ElementCollection":
         """
         Returns:
             ElementCollection: A copy of this element collection.
    @@ -2536,7 +2908,7 @@ 

    Args

    Expand source code -
    def deepcopy(self) -> 'ElementCollection':
    +
    def deepcopy(self) -> "ElementCollection":
         """
         Returns:
             ElementCollection: A deep copy of this element collection.
    @@ -2565,8 +2937,7 @@ 

    Args

    element_name (str): the name of the element that needs to be removed """ self.remove( - next(element for element in self if element.name == element_name) - )
    + next(element for element in self if element.name == element_name))
    @@ -2580,6 +2951,200 @@

    Inherited members

  • +
    +class Embed +(name: str, value: str) +
    +
    +

    Inside Word, it is possible to copy the content of one docx file to the template without rendering.

    +

    To do so, you can use AOP embed tag as {?embed fileToEmbed} where fileToEmbed contains the path of file or file itself.

    +

    The content of fileToEmbed replaces the tag

    +

    Only supported in Word and only supports docx file to embed.

    +

    It takes the tagName and its value as parameter.

    +

    Args

    +
    +
    name : str
    +
    Name of the tag (ex. fileToEmbed)
    +
    value : str
    +
    File to embed. Source can be FTP, SFTP, URL or base64 encoded file. (ex. base64encoded string)
    +
    +
    + +Expand source code + +
    class Embed(Property):
    +    """Inside Word, it is possible to copy the content of one docx file to the template without rendering.
    +
    +        To do so, you can use AOP embed tag as {?embed fileToEmbed} where fileToEmbed contains the path of file or file itself.
    +
    +        The content of fileToEmbed replaces the tag
    +
    +        Only supported in Word and only supports docx file to embed.
    +    """
    +
    +    def __init__(self, name: str, value: str):
    +        """It takes the tagName and its value as parameter.
    +
    +        Args:
    +            name (str): Name of the tag (ex. fileToEmbed)
    +            value (str): File to embed. Source can be FTP, SFTP, URL or base64 encoded file. (ex. base64encoded string)
    +        """
    +        super().__init__(name, value)
    +
    +    @property
    +    def available_tags(self) -> FrozenSet[str]:
    +        return frozenset({"{?embed fileToEmbed}"})
    +
    +

    Ancestors

    + +

    Inherited members

    + +
    +
    +class ExcelInsert +(name: str, value: str, icon: str = None, fromRow: int = None, fromCol: Union[str, int] = None, fromRowOff: str = None, fromColOff: str = None, toRow: int = None, toCol: Union[str, int] = None, toRowOff: str = None, toColOff: str = None) +
    +
    +

    Inside Excel it is posiible to insert word, powerpoint, excel and pdf file using AOP tag {?insert fileToInsert}. +Options available are: +you can provide dynamic icon and icon position.

    +

    It is possible to provide dynamic icon and position of icon.

    +

    Args

    +
    +
    name : str
    +
    Name of insert tag. Ex(fileToInsert)
    +
    value : str
    +
    File to insert of path to file. (Source can be FTP, SFTP, URL or base64encoded file.)
    +
    icon : str, optional
    +
    Icon that links the file to insert. Once clicked on it, opens the file inserted. If it is not provide default icon is used.
    +
    fromRow : int, optional
    +
    position for top of icon. Defaults to row of the tag.
    +
    fromCol : Union[str,int], optional
    +
    positon for left of icon. Defaults to column of the tag.
    +
    fromRowOff : str, optional
    +
    space after the value of from Row. Defaults to 0.
    +
    fromColOff : str, optional
    +
    space after the value of fromCol. Defaults to 0.
    +
    toRow : int, optional
    +
    position for bottom of icon. Defaults to row of the tag + 3.
    +
    toCol : Union[str,int], optional
    +
    position for right side of icon. Defaults to column of the tag.
    +
    toRowOff : str, optional
    +
    space after toRow value. Defaults to 20px.
    +
    toColOff : str, optional
    +
    space after toCol value. Defaults to 50px.
    +
    +
    + +Expand source code + +
    class ExcelInsert(Element):
    +    """Inside Excel it is posiible to insert word, powerpoint, excel and pdf file using AOP tag {?insert fileToInsert}.
    +        Options available are:  you can provide dynamic icon and icon position.
    +    """
    +
    +    def __init__(self,
    +                 name: str,
    +                 value: str,
    +                 #  isPreview: bool = None,
    +                 icon: str = None,
    +                 fromRow: int = None,
    +                 fromCol: Union[str, int] = None,
    +                 fromRowOff: str = None,
    +                 fromColOff: str = None,
    +                 toRow: int = None,
    +                 toCol: Union[str, int] = None,
    +                 toRowOff: str = None,
    +                 toColOff: str = None
    +                 ):
    +        """It is possible to provide dynamic icon and position of icon.
    +
    +        Args:
    +            name (str):  Name of insert tag. Ex(fileToInsert)
    +            value (str): File to insert of path to file. (Source can be FTP, SFTP, URL or base64encoded file.)
    +            icon (str, optional): Icon that links the file to insert. Once clicked on it, opens the file inserted. If it is not provide default icon is used.
    +            fromRow (int, optional): position for top of icon. Defaults to row of the tag.
    +            fromCol (Union[str,int], optional): positon for left of icon. Defaults to column of the tag.
    +            fromRowOff (str, optional): space after the value of from Row. Defaults to 0.
    +            fromColOff (str, optional): space after the value of fromCol. Defaults to 0.
    +            toRow (int, optional): position for bottom of icon. Defaults to row of the tag + 3.
    +            toCol (Union[str,int], optional): position for right side of icon. Defaults to column of the tag.
    +            toRowOff (str, optional): space after toRow value. Defaults to 20px.
    +            toColOff (str, optional): space after toCol value. Defaults to 50px.
    +        """
    +        super().__init__(name)
    +        self.value: str = value
    +        # self.isPreview: bool = isPreview
    +        self.icon: str = icon
    +        self.fromRow: int = fromRow
    +        self.fromCol: Union[str, int] = fromCol
    +        self.fromRowOff: str = fromRowOff
    +        self.fromColOff: str = fromColOff
    +        self.toRow: int = toRow
    +        self.toCol: Union[str, int] = toCol
    +        self.toRowOff: str = toRowOff
    +        self.toColOff: str = toColOff
    +
    +    @property
    +    def as_dict(self) -> Dict:
    +        result = {
    +            self.name: self.value
    +        }
    +        # if self.isPreview is not None:
    +        #     result[self.name+'_isPreview'] = self.isPreview
    +        if self.icon is not None:
    +            result[self.name+'_icon'] = self.icon
    +        if self.fromRow is not None:
    +            result[self.name+'_fromRow'] = self.fromRow
    +        if self.fromCol is not None:
    +            result[self.name+'_fromCol'] = self.fromCol
    +        if self.fromRowOff is not None:
    +            result[self.name+'_fromRowOff'] = self.fromRowOff
    +        if self.fromColOff is not None:
    +            result[self.name+'_fromColOff'] = self.fromColOff
    +        if self.toRow is not None:
    +            result[self.name+'_toRow'] = self.toRow
    +        if self.toCol is not None:
    +            result[self.name+'_toCol'] = self.toCol
    +        if self.toRowOff is not None:
    +            result[self.name+'_toRowOff'] = self.toRowOff
    +        if self.toColOff is not None:
    +            result[self.name+'_toColOff'] = self.toColOff
    +
    +        return result
    +
    +    @property
    +    def available_tags(self) -> FrozenSet[str]:
    +        return frozenset({"{?insert fileToInsert}"})
    +
    +

    Ancestors

    + +

    Inherited members

    + +
    class FootNote (name: str, value: str) @@ -2816,9 +3381,7 @@

    Args

    @property def as_dict(self) -> Dict: - result = { - self.name: self.url - } + result = {self.name: self.url} if self.text is not None: result[self.name + "_text"] = self.text @@ -2846,30 +3409,32 @@

    Inherited members

    (name: str, value: str)
    -

    Inside Word and PowerPoint documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents.

    +

    Inside Word and PowerPoint and Excel documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents. +Please use ExcelInsert element to insert in excel with more flexibility.

    Args

    name : str
    -
    The name for this property.
    +
    The name for the insert tag.
    value : str
    -
    The value for this property. Note: the general purpose for this value-field is the value as a string, -but this can be of any type, for example a dict.
    -
    +
    Base64 encoded document that needs to be inserted in output docx or pptx.
    + +

    The documnet can be docx, pptx, xlsx, or pdf documents.

    Expand source code
    class Insert(Property):
    -    """Inside Word and PowerPoint documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents."""
    -
    -    """
    -    Args:
    -        name (str): The name for the insert tag.
    -        value (str): Base64 encoded document that needs to be inserted in output docx or pptx.
    -         The documnet can be docx, pptx, xlsx, or pdf documents.
    +    """Inside Word and PowerPoint and Excel documents, the tag {?insert fileToInsert} can be used to insert files like Word, Excel, Powerpoint and PDF documents.
    +    Please use `ExcelInsert` element to insert in excel with more flexibility.
         """
     
         def __init__(self, name: str, value: str):
    +        """
    +        Args:
    +            name (str): The name for the insert tag.
    +            value (str): Base64 encoded document that needs to be inserted in output docx or pptx.
    +            The documnet can be docx, pptx, xlsx, or pdf documents.
    +        """
             super().__init__(name, value)
     
         @property
    @@ -2893,6 +3458,91 @@ 

    Inherited members

    + +
    +

    The class for the link/target tags. +This tags allows you to place a link to a target in the same document. +If the uid is not provided, a new uid will be generated uniquely for every link and target pair.

    +

    Create a new link/target tag pair. +If the uid is not provided, a new uid will be generated uniquely for each link/target pair.

    +

    Args

    +
    +
    name : str
    +
    the name of the link/target tags.
    +
    value : str
    +
    the value of the link/target tags.
    +
    uid_name : str
    +
    the name of the uid of the link/target pair.
    +
    uid_value : str
    +
    the value of the uid of the link/target pair.
    +
    +
    + +Expand source code + +
    class Link(Property):
    +    """The class for the link/target tags.
    +    This tags allows you to place a link to a target in the same document.
    +    If the uid is not provided, a new uid will be generated uniquely for every link and target pair.
    +    """
    +
    +    def __init__(
    +        self,
    +        name: str,
    +        value: str,
    +        uid_name: str = None,
    +        uid_value: str = None,
    +    ):
    +        """Create a new link/target tag pair.
    +        If the uid is not provided, a new uid will be generated uniquely for each link/target pair.
    +
    +        Args:
    +            name (str): the name of the link/target tags.
    +            value (str): the value of the link/target tags.
    +            uid_name (str): the name of the uid of the link/target pair.
    +            uid_value (str): the value of the uid of the link/target pair.
    +        """
    +        super().__init__(name, value)
    +        self.uid_name = uid_name
    +        self.uid_value = uid_value
    +
    +    @property
    +    def available_tags(self) -> FrozenSet[str]:
    +        if self.uid_name and self.uid_value:
    +            return frozenset(
    +                {
    +                    "{link" + self.name + ":" + self.uid_name + "}",
    +                    "{target" + self.name + ":" + self.uid_name + "}",
    +                }
    +            )
    +        return frozenset({"{link" + self.name + "}", "{target" + self.name + "}"})
    +
    +    @property
    +    def as_dict(self) -> Dict:
    +        if self.uid_name and self.uid_value:
    +            return {self.name: self.value, self.uid_name: self.uid_value}
    +        return {self.name: self.value}
    +
    +

    Ancestors

    + +

    Inherited members

    + +
    class MarkdownContent (name: str, value: str) @@ -3034,9 +3684,7 @@

    Args

    @property def as_dict(self) -> Dict: - return { - self.name: self.value - }
    + return {self.name: self.value}

    Ancestors

      @@ -3047,11 +3695,13 @@

      Subclasses

      +
      +class SheetProtection +(name: str, value: str = None, autoFilter: str = None, deleteColumns: bool = None, deleteRows: bool = None, formatCells: bool = None, formatColumns: bool = None, formatRows: bool = None, insertColumns: bool = None, insertHyperlinks: bool = None, insertRows: bool = None, password: str = None, pivotTables: bool = None, selectLockedCells: bool = None, selectUnlockedCells: bool = None, sort: bool = None) +
      +
      +

      Inside Excel documents, this tag can be used to make password protected sheets. This tag has the feature of password along with different other features.

      +

      Note: value is considered password, so try to use only one (either value or passowrd).

      +

      Args

      +
      +
      name : str
      +
      The name for the sheet protection tag.
      +
      value : str
      +
      Value for the tag; this is used as password
      +
      autoFilter : str
      +
      lock auto filter in sheet.
      +
      deleteColumns : bool
      +
      lock delete columns in sheet.
      +
      deleteRows : bool
      +
      lock delete rows in sheet.
      +
      formatCells : bool
      +
      lock format cells.
      +
      formatColumns : bool
      +
      lock format columns.
      +
      formatRows : bool
      +
      lock format rows.
      +
      insertColumns : bool
      +
      lock insert columns.
      +
      insertHyperlinks : bool
      +
      lock insert hyperlinks.
      +
      insertRows : bool
      +
      lock insert rows.
      +
      password : str
      +
      password to lock with.
      +
      pivotTables : bool
      +
      lock pivot tables.
      +
      selectLockedCells : bool
      +
      lock select locked cells.
      +
      selectUnlockedCells : bool
      +
      lock select unlocked cells.
      +
      sort : bool
      +
      lock sort.
      +
      +
      + +Expand source code + +
      class SheetProtection(Element):
      +    """Inside Excel documents, this tag can be used to make password protected sheets. This tag has the feature of password along with different other features.
      +
      +        Note: value is considered password, so try to use only one (either value or passowrd).
      +    """
      +
      +    def __init__(self,
      +                 name: str,
      +                 value: str = None,
      +                 autoFilter: str = None,
      +                 deleteColumns: bool = None,
      +                 deleteRows: bool = None,
      +                 formatCells: bool = None,
      +                 formatColumns: bool = None,
      +                 formatRows: bool = None,
      +                 insertColumns: bool = None,
      +                 insertHyperlinks: bool = None,
      +                 insertRows: bool = None,
      +                 password: str = None,
      +                 pivotTables: bool = None,
      +                 selectLockedCells: bool = None,
      +                 selectUnlockedCells: bool = None,
      +                 sort: bool = None,
      +                 ):
      +        """
      +        Args:
      +            name (str): The name for the sheet protection tag.
      +            value (str): Value for the tag; this is used as password
      +            autoFilter (str): lock auto filter in sheet.
      +            deleteColumns (bool): lock delete columns in sheet.
      +            deleteRows (bool): lock delete rows in sheet.
      +            formatCells (bool): lock format cells.
      +            formatColumns (bool): lock format columns.
      +            formatRows (bool): lock format rows.
      +            insertColumns (bool): lock insert columns.
      +            insertHyperlinks (bool): lock insert hyperlinks.
      +            insertRows (bool): lock insert rows.
      +            password (str): password to lock with.
      +            pivotTables (bool): lock pivot tables.
      +            selectLockedCells (bool): lock select locked cells.
      +            selectUnlockedCells (bool): lock select unlocked cells.
      +            sort (bool): lock sort.
      +        """
      +        super().__init__(name)
      +        self.value = value
      +        self.autoFilter = autoFilter
      +        self.deleteColumns = deleteColumns
      +        self.deleteRows = deleteRows
      +        self.formatCells = formatCells
      +        self.formatColumns = formatColumns
      +        self.formatRows = formatRows
      +        self.insertColumns = insertColumns
      +        self.insertHyperlinks = insertHyperlinks
      +        self.insertRows = insertRows
      +        self.password = password
      +        self.pivotTables = pivotTables
      +        self.selectLockedCells = selectLockedCells
      +        self.selectUnlockedCells = selectUnlockedCells
      +        self.sort = sort
      +
      +    @property
      +    def available_tags(self) -> FrozenSet[str]:
      +        return frozenset({"{protect " + self.name + "}"})
      +
      +    @property
      +    def as_dict(self) -> Dict:
      +        result = {}
      +        if self.value is not None:
      +            result[self.name] = self.value
      +        if self.autoFilter is not None:
      +            result[self.name+'_allow_auto_filter'] = self.autoFilter
      +        if self.deleteColumns is not None:
      +            result[self.name+'_allow_delete_columns'] = self.deleteColumns
      +        if self.deleteRows is not None:
      +            result[self.name+'_allow_delete_rows'] = self.deleteRows
      +        if self.formatCells is not None:
      +            result[self.name+'_allow_format_cells'] = self.formatCells
      +        if self.formatColumns is not None:
      +            result[self.name+'_allow_format_columns'] = self.formatColumns
      +        if self.formatRows is not None:
      +            result[self.name+'_allow_format_rows'] = self.formatRows
      +        if self.insertColumns is not None:
      +            result[self.name+'_allow_insert_columns'] = self.insertColumns
      +        if self.insertHyperlinks is not None:
      +            result[self.name+'_allow_insert_hyperlinks'] = self.insertHyperlinks
      +        if self.insertRows is not None:
      +            result[self.name+'_allow_insert_rows'] = self.insertRows
      +        if self.password is not None:
      +            result[self.name+'_password'] = self.password
      +        if self.pivotTables is not None:
      +            result[self.name+'_allow_pivot_tables'] = self.pivotTables
      +        if self.selectLockedCells is not None:
      +            result[self.name+'_allow_select_locked_cells'] = self.selectLockedCells
      +        if self.selectUnlockedCells is not None:
      +            result[self.name+'_allow_select_unlocked_cells'] = self.selectUnlockedCells
      +        if self.sort is not None:
      +            result[self.name+'_allow_sort'] = self.sort
      +        return result
      +
      +

      Ancestors

      + +

      Inherited members

      + +
      class Span (name: str, value: str, columns: int, rows: int) @@ -3211,7 +4022,7 @@

      Args

      return { self.name: self.value, self.name + "_row_span": self.rows, - self.name + "_col_span": self.columns + self.name + "_col_span": self.columns, }

      Ancestors

      @@ -3266,17 +4077,19 @@

      Args

      Expand source code
      class StyledProperty(Property):
      -    def __init__(self,
      -                 name: str,
      -                 value: str,
      -                 font: str = None,
      -                 font_size: Union[str, int] = None,
      -                 font_color: str = None,
      -                 bold: bool = None,
      -                 italic: bool = None,
      -                 underline: bool = None,
      -                 strikethrough: bool = None,
      -                 highlight_color: str = None):
      +    def __init__(
      +        self,
      +        name: str,
      +        value: str,
      +        font: str = None,
      +        font_size: Union[str, int] = None,
      +        font_color: str = None,
      +        bold: bool = None,
      +        italic: bool = None,
      +        underline: bool = None,
      +        strikethrough: bool = None,
      +        highlight_color: str = None,
      +    ):
               """
               Args:
                   name (str): The name for this property.
      @@ -3306,9 +4119,7 @@ 

      Args

      @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: result[self.name + "_font_family"] = self.font @@ -3368,7 +4179,9 @@

      Args

      Expand source code
      class TableOfContents(Element):
      -    def __init__(self, name: str, title: str = None, depth: int = None, tab_leader: str = None):
      +    def __init__(
      +        self, name: str, title: str = None, depth: int = None, tab_leader: str = None
      +    ):
               """
               Args:
                   name (str): The name for this element.
      @@ -3446,15 +4259,17 @@ 

      Args

      class TextBox(Element):
           """This tag will allow you to insert a text box starting in the cell containing the tag in Excel."""
       
      -    def __init__(self,
      -                 name: str,
      -                 value: str,
      -                 font: str = None,
      -                 font_color: str = None,
      -                 font_size: Union[int, str] = None,
      -                 transparency: Union[int, str] = None,
      -                 width: Union[int, str] = None,
      -                 height: Union[int, str] = None):
      +    def __init__(
      +        self,
      +        name: str,
      +        value: str,
      +        font: str = None,
      +        font_color: str = None,
      +        font_size: Union[int, str] = None,
      +        transparency: Union[int, str] = None,
      +        width: Union[int, str] = None,
      +        height: Union[int, str] = None,
      +    ):
               """
               Args:
                   name (str): The name for this element.
      @@ -3481,23 +4296,196 @@ 

      Args

      @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.font is not None: - result[self.name + '_font'] = self.font + result[self.name + "_font"] = self.font if self.font_color is not None: - result[self.name + '_font_color'] = self.font_color + result[self.name + "_font_color"] = self.font_color if self.font_size is not None: - result[self.name + '_font_size'] = self.font_size + result[self.name + "_font_size"] = self.font_size if self.transparency is not None: - result[self.name + '_transparency'] = self.transparency + result[self.name + "_transparency"] = self.transparency if self.width is not None: - result[self.name + '_width'] = self.width + result[self.name + "_width"] = self.width if self.height is not None: - result[self.name + '_height'] = self.height + result[self.name + "_height"] = self.height + + return result
      + +

      Ancestors

      + +

      Inherited members

      + + +
      +class ValidateCell +(name: str, ignoreBlank: bool = None, allow: str = None, value1: str = None, value2: str = None, inCellDropdown: bool = None, data: str = None, showInputMessage: bool = None, inputTitle: str = None, inputMessage: str = None, showErrorAlert: bool = None, errorStyle: str = None, errorTitle: str = None, errorMessage: str = None) +
      +
      +

      It is possible to insert cell validation in excel using validate tag as {validate validateTag} (validate keyword followed by tagName)

      +

      Available option while using validate cell are ( ignoreBlank, allow, value1, value2, inCellDropdown, data, showInputMessage, inputTitle, inputMessage, showErrorAlert, errorStyle, errorTitle,errorMessage )

      +

      Args

      +
      +
      name : string, optional
      +
      Name of the validate tag. For {validate tagName}, tagName is name for this element.
      +
      ignoreBlank : bool, optional
      +
      Set it to false for not allowing empty values in cell. The value is true by default.
      +
      allow : string, optional
      +
      Type of data used for validation. Available options are (anyValue, whole, decimal, list, date, time, textLength, custom). Please use camelCase to insert value for allow attribute.
      +
      value1 : string, optional
      +
      Value to compare with.
      +
      value2 : string, optional
      +
      Value to compare with.
      +
      Note:
      +
      These two options (_value1, _value2) can be used for any allow/type of validation that require values for comparison, in such case use "_value1" attribute as the first value to be passed and "_value2" attribute as the 2nd value.

      +
      Some allow type of validation require only one value to compare; in such case use "_value1" attribute.

      +
      For ex :
      +
      If allow type of validation is date and you have to check in between two dates.
      +
      Then you could use "_value1" attribute as start date and "_value2" attribute as end date.

      +
      If allow type of validation is whole and you have to check for value less than 100.
      +
      Then you could use "_value1" for that value and do not use "_value2".

      +
      While using time and date as allow type validation, please provide date/time with correct formatting.
      +
      for time: hours:minutes:seconds i.e hours , minutes, seconds separated by colon (:)
      +
      ex : 14:30:00 for 2:30 pm

      +
      for date: month/day/year i.e day, month , year separated by forward slash(/)
      +
      ex : 02/07/2023 for Feb 7 2023.

      +
      for list: you could use normal string with elements separated by comma(,).
      +
      ex : "first, second, third" for list of three elements.
      +
      inCellDropdown : bool, optional
      +
      Set it to false for not showing dropdown button while validation allow type is list. It is true by default for list allow type.
      +
      data : string, optional
      +
      Type of comparison to be done for the cell value. Available values are (lessThanOrEqual, notBetween, equal, notEqual, greaterThan, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual). Default value is "between". Please use camelCase for the value as shown in examples.
      +
      showInputMessage : bool, optional
      +
      Set it to false to hide message shown when the cell to validate is being selected. The value for it is true by default.
      +
      inputTitle : string, optional
      +
      Title of message to be shown when cell to validate is selected.
      +
      inputMessage : string, optional
      +
      Message to be shown when cell to validate is selected.
      +
      showErrorAlert : bool, optional
      +
      Set it to false, if you want to hide error alert once cell validation fails. The value is true by default.
      +
      errorStyle : string, optional
      +
      Type of error style when cell validation fails. The value is stop by default. Available options are(stop,waring, Information).
      +
      errorTitle : string, optional
      +
      Title of error to be shown when cell validation fails.
      +
      errorMessage : string, optional
      +
      Message of error to be shown when cell validation fails.
      +
      +
      + +Expand source code + +
      class ValidateCell(Element):
      +    """
      +    It is possible to insert cell validation in excel using validate tag as {validate validateTag} (validate keyword followed by tagName)
      +    """
      +    def __init__(self,
      +                 name: str,
      +                 ignoreBlank: bool = None,
      +                 allow: str = None,
      +                 value1: str = None,
      +                 value2: str = None,
      +                 inCellDropdown: bool = None,
      +                 data: str = None,
      +                 showInputMessage: bool = None,
      +                 inputTitle: str = None,
      +                 inputMessage: str = None,
      +                 showErrorAlert: bool = None,
      +                 errorStyle: str = None,
      +                 errorTitle: str = None,
      +                 errorMessage: str = None,
      +                 ):
      +        """Available option while using validate cell are ( ignoreBlank, allow, value1, value2, inCellDropdown, data, showInputMessage, inputTitle, inputMessage, showErrorAlert, errorStyle, errorTitle,errorMessage )
      +        
      +        Args:
      +            name (string, optional): Name of the validate tag. For {validate tagName}, tagName is name for this element. 
      +            ignoreBlank (bool, optional): Set it to false for not allowing empty values in cell. The value is true by default.
      +            allow (string, optional): Type of data used for validation. Available options are (anyValue, whole, decimal, list, date, time, textLength, custom). Please use camelCase to insert value for allow attribute.
      +            value1 (string, optional): Value to compare with.
      +            value2 (string, optional): Value to compare with.<br>
      +            <i>Note:
      +                These two options <strong>(_value1, _value2)</strong> can be used for any allow/type of validation that require values for comparison, in such case use <strong>"_value1"</strong> attribute as the first value to be passed and <strong>"_value2"</strong> attribute as the 2nd value.<br><br>
      +                Some allow type of validation require only one value to compare; in such case use <strong>"_value1"</strong> attribute.<br><br>
      +                For ex :<br>
      +                If allow type of validation is date and you have to check in between two dates.<br>
      +                Then you could use <strong>"_value1"</strong> attribute as start date and <strong>"_value2"</strong> attribute as end date.<br><br>
      +                If allow type of validation is whole and you have to check for value less than 100.<br>
      +                Then you could use <strong>"_value1"</strong> for that value and do not use "<strong>_value2".</strong><br><br>
      +                While using time and date as allow type validation, please provide date/time with correct formatting.<br>
      +                for time: <strong>hours:minutes:seconds</strong> i.e hours , minutes, seconds separated by colon (:)<br>
      +                    ex : 14:30:00 for 2:30 pm<br><br>
      +                for date: <strong>month/day/year</strong> i.e day, month , year separated by forward slash(/)<br>
      +                    ex : 02/07/2023 for Feb 7 2023.<br><br>
      +                for list: you could use normal string with elements separated by comma(,).<br>
      +                    ex : "first, second, third" for list of three elements.<br></i>
      +            inCellDropdown (bool, optional): Set it to false for not showing dropdown button while validation allow type is list. It is true by default for list allow type.
      +            data (string, optional): Type of comparison to be done for the cell value. Available values are (lessThanOrEqual, notBetween, equal, notEqual, greaterThan, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual). Default value is "between". Please use camelCase for the value as shown in examples.
      +            showInputMessage (bool, optional): Set it to false to hide message shown when the cell to validate is being selected. The value for it is true by default.
      +            inputTitle (string, optional): Title of message to be shown when cell to validate is selected.
      +            inputMessage (string, optional): Message to be shown when cell to validate is selected.
      +            showErrorAlert (bool, optional): Set it to false, if you want to hide error alert once cell validation fails. The value is true by default.
      +            errorStyle (string, optional): Type of error style when cell validation fails. The value is stop by default. Available options are(stop,waring, Information).
      +            errorTitle (string, optional): Title of error to be shown when cell validation fails.
      +            errorMessage (string, optional): Message of error to be shown when cell validation fails.
      +        """
      +        super().__init__(name)
      +        self.ignoreBlank = ignoreBlank
      +        self.allow = allow
      +        self.value1 = value1
      +        self.value2 = value2
      +        self.inCellDropdown = inCellDropdown
      +        self.data = data
      +        self.showInputMessage = showInputMessage
      +        self.inputTitle = inputTitle
      +        self.inputMessage = inputMessage
      +        self.showErrorAlert = showErrorAlert
      +        self.errorStyle = errorStyle
      +        self.errorTitle = errorTitle
      +        self.errorMessage = errorMessage
       
      +    @property
      +    def available_tags(self) -> FrozenSet[str]:
      +        return frozenset({"{validate " + self.name + "}"})
      +
      +    def as_dict(self) -> Dict:
      +        result = {}
      +        if self.ignoreBlank is not None:
      +            result[self.name + '_ignore_blank'] = self.ignoreBlank
      +        if self.allow is not None:
      +            result[self.name + '_allow'] = self.allow
      +        if self.value1 is not None:
      +            result[self.name + '_value1'] = self.value1
      +        if self.value2 is not None:
      +            result[self.name + '_value2'] = self.value2
      +        if self.inCellDropdown is not None:
      +            result[self.name + '_in_cell_dropdown'] = self.inCellDropdown
      +        if self.data is not None:
      +            result[self.name + '_data'] = self.data
      +        if self.showInputMessage is not None:
      +            result[self.name + '_show_input_message'] = self.showInputMessage
      +        if self.inputTitle is not None:
      +            result[self.name + '_input_title'] = self.inputTitle
      +        if self.inputMessage is not None:
      +            result[self.name + '_input_message'] = self.inputMessage
      +        if self.showErrorAlert is not None:
      +            result[self.name + '_show_error_alert'] = self.showErrorAlert
      +        if self.errorStyle is not None:
      +            result[self.name + '_error_style'] = self.errorStyle
      +        if self.errorTitle is not None:
      +            result[self.name + '_error_title'] = self.errorTitle
      +        if self.errorMessage is not None:
      +            result[self.name + '_error_message'] = self.errorMessage
               return result

      Ancestors

      @@ -3547,15 +4535,17 @@

      Args

      Expand source code
      class Watermark(Property):
      -    def __init__(self,
      -                 name: str,
      -                 text: str,
      -                 color: str = None,
      -                 font: str = None,
      -                 width: Union[int, str] = None,
      -                 height: Union[int, str] = None,
      -                 opacity: float = None,
      -                 rotation: int = None):
      +    def __init__(
      +        self,
      +        name: str,
      +        text: str,
      +        color: str = None,
      +        font: str = None,
      +        width: Union[int, str] = None,
      +        height: Union[int, str] = None,
      +        opacity: float = None,
      +        rotation: int = None,
      +    ):
               """
               Args:
                   name (str): The name for this property.
      @@ -3581,9 +4571,7 @@ 

      Args

      @property def as_dict(self) -> Dict: - result = { - self.name: self.value - } + result = {self.name: self.value} if self.color is not None: result[self.name + "_color"] = self.color @@ -3690,6 +4678,12 @@

      Embed

      + +
    • +

      ExcelInsert

      +
    • +
    • FootNote

    • @@ -3708,6 +4702,9 @@

      Insert

    • +

      Link

      +
    • +
    • MarkdownContent

    • @@ -3723,6 +4720,9 @@

      RightToLeft

    • +

      SheetProtection

      +
    • +
    • Span

    • @@ -3735,6 +4735,9 @@

      TextBox

    • +

      ValidateCell

      +
    • +
    • Watermark

    diff --git a/docs/cloudofficeprint/index.html b/docs/cloudofficeprint/index.html index 095783c..1358f69 100644 --- a/docs/cloudofficeprint/index.html +++ b/docs/cloudofficeprint/index.html @@ -192,6 +192,7 @@

    Further information

    from .printjob import PrintJob from .resource import Resource +from .template import Template from .response import Response # specify what is imported on "from cloudofficeprint import *" @@ -203,7 +204,8 @@

    Further information

    "own_utils", "PrintJob", "Resource", - "Response" + "Template", + "Response", ]
    @@ -238,6 +240,10 @@

    Sub-modules

    Module containing the Response class, which is also exposed at package level.

    +
    cloudofficeprint.template
    +
    +
    +
    @@ -249,7 +255,7 @@

    Classes

    class PrintJob -(data: Union[Element, Mapping[str, Element], RESTSource], server: Server, template: Resource = None, output_config: OutputConfig = <cloudofficeprint.config.output.OutputConfig object>, subtemplates: Dict[str, Resource] = {}, prepend_files: List[Resource] = [], append_files: List[Resource] = [], cop_verbose: bool = False) +(data: Union[Element, Mapping[str, Element], RESTSource], server: Server, template: Union[Template, Resource] = None, output_config: OutputConfig = <cloudofficeprint.config.output.OutputConfig object>, subtemplates: Dict[str, Resource] = {}, prepend_files: List[Resource] = [], append_files: List[Resource] = [], cop_verbose: bool = False)

    A print job for a Cloud Office Print server.

    @@ -261,7 +267,7 @@

    Args

    This is either: An Element (e.g. an ElementCollection); A mapping, containing file names as keys and an Element as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
    server : Server
    Server to be used for this print job.
    -
    template : Resource
    +
    template : Union[Template, Resource]
    Template to use for this print job.
    output_config : OutputConfig, optional
    Output configuration to be used for this print job. Defaults to OutputConfig().
    @@ -285,31 +291,32 @@

    Args

    and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server. """ - def __init__(self, - data: Union[Element, Mapping[str, Element], RESTSource], - server: Server, - template: Resource = None, - output_config: OutputConfig = OutputConfig(), - subtemplates: Dict[str, Resource] = {}, - prepend_files: List[Resource] = [], - append_files: List[Resource] = [], - cop_verbose: bool = False): + def __init__( + self, + data: Union[Element, Mapping[str, Element], RESTSource], + server: Server, + template: Union[Template, Resource] = None, + output_config: OutputConfig = OutputConfig(), + subtemplates: Dict[str, Resource] = {}, + prepend_files: List[Resource] = [], + append_files: List[Resource] = [], + cop_verbose: bool = False, + ): """ Args: data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0". server (Server): Server to be used for this print job. - template (Resource): Template to use for this print job. + template (Union[Template, Resource]): Template to use for this print job. output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`(). subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}. prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to []. append_files (List[Resource], optional): Files to append to the output file. Defaults to []. cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False. """ - self.data: Union[Element, Mapping[str, Element], RESTSource] = data self.server: Server = server self.output_config: OutputConfig = output_config - self.template: Resource = template + self.template: Union[Template, Resource] = template self.subtemplates: Dict[str, Resource] = subtemplates self.prepend_files: List[Resource] = prepend_files self.append_files: List[Resource] = append_files @@ -322,7 +329,18 @@

    Args

    Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response) async def execute_async(self) -> Response: """Async version of `PrintJob.execute` @@ -331,16 +349,22 @@

    Args

    Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) @staticmethod def execute_full_json(json_data: str, server: Server) -> Response: @@ -354,7 +378,14 @@

    Args

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"})) + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response) @staticmethod async def execute_full_json_async(json_data: str, server: Server) -> Response: @@ -368,17 +399,18 @@

    Args

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + return PrintJob._handle_response(response) @staticmethod def _handle_response(res: requests.Response) -> Response: @@ -415,8 +447,8 @@

    Args

    Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -431,43 +463,41 @@

    Args

    # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result
    @@ -507,7 +537,14 @@

    Returns

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"}))
    + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response)
    @@ -543,17 +580,18 @@

    Returns

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) - )
    + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), + ) + return PrintJob._handle_response(response)
    @@ -578,8 +616,8 @@

    Returns

    Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -594,43 +632,41 @@

    Returns

    # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result @@ -684,7 +720,18 @@

    Returns

    Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response)
    @@ -708,16 +755,22 @@

    Returns

    Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) - )
    + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) @@ -728,12 +781,13 @@

    Returns

    The abstract base class for the resources.

    +

    Create a new Resource.

    Args

    data : Union[str, bytes], optional
    -
    the data for this resource. Defaults to None.
    +
    the data for this Resource. Defaults to None.
    filetype : str, optional
    -
    the file type of this resource. Defaults to None.
    +
    the file type of this Resource. Defaults to None.
    @@ -742,70 +796,59 @@

    Args

    class Resource(ABC):
         """The abstract base class for the resources."""
     
    -    def __init__(self, data: Union[str, bytes] = None, filetype: str = None):
    -        """
    +    def __init__(
    +        self,
    +        data: Union[str, bytes] = None,
    +        filetype: str = None,
    +    ):
    +        """Create a new Resource.
    +
             Args:
    -            data (Union[str, bytes], optional): the data for this resource. Defaults to None.
    -            filetype (str, optional): the file type of this resource. Defaults to None.
    +            data (Union[str, bytes], optional): the data for this Resource. Defaults to None.
    +            filetype (str, optional): the file type of this Resource. Defaults to None.
             """
    -        self._data: Union[str, bytes] = data
    +        self.data: Union[str, bytes] = data
             self.filetype: str = filetype
     
         @property
         def mimetype(self) -> str:
    -        """Resource type as a mime type.
    -
    -        Returns:
    -            str: resource type as a mime type
             """
    -        return type_utils.extension_to_mimetype(self.filetype)
    -
    -    @property
    -    def data(self) -> Union[str, bytes]:
    -        """The data contained in this Resource.
    -
             Returns:
    -            Union[str, bytes]: the data contained in this Resource
    +            str: the mime type of the Resource
             """
    -        return self._data
    +        return type_utils.extension_to_mimetype(self.filetype)
     
         @property
         def template_json(self) -> str:
    -        """Get the JSON representation when used as a template.
    -
    +        """
             Returns:
    -            str: JSON representation of this resource as a template
    +            str: the JSON representation of this Resource.
             """
             return json.dumps(self.template_dict)
     
         @property
         @abstractmethod
         def template_dict(self) -> Dict:
    -        """This Resource object as a dict object for use as a template.
    -        This dict and the template JSON representation (`Resource.template_json`) are isomorphic.
    -
    +        """
             Returns:
    -            Dict: dict representation of this resource as a template
    +            Dict: the dictionary representation of this Resource.
             """
             pass
     
         @property
         def secondary_file_json(self) -> str:
    -        """The JSON representation for use as secondary file.
    -
    +        """
             Returns:
    -            str: JSON representation of this resource as a secondary file
    +            str: the JSON representation of this Resource.
             """
             return json.dumps(self.secondary_file_dict)
     
         @property
         @abstractmethod
         def secondary_file_dict(self) -> Dict:
    -        """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate).
    -        This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic.
    -
    +        """
             Returns:
    -            Dict: dict representation of this resource as a secondary file
    +            Dict: the dictionarty representation of this resource as a secondary file (prepend, append, insert, as subtemplate).
             """
             pass
     
    @@ -813,91 +856,91 @@ 

    Args

    """Override the string representation of this class to return the template-style json. Returns: - str: JSON representation of this resource as a template + str: the JSON representation of this resource as a template. """ return self.template_json @staticmethod - def from_base64(base64string: str, filetype: str) -> 'Base64Resource': - """Create a Base64Resource from a base64 string and a file type (extension). + def from_raw(raw_data: bytes, filetype: str) -> "RawResource": + """Create a RawResource from raw file data. Args: - base64string (str): base64 encoded string - filetype (str): file type (extension) + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). Returns: - Base64Resource: the created Resource + RawResource: the created RawResource. """ - return Base64Resource(base64string, filetype) + return RawResource(raw_data, filetype) @staticmethod - def from_raw(raw_data: bytes, filetype: str) -> 'RawResource': - """Create a RawResource from raw file data and a file type (extension). + def from_base64(base64string: str, filetype: str) -> "Base64Resource": + """Create a Base64Resource from a base64 string. Args: - raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object) - filetype (str): file type (extension) + base64string (str): the base64 encoded representation of a file. + filetype (str): the file type (extension). Returns: - RawResource: the created Resource + Base64Resource: the created Base64Resource. """ - return RawResource(raw_data, filetype) + return Base64Resource(base64string, filetype) @staticmethod - def from_local_file(local_path: str) -> 'Base64Resource': + def from_local_file(local_path: str) -> "Base64Resource": """Create a Base64Resource with the contents of a local file. + The filetype is determined by the extension of the file. Throws IOError if it can't read the file. - The filetype is determined by the extension of the file. Args: - local_path (str): path to local file + local_path (str): the path to local file. Returns: - Base64Resource: the created Resource + Base64Resource: the created Base64Resource. """ - base64string: str = file_utils.read_file_as_base64(local_path) - return Base64Resource(base64string, type_utils.path_to_extension(local_path)) + return Base64Resource( + file_utils.read_file_as_base64(local_path), + type_utils.path_to_extension(local_path), + ) @staticmethod - def from_server_path(path: str) -> 'ServerPathResource': + def from_server_path(path: str) -> "ServerPathResource": """Create a ServerPathResource targeting a file on the server. - The filetype is determined by the extension of the file. Args: - path (str): location of target file on the server + path (str): the location of target file on the server. Returns: - ServerPathResource: the created Resource + ServerPathResource: the created ServerPathResource. """ return ServerPathResource(path) @staticmethod - def from_url(url: str, filetype: str) -> 'URLResource': - """Create an Resource targeting the file at url with given filetype (extension). + def from_url(url: str, filetype: str) -> "URLResource": + """Create an URLResource targeting the file at a given URL. Args: - url (str): file url - filetype (str): file type (extension) + url (str): the file URL. + filetype (str): the file type (extension). Returns: - URLResource: the created Resource + URLResource: the created URLResource. """ return URLResource(url, filetype) @staticmethod - def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource': + def from_html(htmlstring: str, landscape: bool = False) -> "HTMLResource": """Create an HTMLResource with html data in plain text. - Landscape is not supported for prepend/append sources, only for template resources. Args: - htmlstring (str): html content - landscape (bool, optional): whether to use the landscape option. Defaults to False. + htmlstring (str): the html content. + landscape (bool, optional): whether or not to use the landscape option. Defaults to False. Returns: - HTMLResource: the created Resource + HTMLResource: the created HTMLResource. """ return HTMLResource(htmlstring, landscape)
    @@ -919,33 +962,33 @@

    Static methods

    def from_base64(base64string: str, filetype: str) ‑> Base64Resource
    -

    Create a Base64Resource from a base64 string and a file type (extension).

    +

    Create a Base64Resource from a base64 string.

    Args

    base64string : str
    -
    base64 encoded string
    +
    the base64 encoded representation of a file.
    filetype : str
    -
    file type (extension)
    +
    the file type (extension).

    Returns

    Base64Resource
    -
    the created Resource
    +
    the created Base64Resource.
    Expand source code
    @staticmethod
    -def from_base64(base64string: str, filetype: str) -> 'Base64Resource':
    -    """Create a Base64Resource from a base64 string and a file type (extension).
    +def from_base64(base64string: str, filetype: str) -> "Base64Resource":
    +    """Create a Base64Resource from a base64 string.
     
         Args:
    -        base64string (str): base64 encoded string
    -        filetype (str): file type (extension)
    +        base64string (str): the base64 encoded representation of a file.
    +        filetype (str): the file type (extension).
     
         Returns:
    -        Base64Resource: the created Resource
    +        Base64Resource: the created Base64Resource.
         """
         return Base64Resource(base64string, filetype)
    @@ -954,36 +997,35 @@

    Returns

    def from_html(htmlstring: str, landscape: bool = False) ‑> HTMLResource
    -

    Create an HTMLResource with html data in plain text.

    -

    Landscape is not supported for prepend/append sources, only for template resources.

    +

    Create an HTMLResource with html data in plain text. +Landscape is not supported for prepend/append sources, only for template resources.

    Args

    htmlstring : str
    -
    html content
    +
    the html content.
    landscape : bool, optional
    -
    whether to use the landscape option. Defaults to False.
    +
    whether or not to use the landscape option. Defaults to False.

    Returns

    HTMLResource
    -
    the created Resource
    +
    the created HTMLResource.
    Expand source code
    @staticmethod
    -def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource':
    +def from_html(htmlstring: str, landscape: bool = False) -> "HTMLResource":
         """Create an HTMLResource with html data in plain text.
    -
         Landscape is not supported for prepend/append sources, only for template resources.
     
         Args:
    -        htmlstring (str): html content
    -        landscape (bool, optional): whether to use the landscape option. Defaults to False.
    +        htmlstring (str): the html content.
    +        landscape (bool, optional): whether or not to use the landscape option. Defaults to False.
     
         Returns:
    -        HTMLResource: the created Resource
    +        HTMLResource: the created HTMLResource.
         """
         return HTMLResource(htmlstring, landscape)
    @@ -992,71 +1034,73 @@

    Returns

    def from_local_file(local_path: str) ‑> Base64Resource
    -

    Create a Base64Resource with the contents of a local file.

    -

    Throws IOError if it can't read the file. +

    Create a Base64Resource with the contents of a local file. The filetype is determined by the extension of the file.

    +

    Throws IOError if it can't read the file.

    Args

    local_path : str
    -
    path to local file
    +
    the path to local file.

    Returns

    Base64Resource
    -
    the created Resource
    +
    the created Base64Resource.
    Expand source code
    @staticmethod
    -def from_local_file(local_path: str) -> 'Base64Resource':
    +def from_local_file(local_path: str) -> "Base64Resource":
         """Create a Base64Resource with the contents of a local file.
    +    The filetype is determined by the extension of the file.
     
         Throws IOError if it can't read the file.
    -    The filetype is determined by the extension of the file.
     
         Args:
    -        local_path (str): path to local file
    +        local_path (str): the path to local file.
     
         Returns:
    -        Base64Resource: the created Resource
    +        Base64Resource: the created Base64Resource.
         """
    -    base64string: str = file_utils.read_file_as_base64(local_path)
    -    return Base64Resource(base64string, type_utils.path_to_extension(local_path))
    + return Base64Resource( + file_utils.read_file_as_base64(local_path), + type_utils.path_to_extension(local_path), + )
    def from_raw(raw_data: bytes, filetype: str) ‑> RawResource
    -

    Create a RawResource from raw file data and a file type (extension).

    +

    Create a RawResource from raw file data.

    Args

    raw_data : bytes
    -
    raw data as a bytes-like object
    +
    the raw data as a bytes-like object.
    filetype : str
    -
    file type (extension)
    +
    the file type (extension).

    Returns

    RawResource
    -
    the created Resource
    +
    the created RawResource.
    Expand source code
    @staticmethod
    -def from_raw(raw_data: bytes, filetype: str) -> 'RawResource':
    -    """Create a RawResource from raw file data and a file type (extension).
    +def from_raw(raw_data: bytes, filetype: str) -> "RawResource":
    +    """Create a RawResource from raw file data.
     
         Args:
    -        raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)
    -        filetype (str): file type (extension)
    +        raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object).
    +        filetype (str): the file type (extension).
     
         Returns:
    -        RawResource: the created Resource
    +        RawResource: the created RawResource.
         """
         return RawResource(raw_data, filetype)
    @@ -1065,33 +1109,32 @@

    Returns

    def from_server_path(path: str) ‑> ServerPathResource
    -

    Create a ServerPathResource targeting a file on the server.

    -

    The filetype is determined by the extension of the file.

    +

    Create a ServerPathResource targeting a file on the server. +The filetype is determined by the extension of the file.

    Args

    path : str
    -
    location of target file on the server
    +
    the location of target file on the server.

    Returns

    ServerPathResource
    -
    the created Resource
    +
    the created ServerPathResource.
    Expand source code
    @staticmethod
    -def from_server_path(path: str) -> 'ServerPathResource':
    +def from_server_path(path: str) -> "ServerPathResource":
         """Create a ServerPathResource targeting a file on the server.
    -
         The filetype is determined by the extension of the file.
     
         Args:
    -        path (str): location of target file on the server
    +        path (str): the location of target file on the server.
     
         Returns:
    -        ServerPathResource: the created Resource
    +        ServerPathResource: the created ServerPathResource.
         """
         return ServerPathResource(path)
    @@ -1100,33 +1143,33 @@

    Returns

    def from_url(url: str, filetype: str) ‑> URLResource
    -

    Create an Resource targeting the file at url with given filetype (extension).

    +

    Create an URLResource targeting the file at a given URL.

    Args

    url : str
    -
    file url
    +
    the file URL.
    filetype : str
    -
    file type (extension)
    +
    the file type (extension).

    Returns

    URLResource
    -
    the created Resource
    +
    the created URLResource.
    Expand source code
    @staticmethod
    -def from_url(url: str, filetype: str) -> 'URLResource':
    -    """Create an Resource targeting the file at url with given filetype (extension).
    +def from_url(url: str, filetype: str) -> "URLResource":
    +    """Create an URLResource targeting the file at a given URL.
     
         Args:
    -        url (str): file url
    -        filetype (str): file type (extension)
    +        url (str): the file URL.
    +        filetype (str): the file type (extension).
     
         Returns:
    -        URLResource: the created Resource
    +        URLResource: the created URLResource.
         """
         return URLResource(url, filetype)
    @@ -1134,35 +1177,12 @@

    Returns

    Instance variables

    -
    var data : Union[str, bytes]
    -
    -

    The data contained in this Resource.

    -

    Returns

    -
    -
    Union[str, bytes]
    -
    the data contained in this Resource
    -
    -
    - -Expand source code - -
    @property
    -def data(self) -> Union[str, bytes]:
    -    """The data contained in this Resource.
    -
    -    Returns:
    -        Union[str, bytes]: the data contained in this Resource
    -    """
    -    return self._data
    -
    -
    var mimetype : str
    -

    Resource type as a mime type.

    -

    Returns

    +

    Returns

    str
    -
    resource type as a mime type
    +
    the mime type of the Resource
    @@ -1170,22 +1190,19 @@

    Returns

    @property
     def mimetype(self) -> str:
    -    """Resource type as a mime type.
    -
    +    """
         Returns:
    -        str: resource type as a mime type
    +        str: the mime type of the Resource
         """
         return type_utils.extension_to_mimetype(self.filetype)
    var secondary_file_dict : Dict
    -

    This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate). -This dict and the "concat file" JSON representation (Resource.secondary_file_json) are isomorphic.

    -

    Returns

    +

    Returns

    Dict
    -
    dict representation of this resource as a secondary file
    +
    the dictionarty representation of this resource as a secondary file (prepend, append, insert, as subtemplate).
    @@ -1194,22 +1211,19 @@

    Returns

    @property
     @abstractmethod
     def secondary_file_dict(self) -> Dict:
    -    """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate).
    -    This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic.
    -
    +    """
         Returns:
    -        Dict: dict representation of this resource as a secondary file
    +        Dict: the dictionarty representation of this resource as a secondary file (prepend, append, insert, as subtemplate).
         """
         pass
    var secondary_file_json : str
    -

    The JSON representation for use as secondary file.

    -

    Returns

    +

    Returns

    str
    -
    JSON representation of this resource as a secondary file
    +
    the JSON representation of this Resource.
    @@ -1217,22 +1231,19 @@

    Returns

    @property
     def secondary_file_json(self) -> str:
    -    """The JSON representation for use as secondary file.
    -
    +    """
         Returns:
    -        str: JSON representation of this resource as a secondary file
    +        str: the JSON representation of this Resource.
         """
         return json.dumps(self.secondary_file_dict)
    var template_dict : Dict
    -

    This Resource object as a dict object for use as a template. -This dict and the template JSON representation (Resource.template_json) are isomorphic.

    -

    Returns

    +

    Returns

    Dict
    -
    dict representation of this resource as a template
    +
    the dictionary representation of this Resource.
    @@ -1241,22 +1252,19 @@

    Returns

    @property
     @abstractmethod
     def template_dict(self) -> Dict:
    -    """This Resource object as a dict object for use as a template.
    -    This dict and the template JSON representation (`Resource.template_json`) are isomorphic.
    -
    +    """
         Returns:
    -        Dict: dict representation of this resource as a template
    +        Dict: the dictionary representation of this Resource.
         """
         pass
    var template_json : str
    -

    Get the JSON representation when used as a template.

    -

    Returns

    +

    Returns

    str
    -
    JSON representation of this resource as a template
    +
    the JSON representation of this Resource.
    @@ -1264,10 +1272,9 @@

    Returns

    @property
     def template_json(self) -> str:
    -    """Get the JSON representation when used as a template.
    -
    +    """
         Returns:
    -        str: JSON representation of this resource as a template
    +        str: the JSON representation of this Resource.
         """
         return json.dumps(self.template_dict)
    @@ -1530,6 +1537,804 @@

    Returns

    +
    +class Template +(resource: Resource, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) +
    +
    +

    The Template class

    +

    Create a new Template.

    +

    Args

    +
    +
    resource : Resource
    +
    the resource of this template.
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +
    + +Expand source code + +
    class Template:
    +    """The Template class"""
    +
    +    def __init__(
    +        self,
    +        resource: Resource,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ):
    +        """Create a new Template.
    +
    +        Args:
    +            resource (Resource): the resource of this template.
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +        """
    +        self.resource = resource
    +        self.start_delimiter = start_delimiter
    +        self.end_delimiter = end_delimiter
    +        self.should_hash = should_hash
    +        self.template_hash = template_hash
    +
    +    def update_hash(self, template_hash: str):
    +        """Update the Template to store a hash.
    +        On the next request to the server, the file data will not be sent, only the hash of the template.
    +
    +        Args:
    +            template_hash (str): the hash of the template.
    +        """
    +        self.template_hash = template_hash
    +        self.should_hash = False
    +
    +    def reset_hash(self, should_hash: bool = True):
    +        """Reset the stored hash of the template.
    +
    +        Args:
    +            should_hash (bool, optional): whether the template should be hashed on the server. Defaults to True.
    +        """
    +        self.template_hash = None
    +        self.should_hash = should_hash
    +
    +    @property
    +    def mimetype(self) -> str:
    +        """
    +        Returns:
    +            str: the mime type of the Resource
    +        """
    +        return self.resource.mimetype
    +
    +    @property
    +    def template_json(self) -> str:
    +        """
    +        Returns:
    +            str: the JSON representation of this Resource.
    +        """
    +        return json.dumps(self.template_dict)
    +
    +    @property
    +    def template_dict(self) -> Dict:
    +        """
    +        Returns:
    +            Dict: the dictionary representation of this Resource.
    +        """
    +        if self.template_hash and not self.should_hash:
    +            dict = {
    +                "template_type": self.resource.filetype,
    +                "template_hash": self.template_hash,
    +            }
    +            if self.start_delimiter:
    +                dict["start_delimiter"] = self.start_delimiter
    +            if self.end_delimiter:
    +                dict["end_delimiter"] = self.end_delimiter
    +            return dict
    +        dict = self.resource.template_dict
    +        if self.start_delimiter:
    +            dict["start_delimiter"] = self.start_delimiter
    +        if self.end_delimiter:
    +            dict["end_delimiter"] = self.end_delimiter
    +        if self.should_hash:
    +            dict["should_hash"] = self.should_hash
    +        if self.template_hash:
    +            dict["template_hash"] = self.template_hash
    +        return dict
    +
    +    def __str__(self) -> str:
    +        """Override the string representation of this class to return the template-style json.
    +
    +        Returns:
    +            str: the JSON representation of this resource as a template.
    +        """
    +        return self.template_json
    +
    +    @staticmethod
    +    def from_raw(
    +        raw_data: bytes,
    +        filetype: str,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a RawResource from raw file data.
    +
    +        Args:
    +            raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object).
    +            filetype (str): the file type (extension).
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_raw(raw_data, filetype),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +    @staticmethod
    +    def from_base64(
    +        base64string: str,
    +        filetype: str,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a Base64Resource from a base64 string.
    +
    +        Args:
    +            base64string (str): the base64 encoded representation of a file.
    +            filetype (str): the file type (extension).
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_base64(base64string, filetype),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +    @staticmethod
    +    def from_local_file(
    +        local_path: str,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a Base64Resource with the contents of a local file.
    +        The filetype is determined by the extension of the file.
    +
    +        Throws IOError if it can't read the file.
    +
    +        Args:
    +            local_path (str): the path to local file.
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_local_file(local_path),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +    @staticmethod
    +    def from_server_path(
    +        path: str,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a ServerPathResource targeting a file on the server.
    +        The filetype is determined by the extension of the file.
    +
    +        Args:
    +            path (str): the location of target file on the server.
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_server_path(path),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +    @staticmethod
    +    def from_url(
    +        url: str,
    +        filetype: str,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a URLResource targeting the file at a given url.
    +
    +        Args:
    +            url (str): the file URL.
    +            filetype (str): the file type (extension).
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_url(url, filetype),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +    @staticmethod
    +    def from_html(
    +        htmlstring: str,
    +        landscape: bool = False,
    +        start_delimiter: str = None,
    +        end_delimiter: str = None,
    +        should_hash: bool = None,
    +        template_hash: str = None,
    +    ) -> "Template":
    +        """Create a Template with a HTMLResource with html data in plain text.
    +
    +        Args:
    +            htmlstring (str): the html content.
    +            landscape (bool, optional): whether or not to use the landscape option. Defaults to False.
    +            start_delimiter (str, optional): the starting delimiter used in the template.
    +            end_delimiter (str, optional): the starting delimiter used in the template.
    +            should_hash (bool, optional): whether the template should be hashed on the server.
    +            template_hash (str, optional): the hash of the template.
    +
    +        Returns:
    +            Template: the created Template.
    +        """
    +        return Template(
    +            Resource.from_html(htmlstring, landscape),
    +            start_delimiter,
    +            end_delimiter,
    +            should_hash,
    +            template_hash,
    +        )
    +
    +

    Static methods

    +
    +
    +def from_base64(base64string: str, filetype: str, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a Base64Resource from a base64 string.

    +

    Args

    +
    +
    base64string : str
    +
    the base64 encoded representation of a file.
    +
    filetype : str
    +
    the file type (extension).
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_base64(
    +    base64string: str,
    +    filetype: str,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a Base64Resource from a base64 string.
    +
    +    Args:
    +        base64string (str): the base64 encoded representation of a file.
    +        filetype (str): the file type (extension).
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_base64(base64string, filetype),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +def from_html(htmlstring: str, landscape: bool = False, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a HTMLResource with html data in plain text.

    +

    Args

    +
    +
    htmlstring : str
    +
    the html content.
    +
    landscape : bool, optional
    +
    whether or not to use the landscape option. Defaults to False.
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_html(
    +    htmlstring: str,
    +    landscape: bool = False,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a HTMLResource with html data in plain text.
    +
    +    Args:
    +        htmlstring (str): the html content.
    +        landscape (bool, optional): whether or not to use the landscape option. Defaults to False.
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_html(htmlstring, landscape),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +def from_local_file(local_path: str, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a Base64Resource with the contents of a local file. +The filetype is determined by the extension of the file.

    +

    Throws IOError if it can't read the file.

    +

    Args

    +
    +
    local_path : str
    +
    the path to local file.
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_local_file(
    +    local_path: str,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a Base64Resource with the contents of a local file.
    +    The filetype is determined by the extension of the file.
    +
    +    Throws IOError if it can't read the file.
    +
    +    Args:
    +        local_path (str): the path to local file.
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_local_file(local_path),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +def from_raw(raw_data: bytes, filetype: str, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a RawResource from raw file data.

    +

    Args

    +
    +
    raw_data : bytes
    +
    the raw data as a bytes-like object.
    +
    filetype : str
    +
    the file type (extension).
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_raw(
    +    raw_data: bytes,
    +    filetype: str,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a RawResource from raw file data.
    +
    +    Args:
    +        raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object).
    +        filetype (str): the file type (extension).
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_raw(raw_data, filetype),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +def from_server_path(path: str, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a ServerPathResource targeting a file on the server. +The filetype is determined by the extension of the file.

    +

    Args

    +
    +
    path : str
    +
    the location of target file on the server.
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_server_path(
    +    path: str,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a ServerPathResource targeting a file on the server.
    +    The filetype is determined by the extension of the file.
    +
    +    Args:
    +        path (str): the location of target file on the server.
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_server_path(path),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +def from_url(url: str, filetype: str, start_delimiter: str = None, end_delimiter: str = None, should_hash: bool = None, template_hash: str = None) ‑> Template +
    +
    +

    Create a Template with a URLResource targeting the file at a given url.

    +

    Args

    +
    +
    url : str
    +
    the file URL.
    +
    filetype : str
    +
    the file type (extension).
    +
    start_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    end_delimiter : str, optional
    +
    the starting delimiter used in the template.
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server.
    +
    template_hash : str, optional
    +
    the hash of the template.
    +
    +

    Returns

    +
    +
    Template
    +
    the created Template.
    +
    +
    + +Expand source code + +
    @staticmethod
    +def from_url(
    +    url: str,
    +    filetype: str,
    +    start_delimiter: str = None,
    +    end_delimiter: str = None,
    +    should_hash: bool = None,
    +    template_hash: str = None,
    +) -> "Template":
    +    """Create a Template with a URLResource targeting the file at a given url.
    +
    +    Args:
    +        url (str): the file URL.
    +        filetype (str): the file type (extension).
    +        start_delimiter (str, optional): the starting delimiter used in the template.
    +        end_delimiter (str, optional): the starting delimiter used in the template.
    +        should_hash (bool, optional): whether the template should be hashed on the server.
    +        template_hash (str, optional): the hash of the template.
    +
    +    Returns:
    +        Template: the created Template.
    +    """
    +    return Template(
    +        Resource.from_url(url, filetype),
    +        start_delimiter,
    +        end_delimiter,
    +        should_hash,
    +        template_hash,
    +    )
    +
    +
    +
    +

    Instance variables

    +
    +
    var mimetype : str
    +
    +

    Returns

    +
    +
    str
    +
    the mime type of the Resource
    +
    +
    + +Expand source code + +
    @property
    +def mimetype(self) -> str:
    +    """
    +    Returns:
    +        str: the mime type of the Resource
    +    """
    +    return self.resource.mimetype
    +
    +
    +
    var template_dict : Dict
    +
    +

    Returns

    +
    +
    Dict
    +
    the dictionary representation of this Resource.
    +
    +
    + +Expand source code + +
    @property
    +def template_dict(self) -> Dict:
    +    """
    +    Returns:
    +        Dict: the dictionary representation of this Resource.
    +    """
    +    if self.template_hash and not self.should_hash:
    +        dict = {
    +            "template_type": self.resource.filetype,
    +            "template_hash": self.template_hash,
    +        }
    +        if self.start_delimiter:
    +            dict["start_delimiter"] = self.start_delimiter
    +        if self.end_delimiter:
    +            dict["end_delimiter"] = self.end_delimiter
    +        return dict
    +    dict = self.resource.template_dict
    +    if self.start_delimiter:
    +        dict["start_delimiter"] = self.start_delimiter
    +    if self.end_delimiter:
    +        dict["end_delimiter"] = self.end_delimiter
    +    if self.should_hash:
    +        dict["should_hash"] = self.should_hash
    +    if self.template_hash:
    +        dict["template_hash"] = self.template_hash
    +    return dict
    +
    +
    +
    var template_json : str
    +
    +

    Returns

    +
    +
    str
    +
    the JSON representation of this Resource.
    +
    +
    + +Expand source code + +
    @property
    +def template_json(self) -> str:
    +    """
    +    Returns:
    +        str: the JSON representation of this Resource.
    +    """
    +    return json.dumps(self.template_dict)
    +
    +
    +
    +

    Methods

    +
    +
    +def reset_hash(self, should_hash: bool = True) +
    +
    +

    Reset the stored hash of the template.

    +

    Args

    +
    +
    should_hash : bool, optional
    +
    whether the template should be hashed on the server. Defaults to True.
    +
    +
    + +Expand source code + +
    def reset_hash(self, should_hash: bool = True):
    +    """Reset the stored hash of the template.
    +
    +    Args:
    +        should_hash (bool, optional): whether the template should be hashed on the server. Defaults to True.
    +    """
    +    self.template_hash = None
    +    self.should_hash = should_hash
    +
    +
    +
    +def update_hash(self, template_hash: str) +
    +
    +

    Update the Template to store a hash. +On the next request to the server, the file data will not be sent, only the hash of the template.

    +

    Args

    +
    +
    template_hash : str
    +
    the hash of the template.
    +
    +
    + +Expand source code + +
    def update_hash(self, template_hash: str):
    +    """Update the Template to store a hash.
    +    On the next request to the server, the file data will not be sent, only the hash of the template.
    +
    +    Args:
    +        template_hash (str): the hash of the template.
    +    """
    +    self.template_hash = template_hash
    +    self.should_hash = False
    +
    +
    +
    +
    @@ -1559,6 +2364,7 @@

    Index

  • cloudofficeprint.printjob
  • cloudofficeprint.resource
  • cloudofficeprint.response
  • +
  • cloudofficeprint.template
  • Classes

    @@ -1577,7 +2383,6 @@

    Resource

  • +
  • +

    Template

    + +
  • diff --git a/docs/cloudofficeprint/own_utils.html b/docs/cloudofficeprint/own_utils.html index 052c4ac..91be9a5 100644 --- a/docs/cloudofficeprint/own_utils.html +++ b/docs/cloudofficeprint/own_utils.html @@ -3,64 +3,65 @@ - + cloudofficeprint.own_utils API documentation - - - - - - - -
    -
    +

    cloudofficeprint.own_utils

    Helper functions.

    -
    - View Source -
    """
    -Helper functions.
    -"""
    +                        
    +
    +                        
     
    -from .file_utils import *
    -from .type_utils import *
    -
    +
    1"""
    +2Helper functions.
    +3"""
    +4
    +5from .file_utils import *
    +6from .type_utils import *
    +
    -
    @@ -164,12 +165,26 @@

    } let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}(${doc.parameters.join(", ")})`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; + if (doc.bases) + heading += `(${doc.bases})`; + heading += `:`; + break; + case "variable": + heading = `${doc.fullname}`; + if (doc.annotation) + heading += `${doc.annotation}`; + if (doc.default_value) + heading += `${doc.default_value}`; break; default: heading = `${doc.fullname}`; @@ -177,7 +192,7 @@

    } html += `
    - ${heading} + ${heading}
    ${doc.doc}
    `; diff --git a/docs/cloudofficeprint/printjob.html b/docs/cloudofficeprint/printjob.html index 3b5b710..df72757 100644 --- a/docs/cloudofficeprint/printjob.html +++ b/docs/cloudofficeprint/printjob.html @@ -31,20 +31,21 @@

    Module cloudofficeprint.printjob

    Module containing the PrintJob class, which is also exposed at package level. """ -from cloudofficeprint.elements.rest_source import RESTSource import requests import asyncio import json -from .config import OutputConfig, Server -from .exceptions import COPError -from .response import Response -from .resource import Resource -from .elements import Element, ElementCollection + from typing import Union, List, Dict, Mapping from functools import partial -import sys from pprint import pprint +from .config import OutputConfig, Server +from .elements import Element, RESTSource +from .exceptions import COPError +from .resource import Resource +from .template import Template +from .response import Response + STATIC_OPTS = { "tool": "python", # "version": "18.2", # optional: version of Cloud Office Print JSON format @@ -59,31 +60,32 @@

    Module cloudofficeprint.printjob

    and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server. """ - def __init__(self, - data: Union[Element, Mapping[str, Element], RESTSource], - server: Server, - template: Resource = None, - output_config: OutputConfig = OutputConfig(), - subtemplates: Dict[str, Resource] = {}, - prepend_files: List[Resource] = [], - append_files: List[Resource] = [], - cop_verbose: bool = False): + def __init__( + self, + data: Union[Element, Mapping[str, Element], RESTSource], + server: Server, + template: Union[Template, Resource] = None, + output_config: OutputConfig = OutputConfig(), + subtemplates: Dict[str, Resource] = {}, + prepend_files: List[Resource] = [], + append_files: List[Resource] = [], + cop_verbose: bool = False, + ): """ Args: data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0". server (Server): Server to be used for this print job. - template (Resource): Template to use for this print job. + template (Union[Template, Resource]): Template to use for this print job. output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`(). subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}. prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to []. append_files (List[Resource], optional): Files to append to the output file. Defaults to []. cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False. """ - self.data: Union[Element, Mapping[str, Element], RESTSource] = data self.server: Server = server self.output_config: OutputConfig = output_config - self.template: Resource = template + self.template: Union[Template, Resource] = template self.subtemplates: Dict[str, Resource] = subtemplates self.prepend_files: List[Resource] = prepend_files self.append_files: List[Resource] = append_files @@ -96,7 +98,18 @@

    Module cloudofficeprint.printjob

    Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response) async def execute_async(self) -> Response: """Async version of `PrintJob.execute` @@ -105,16 +118,22 @@

    Module cloudofficeprint.printjob

    Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) @staticmethod def execute_full_json(json_data: str, server: Server) -> Response: @@ -128,7 +147,14 @@

    Module cloudofficeprint.printjob

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"})) + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response) @staticmethod async def execute_full_json_async(json_data: str, server: Server) -> Response: @@ -142,17 +168,18 @@

    Module cloudofficeprint.printjob

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + return PrintJob._handle_response(response) @staticmethod def _handle_response(res: requests.Response) -> Response: @@ -189,8 +216,8 @@

    Module cloudofficeprint.printjob

    Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -205,43 +232,41 @@

    Module cloudofficeprint.printjob

    # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result
    @@ -258,7 +283,7 @@

    Classes

    class PrintJob -(data: Union[Element, Mapping[str, Element], RESTSource], server: Server, template: Resource = None, output_config: OutputConfig = <cloudofficeprint.config.output.OutputConfig object>, subtemplates: Dict[str, Resource] = {}, prepend_files: List[Resource] = [], append_files: List[Resource] = [], cop_verbose: bool = False) +(data: Union[Element, Mapping[str, Element], RESTSource], server: Server, template: Union[Template, Resource] = None, output_config: OutputConfig = <cloudofficeprint.config.output.OutputConfig object>, subtemplates: Dict[str, Resource] = {}, prepend_files: List[Resource] = [], append_files: List[Resource] = [], cop_verbose: bool = False)

    A print job for a Cloud Office Print server.

    @@ -270,7 +295,7 @@

    Args

    This is either: An Element (e.g. an ElementCollection); A mapping, containing file names as keys and an Element as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0".
    server : Server
    Server to be used for this print job.
    -
    template : Resource
    +
    template : Union[Template, Resource]
    Template to use for this print job.
    output_config : OutputConfig, optional
    Output configuration to be used for this print job. Defaults to OutputConfig().
    @@ -294,31 +319,32 @@

    Args

    and the `PrintJob.execute` method to combine all these and send a request to the Cloud Office Print server. """ - def __init__(self, - data: Union[Element, Mapping[str, Element], RESTSource], - server: Server, - template: Resource = None, - output_config: OutputConfig = OutputConfig(), - subtemplates: Dict[str, Resource] = {}, - prepend_files: List[Resource] = [], - append_files: List[Resource] = [], - cop_verbose: bool = False): + def __init__( + self, + data: Union[Element, Mapping[str, Element], RESTSource], + server: Server, + template: Union[Template, Resource] = None, + output_config: OutputConfig = OutputConfig(), + subtemplates: Dict[str, Resource] = {}, + prepend_files: List[Resource] = [], + append_files: List[Resource] = [], + cop_verbose: bool = False, + ): """ Args: data (Union[Element, Mapping[str, Element], RESTSource]): This is either: An `Element` (e.g. an `ElementCollection`); A mapping, containing file names as keys and an `Element` as data. Multiple files will be produced from the different datas, the result is a zip file containing them. In the first case, no output file name is specified and the server will name it "file0". server (Server): Server to be used for this print job. - template (Resource): Template to use for this print job. + template (Union[Template, Resource]): Template to use for this print job. output_config (OutputConfig, optional): Output configuration to be used for this print job. Defaults to `OutputConfig`(). subtemplates (Dict[str, Resource], optional): Subtemplates for this print job, accessible (in docx) through `{?include subtemplate_dict_key}`. Defaults to {}. prepend_files (List[Resource], optional): Files to prepend to the output file. Defaults to []. append_files (List[Resource], optional): Files to append to the output file. Defaults to []. cop_verbose (bool, optional): Whether or not verbose mode should be activated. Defaults to False. """ - self.data: Union[Element, Mapping[str, Element], RESTSource] = data self.server: Server = server self.output_config: OutputConfig = output_config - self.template: Resource = template + self.template: Union[Template, Resource] = template self.subtemplates: Dict[str, Resource] = subtemplates self.prepend_files: List[Resource] = prepend_files self.append_files: List[Resource] = append_files @@ -331,7 +357,18 @@

    Args

    Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response) async def execute_async(self) -> Response: """Async version of `PrintJob.execute` @@ -340,16 +377,22 @@

    Args

    Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) @staticmethod def execute_full_json(json_data: str, server: Server) -> Response: @@ -363,7 +406,14 @@

    Args

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"})) + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response) @staticmethod async def execute_full_json_async(json_data: str, server: Server) -> Response: @@ -377,17 +427,18 @@

    Args

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), ) + return PrintJob._handle_response(response) @staticmethod def _handle_response(res: requests.Response) -> Response: @@ -424,8 +475,8 @@

    Args

    Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -440,43 +491,41 @@

    Args

    # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result
    @@ -516,7 +565,14 @@

    Returns

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response(requests.post(server.url, proxies=server.config.proxies if server.config is not None else None, data=json_data, headers={"Content-type": "application/json"})) + proxy = server.config.proxies if server.config else None + response = requests.post( + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + return PrintJob._handle_response(response)
    @@ -552,17 +608,18 @@

    Returns

    Response: `Response`-object """ server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - server.url, - proxies=server.config.proxies if server.config is not None else None, - data=json_data, - headers={"Content-type": "application/json"} - ) - ) - )
    + proxy = server.config.proxies if server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + server.url, + data=json_data, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), + ) + return PrintJob._handle_response(response)
    @@ -587,8 +644,8 @@

    Returns

    Returns: Dict: dict representation of this print job """ - result = dict( - STATIC_OPTS) # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + # Copy of STATIC_OPTS! Otherwise everything we add to 'result' will also be added to 'STATIC_OPTS' + result = dict(STATIC_OPTS) # server config goes in the upper level if self.server.config: result.update(self.server.config.as_dict) @@ -603,43 +660,41 @@

    Returns

    # If output_type is not specified, set this to the template filetype # If no template found: default docx - if 'output_type' not in self.output_config.as_dict.keys(): + if "output_type" not in self.output_config.as_dict.keys(): if self.template: - result['output']['output_type'] = result['template']['template_type'] + result["output"]["output_type"] = result["template"]["template_type"] else: - result['output']['output_type'] = 'docx' + result["output"]["output_type"] = "docx" if isinstance(self.data, Mapping): - result["files"] = [{ - "filename": name, - "data": data.as_dict - } for name, data in self.data.items()] + result["files"] = [ + {"filename": name, "data": data.as_dict} + for name, data in self.data.items() + ] elif isinstance(self.data, RESTSource): - result['files'] = [self.data.as_dict] + result["files"] = [self.data.as_dict] else: result["files"] = [{"data": self.data.as_dict}] if len(self.prepend_files) > 0: result["prepend_files"] = [ - res.secondary_file_dict for res in self.prepend_files + file.secondary_file_dict for file in self.prepend_files ] if len(self.append_files) > 0: result["append_files"] = [ - res.secondary_file_dict for res in self.append_files + file.secondary_file_dict for file in self.append_files ] if len(self.subtemplates) > 0: - templates_list = [] - for name, res in self.subtemplates.items(): - to_add = res.secondary_file_dict - to_add["name"] = name - templates_list.append(to_add) - result["templates"] = templates_list + result["templates"] = [ + {**file.secondary_file_dict, "name": name} + for name, file in self.subtemplates.items() + ] # If verbose mode is activated, print the result to the terminal if self.cop_verbose: - print('The JSON data that is sent to the Cloud Office Print server:\n') + print("The JSON data that is sent to the Cloud Office Print server:\n") pprint(result) return result @@ -693,7 +748,18 @@

    Returns

    Response: `Response`-object """ self.server._raise_if_unreachable() - return self._handle_response(requests.post(self.server.url, proxies=self.server.config.proxies if self.server.config is not None else None, json=self.as_dict, headers={"Content-type": "application/json"})) + proxy = self.server.config.proxies if self.server.config else None + response = requests.post( + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return self._handle_response(response)
    @@ -717,16 +783,22 @@

    Returns

    Response: `Response`-object """ self.server._raise_if_unreachable() - return PrintJob._handle_response( - await asyncio.get_event_loop().run_in_executor( - None, partial( - requests.post, - self.server.url, - proxies=self.server.config.proxies if self.server.config is not None else None, - json=self.as_dict - ) - ) - )
    + proxy = self.server.config.proxies if self.server.config else None + response = await asyncio.get_event_loop().run_in_executor( + None, + partial( + requests.post, + self.server.url, + json=self.as_dict, + proxies=proxy, + headers={"Content-type": "application/json"}, + ), + ) + if type(self.template) is Template and self.template.should_hash: + template_hash = response.headers["Template-Hash"] + if template_hash: + self.template.update_hash(template_hash) + return PrintJob._handle_response(response) diff --git a/docs/cloudofficeprint/resource.html b/docs/cloudofficeprint/resource.html index 2ebd09e..5e3e659 100644 --- a/docs/cloudofficeprint/resource.html +++ b/docs/cloudofficeprint/resource.html @@ -46,77 +46,67 @@

    Resource creation

    import json from typing import Dict, Union -from .own_utils import type_utils, file_utils from abc import abstractmethod, ABC +from .own_utils import type_utils, file_utils + class Resource(ABC): """The abstract base class for the resources.""" - def __init__(self, data: Union[str, bytes] = None, filetype: str = None): - """ + def __init__( + self, + data: Union[str, bytes] = None, + filetype: str = None, + ): + """Create a new Resource. + Args: - data (Union[str, bytes], optional): the data for this resource. Defaults to None. - filetype (str, optional): the file type of this resource. Defaults to None. + data (Union[str, bytes], optional): the data for this Resource. Defaults to None. + filetype (str, optional): the file type of this Resource. Defaults to None. """ - self._data: Union[str, bytes] = data + self.data: Union[str, bytes] = data self.filetype: str = filetype @property def mimetype(self) -> str: - """Resource type as a mime type. - - Returns: - str: resource type as a mime type """ - return type_utils.extension_to_mimetype(self.filetype) - - @property - def data(self) -> Union[str, bytes]: - """The data contained in this Resource. - Returns: - Union[str, bytes]: the data contained in this Resource + str: the mime type of the Resource """ - return self._data + return type_utils.extension_to_mimetype(self.filetype) @property def template_json(self) -> str: - """Get the JSON representation when used as a template. - + """ Returns: - str: JSON representation of this resource as a template + str: the JSON representation of this Resource. """ return json.dumps(self.template_dict) @property @abstractmethod def template_dict(self) -> Dict: - """This Resource object as a dict object for use as a template. - This dict and the template JSON representation (`Resource.template_json`) are isomorphic. - + """ Returns: - Dict: dict representation of this resource as a template + Dict: the dictionary representation of this Resource. """ pass @property def secondary_file_json(self) -> str: - """The JSON representation for use as secondary file. - + """ Returns: - str: JSON representation of this resource as a secondary file + str: the JSON representation of this Resource. """ return json.dumps(self.secondary_file_dict) @property @abstractmethod def secondary_file_dict(self) -> Dict: - """This Resource object as a dict object for use as a secondary file (prepend, append, insert, as subtemplate). - This dict and the "concat file" JSON representation (`Resource.secondary_file_json`) are isomorphic. - + """ Returns: - Dict: dict representation of this resource as a secondary file + Dict: the dictionarty representation of this resource as a secondary file (prepend, append, insert, as subtemplate). """ pass @@ -124,91 +114,91 @@

    Resource creation

    """Override the string representation of this class to return the template-style json. Returns: - str: JSON representation of this resource as a template + str: the JSON representation of this resource as a template. """ return self.template_json @staticmethod - def from_base64(base64string: str, filetype: str) -> 'Base64Resource': - """Create a Base64Resource from a base64 string and a file type (extension). + def from_raw(raw_data: bytes, filetype: str) -> "RawResource": + """Create a RawResource from raw file data. Args: - base64string (str): base64 encoded string - filetype (str): file type (extension) + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). Returns: - Base64Resource: the created Resource + RawResource: the created RawResource. """ - return Base64Resource(base64string, filetype) + return RawResource(raw_data, filetype) @staticmethod - def from_raw(raw_data: bytes, filetype: str) -> 'RawResource': - """Create a RawResource from raw file data and a file type (extension). + def from_base64(base64string: str, filetype: str) -> "Base64Resource": + """Create a Base64Resource from a base64 string. Args: - raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object) - filetype (str): file type (extension) + base64string (str): the base64 encoded representation of a file. + filetype (str): the file type (extension). Returns: - RawResource: the created Resource + Base64Resource: the created Base64Resource. """ - return RawResource(raw_data, filetype) + return Base64Resource(base64string, filetype) @staticmethod - def from_local_file(local_path: str) -> 'Base64Resource': + def from_local_file(local_path: str) -> "Base64Resource": """Create a Base64Resource with the contents of a local file. + The filetype is determined by the extension of the file. Throws IOError if it can't read the file. - The filetype is determined by the extension of the file. Args: - local_path (str): path to local file + local_path (str): the path to local file. Returns: - Base64Resource: the created Resource + Base64Resource: the created Base64Resource. """ - base64string: str = file_utils.read_file_as_base64(local_path) - return Base64Resource(base64string, type_utils.path_to_extension(local_path)) + return Base64Resource( + file_utils.read_file_as_base64(local_path), + type_utils.path_to_extension(local_path), + ) @staticmethod - def from_server_path(path: str) -> 'ServerPathResource': + def from_server_path(path: str) -> "ServerPathResource": """Create a ServerPathResource targeting a file on the server. - The filetype is determined by the extension of the file. Args: - path (str): location of target file on the server + path (str): the location of target file on the server. Returns: - ServerPathResource: the created Resource + ServerPathResource: the created ServerPathResource. """ return ServerPathResource(path) @staticmethod - def from_url(url: str, filetype: str) -> 'URLResource': - """Create an Resource targeting the file at url with given filetype (extension). + def from_url(url: str, filetype: str) -> "URLResource": + """Create an URLResource targeting the file at a given URL. Args: - url (str): file url - filetype (str): file type (extension) + url (str): the file URL. + filetype (str): the file type (extension). Returns: - URLResource: the created Resource + URLResource: the created URLResource. """ return URLResource(url, filetype) @staticmethod - def from_html(htmlstring: str, landscape: bool = False) -> 'HTMLResource': + def from_html(htmlstring: str, landscape: bool = False) -> "HTMLResource": """Create an HTMLResource with html data in plain text. - Landscape is not supported for prepend/append sources, only for template resources. Args: - htmlstring (str): html content - landscape (bool, optional): whether to use the landscape option. Defaults to False. + htmlstring (str): the html content. + landscape (bool, optional): whether or not to use the landscape option. Defaults to False. Returns: - HTMLResource: the created Resource + HTMLResource: the created HTMLResource. """ return HTMLResource(htmlstring, landscape) @@ -217,62 +207,83 @@

    Resource creation

    """A `Resource` containing raw binary data.""" def __init__(self, raw_data: bytes, filetype: str): - """ + """Create a new RawResource. + Args: - raw_data (bytes): raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object) - filetype (str): file type (extension) + raw_data (bytes): the raw data as a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object). + filetype (str): the file type (extension). """ super().__init__(raw_data, filetype) @property def base64(self) -> str: - """Base64 representation of the raw data in `RawResource.data`. - + """ Returns: - str: base64 representation of the raw data in `RawResource.data` + str: the base64 representation of the raw data in `RawResource.data`. """ return file_utils.raw_to_base64(self.data) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "file": self.base64 + "file": self.base64, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "base64", - "file_content": self.base64 + "file_content": self.base64, } class Base64Resource(Resource): """A `Resource` containing base64 data.""" - def __init__(self, base64string: str, filetype: str): - """ + def __init__( + self, + base64string: str, + filetype: str, + ): + """Create a new Base64Resource. + Args: - base64string (str): base64 encoded file - filetype (str): file type (extension) + base64string (str): the base64 encoded data. + filetype (str): the file type (extension). """ super().__init__(base64string, filetype) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "file": self.data + "file": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "base64", - "file_content": self.data + "file_content": self.data, } @@ -280,25 +291,34 @@

    Resource creation

    """A `Resource` targeting a file on the server.""" def __init__(self, server_path: str): - """ + """Create a new ServerPathResource. + Args: - server_path (str): path on the server to target + server_path (str): the path on the server to target. """ super().__init__(server_path, type_utils.path_to_extension(server_path)) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "filename": self.data + "filename": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "filename": self.data + "filename": self.data, } @@ -306,37 +326,51 @@

    Resource creation

    """A `Resource` targeting a file at a URL.""" def __init__(self, url: str, filetype: str): - """ + """Create a new URLResource. + Args: - url (str): URL location of the file - filetype (str): file type (extension) + url (str): the URL location of the file. + filetype (str): the file type (extension). """ super().__init__(url, filetype) @property def template_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "template_type": self.filetype, - "url": self.data + "url": self.data, } @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "file_url": self.data + "file_url": self.data, } class HTMLResource(Resource): """A Resource containing HTML data in plain text.""" - def __init__(self, htmlstring: str, landscape: bool = False): - """ + def __init__( + self, + htmlstring: str, + landscape: bool = False, + ): + """Create a new HTMLResource. + Args: - htmlstring (str): HTML input in plain text - landscape (bool, optional): Whether the HTML should be rendered as landscape-oriented page. Defaults to False. + htmlstring (str): the HTML input in plain text. + landscape (bool, optional): whether the HTML should be rendered as landscape-oriented page. Defaults to False. """ super().__init__(htmlstring, "html") self.landscape: bool = landscape @@ -349,28 +383,32 @@

    Resource creation

    Orientation is not supported for prepend/append sources, only for template resources. Returns: - str: orientation + str: the orientation. """ return None if not self.landscape else "landscape" @property def template_dict(self) -> Dict: - result = { + """ + Returns: + str: the JSON representation of this resource. + """ + return { "template_type": self.filetype, - "html_template_content": self.data + "html_template_content": self.data, + "orientation": self.orientation, } - if self.orientation is not None: - result["orientation"] = self.orientation - - return result - @property def secondary_file_dict(self) -> Dict: + """ + Returns: + str: the JSON representation of this resource. + """ return { "mime_type": self.mimetype, "file_source": "file", - "file_content": self.data + "file_content": self.data, } @@ -389,12 +427,13 @@

    Classes

    A Resource containing base64 data.

    +

    Create a new Base64Resource.

    Args

    base64string : str
    -
    base64 encoded file
    +
    the base64 encoded data.
    filetype : str
    -
    file type (extension)
    +
    the file type (extension).
    @@ -403,27 +442,40 @@

    Args

    class Base64Resource(Resource):
         """A `Resource` containing base64 data."""
     
    -    def __init__(self, base64string: str, filetype: str):
    -        """
    +    def __init__(
    +        self,
    +        base64string: str,
    +        filetype: str,
    +    ):
    +        """Create a new Base64Resource.
    +
             Args:
    -            base64string (str): base64 encoded file
    -            filetype (str): file type (extension)
    +            base64string (str): the base64 encoded data.
    +            filetype (str): the file type (extension).
             """
             super().__init__(base64string, filetype)
     
         @property
         def template_dict(self) -> Dict:
    +        """
    +        Returns:
    +            str: the JSON representation of this resource.
    +        """
             return {
                 "template_type": self.filetype,
    -            "file": self.data
    +            "file": self.data,
             }
     
         @property
         def secondary_file_dict(self) -> Dict:
    +        """
    +        Returns:
    +            str: the JSON representation of this resource.
    +        """
             return {
                 "mime_type": self.mimetype,
                 "file_source": "base64",
    -            "file_content": self.data
    +            "file_content": self.data,
             }

    Ancestors

    @@ -431,11 +483,60 @@

    Ancestors

  • Resource
  • abc.ABC
  • +

    Instance variables

    +
    +
    var secondary_file_dict : Dict
    +
    +

    Returns

    +
    +
    str
    +
    the JSON representation of this resource.
    +
    +
    + +Expand source code + +
    @property
    +def secondary_file_dict(self) -> Dict:
    +    """
    +    Returns:
    +        str: the JSON representation of this resource.
    +    """
    +    return {
    +        "mime_type": self.mimetype,
    +        "file_source": "base64",
    +        "file_content": self.data,
    +    }
    +
    +
    +
    var template_dict : Dict
    +
    +

    Returns

    +
    +
    str
    +
    the JSON representation of this resource.
    +
    +
    + +Expand source code + +
    @property
    +def template_dict(self) -> Dict:
    +    """
    +    Returns:
    +        str: the JSON representation of this resource.
    +    """
    +    return {
    +        "template_type": self.filetype,
    +        "file": self.data,
    +    }
    +
    +
    +

    Inherited members