diff --git a/dev/docs/source/page_setup.rst b/dev/docs/source/page_setup.rst index 5ccd4499d..eb4070d7c 100644 --- a/dev/docs/source/page_setup.rst +++ b/dev/docs/source/page_setup.rst @@ -571,8 +571,8 @@ worksheet.print_area() :type last_row: integer :type last_col: integer - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: ReturnCode.XW_NO_ERROR: Success. + :returns: None : Max print area selected This method is used to specify the area of the worksheet that will be printed. diff --git a/dev/docs/source/workbook.rst b/dev/docs/source/workbook.rst index 0773a82b1..e739b4fc5 100644 --- a/dev/docs/source/workbook.rst +++ b/dev/docs/source/workbook.rst @@ -531,6 +531,10 @@ workbook.set_custom_property() :type name: string :type property_type: string + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. + The ``set_custom_property()`` method can be used to set one or more custom document properties not covered by the standard properties in the @@ -578,6 +582,10 @@ workbook.define_name() :param string name: The defined name. :param string formula: The cell or range that the defined name refers to. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. + This method is used to defined a name that can be used to represent a value, a single cell or a range of cells in a workbook. These are sometimes referred to as a "Named Range". diff --git a/dev/docs/source/worksheet.rst b/dev/docs/source/worksheet.rst index f16fe3d06..bdb83ff2a 100644 --- a/dev/docs/source/worksheet.rst +++ b/dev/docs/source/worksheet.rst @@ -41,9 +41,21 @@ worksheet.write() :param \*args: The additional args that are passed to the sub methods such as number, string and cell_format. - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: Other values from the called write methods. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String truncated to 32k + characters. + :returns: XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY: Formula can't be None or + empty. + :returns: XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED: URL longer than Excel + limit of characters. + :returns: XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED: Exceeds Excel limit + of 65,530 urls per + worksheet. + :returns: XW_ERROR_2_CONSECUTIVE_FORMATS: 2 consecutive formats used. + :returns: XW_ERROR_EMPTY_STRING_USED: Empty string used. + :returns: XW_ERROR_INSUFFICIENT_PARAMETERS: Insufficient parameters. Excel makes a distinction between data types such as strings, numbers, blanks, formulas and hyperlinks. To simplify the process of writing data to an @@ -214,9 +226,11 @@ worksheet.write_string() :type string: string :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: String truncated to 32k characters. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String truncated to 32k + characters. The ``write_string()`` method writes a string to the cell specified by ``row`` and ``column``:: @@ -270,8 +284,9 @@ worksheet.write_number() :type number: int or float :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``write_number()`` method writes numeric types to the cell specified by ``row`` and ``column``:: @@ -315,8 +330,11 @@ worksheet.write_formula() :type formula: string :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY: Formula can't be None or + empty. The ``write_formula()`` method writes a formula or function to the cell specified by ``row`` and ``column``:: @@ -392,8 +410,9 @@ worksheet.write_array_formula() :type formula: string :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``write_array_formula()`` method writes an array formula to a cell range. In Excel an array formula is a formula that performs a calculation on a set of @@ -458,8 +477,9 @@ worksheet.write_dynamic_array_formula() :type formula: string :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``write_dynamic_array_formula()`` method writes an dynamic array formula to a cell range. Dynamic array formulas are explained in detail in :ref:`formula_dynamic_arrays`. @@ -497,8 +517,9 @@ worksheet.write_blank() :type col: int :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. Write a blank cell specified by ``row`` and ``column``:: @@ -541,8 +562,9 @@ worksheet.write_boolean() :type boolean: bool :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``write_boolean()`` method writes a boolean value to the cell specified by ``row`` and ``column``:: @@ -575,8 +597,9 @@ worksheet.write_datetime() :type datetime: :mod:`datetime` :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``write_datetime()`` method can be used to write a date or time to the cell specified by ``row`` and ``column``:: @@ -632,11 +655,16 @@ worksheet.write_url() :type tip: string :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: String longer than 32k characters. - :returns: -3: Url longer than Excel limit of 2079 characters. - :returns: -4: Exceeds Excel limit of 65,530 urls per worksheet. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String longer than 32767 + characters. + :returns: XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED: URL longer than Excel + limit of characters. + :returns: XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED: Exceeds Excel limit + of 65,530 urls per + worksheet. The ``write_url()`` method is used to write a hyperlink in a worksheet cell. The url is comprised of two elements: the displayed string and the @@ -768,12 +796,14 @@ worksheet.write_rich_string() :type string_parts: list :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: String longer than 32k characters. - :returns: -3: 2 consecutive formats used. - :returns: -4: Empty string used. - :returns: -5: Insufficient parameters. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String truncated to 32k + characters. + :returns: XW_ERROR_2_CONSECUTIVE_FORMATS: 2 consecutive formats used. + :returns: XW_ERROR_EMPTY_STRING_USED: Empty string used. + :returns: XW_ERROR_INSUFFICIENT_PARAMETERS: Insufficient parameters. The ``write_rich_string()`` method is used to write strings with multiple formats. For example to write the string "This is **bold** and this is @@ -887,7 +917,7 @@ worksheet.write_row() :type col: int :type cell_format: :ref:`Format ` - :returns: 0: Success. + :returns: XW_NO_ERROR: Success. :returns: Other: Error return value of the ``write()`` method. The ``write_row()`` method can be used to write a list of data in one go. This @@ -930,7 +960,7 @@ worksheet.write_column() :type col: int :type cell_format: :ref:`Format ` - :returns: 0: Success. + :returns: XW_NO_ERROR: Success. :returns: Other: Error return value of the ``write()`` method. The ``write_column()`` method can be used to write a list of data in one go. @@ -971,8 +1001,9 @@ worksheet.set_row() :type cell_format: :ref:`Format ` :param dict options: Optional row parameters: hidden, level, collapsed. - :returns: 0: Success. - :returns: -1: Row is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``set_row()`` method is used to change the default properties of a row. The most common use for this method is to change the height of a row:: @@ -1061,8 +1092,9 @@ worksheet.set_row_pixels() :type cell_format: :ref:`Format ` :param dict options: Optional row parameters: hidden, level, collapsed. - :returns: 0: Success. - :returns: -1: Row is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``set_row_pixels()`` method is identical to :func:`set_row` except that the height can be set in pixels instead of Excel character units:: @@ -1087,8 +1119,9 @@ worksheet.set_column() :type cell_format: :ref:`Format ` :param dict options: Optional parameters: hidden, level, collapsed. - :returns: 0: Success. - :returns: -1: Column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``set_column()`` method can be used to change the default properties of a single column or a range of columns:: @@ -1215,8 +1248,9 @@ worksheet.set_column_pixels() :type cell_format: :ref:`Format ` :param dict options: Optional parameters: hidden, level, collapsed. - :returns: 0: Success. - :returns: -1: Column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``set_column_pixels()`` method is identical to :func:`set_column` except that the width can be set in pixels instead of Excel character units:: @@ -1245,8 +1279,10 @@ worksheet.insert_image() :type image: string :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_IMAGE_FILE_NOT_FOUND: Image file not found. This method can be used to insert a image into a worksheet. The image can be in PNG, JPEG, GIF, BMP, WMF or EMF format (see the notes about BMP and EMF below):: @@ -1385,8 +1421,10 @@ worksheet.insert_chart() :type col: int :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: None: The chart (or the combined one) was already inserted. This method can be used to insert a chart into a worksheet. A chart object is created via the Workbook :func:`add_chart()` method where the chart type is @@ -1491,8 +1529,9 @@ worksheet.insert_textbox() :type text: string :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. This method can be used to insert a textbox into a worksheet:: @@ -1560,8 +1599,9 @@ worksheet.insert_button() :type col: int :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. The ``insert_button()`` method can be used to insert an Excel form button into a worksheet. @@ -1641,9 +1681,11 @@ worksheet.data_validation() :type last_col: int :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: Incorrect parameter or option. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. The ``data_validation()`` method is used to construct an Excel data validation or to limit the user input to a dropdown list of values:: @@ -1702,9 +1744,11 @@ worksheet.conditional_format() :type last_col: int :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: Incorrect parameter or option. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. The ``conditional_format()`` method is used to add formatting to a cell or range of cells based on user defined criteria:: @@ -1765,10 +1809,13 @@ worksheet.add_table() :type last_col: int :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: Incorrect parameter or option. - :returns: -3: Not supported in ``constant_memory`` mode. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. + :returns: XW_ERROR_NOT_SUPPORTED_COSTANT_MEMORY: Not supported in + constant_memory mode. The ``add_table()`` method is used to group a range of cells into an Excel Table:: @@ -1804,9 +1851,11 @@ worksheet.add_sparkline() :param int col: The cell column (zero indexed). :param dict options: Sparkline formatting options. - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: Incorrect parameter or option. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. Sparklines are small charts that fit in a single cell and are used to show trends in data. @@ -1854,9 +1903,11 @@ worksheet.write_comment() :type comment: string :type options: dict - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. - :returns: -2: String longer than 32k characters. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + :returns: XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String truncated to 32k + characters. The ``write_comment()`` method is used to add a comment to a cell. A comment is indicated in Excel by a small red triangle in the upper right-hand corner of @@ -2082,9 +2133,11 @@ worksheet.merge_range() :type last_col: int :type cell_format: :ref:`Format ` - :returns: 0: Success. - :returns: -1: Row or column is out of worksheet bounds. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. :returns: Other: Error return value of the called ``write()`` method. + :returns: None: A single cell was (tried to be) merged The ``merge_range()`` method allows cells to be merged together so that they act as a single area. @@ -2468,6 +2521,9 @@ worksheet.set_background() :param str filename: The image file (or byte stream). :param bool is_byte_stream: The file is a stream of bytes. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_IMAGE_FILE_NOT_FOUND: Image file not found + The ``set_background()`` method can be used to set the background image for the worksheet:: @@ -2605,6 +2661,10 @@ worksheet.unprotect_range() :param string cell_range: The cell or cell range to unprotect. :param string range_name: An name for the range. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. + The ``unprotect_range()`` method is used to unprotect ranges in a protected worksheet. It can be used to set a single range or multiple ranges:: @@ -2720,8 +2780,9 @@ worksheet.ignore_errors() Ignore various Excel errors/warnings in a worksheet for user defined ranges. - :returns: 0: Success. - :returns: -1: Incorrect parameter or option. + :returns: XW_NO_ERROR: Success. + :returns: XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. The ``ignore_errors()`` method can be used to ignore various worksheet cell errors/warnings. For example the following code writes a string that looks diff --git a/examples/inheritance2.py b/examples/inheritance2.py index 4a2498fe7..8c386f4df 100644 --- a/examples/inheritance2.py +++ b/examples/inheritance2.py @@ -17,6 +17,7 @@ from xlsxwriter.workbook import Workbook from xlsxwriter.worksheet import Worksheet from xlsxwriter.worksheet import convert_cell_args +from xlsxwriter.returncodes import ReturnCode def excel_string_width(str): @@ -48,7 +49,7 @@ def write_string(self, row, col, string, cell_format=None): # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Set the min width for the cell. In some cases this might be the # default width of 8.43. In this case we use 0 and adjust for all diff --git a/xlsxwriter/returncodes.py b/xlsxwriter/returncodes.py new file mode 100644 index 000000000..8507d69cf --- /dev/null +++ b/xlsxwriter/returncodes.py @@ -0,0 +1,59 @@ +############################################################################### +# +# ReturnCodes - A class for XlsxWriter return codes. +# +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2013-2022, John McNamara, jmcnamara@cpan.org +# + +from enum import Enum + + +class ReturnCode(str, Enum): + """Return codes enumeration for XlsxWriter functions + + These values can be converted to string in different ways: + - direct assignment: mystr = retcode + - through format function: mystr = "Value {0}".format(retcode) + - through f-string: mystr = f'Value {retcode}' + + Conversion through str() function will result in the internal Enum + representation, i.e. str(ReturnCode.XW_NO_ERROR) will return + "ReturnCode.XW_NO_ERROR" + """ + + # Note: the following are not tuples, but strings on multiple lines + # This is required to be compliant to E501 + + ########################################################################### + # + # Values from libxlsxwriter library + # + ########################################################################### + + XW_NO_ERROR = "No error" + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED = ("String exceeds Excel's limit of " + "32,767 characters") + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE = ("Worksheet row or column index " + "out of range") + XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED = ("Maximum hyperlink length " + "(2079) exceeded") + XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED = ("Maximum number of " + "worksheet URLs (65530) " + "exceeded") + + ########################################################################### + # + # Values added only for this library + # + ########################################################################### + + XW_ERROR_VBA_FILE_NOT_FOUND = "VBA project binary file not found" + XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY = "Formula can't be None or empty" + XW_ERROR_2_CONSECUTIVE_FORMATS = "2 consecutive formats used" + XW_ERROR_EMPTY_STRING_USED = "Empty string used" + XW_ERROR_INSUFFICIENT_PARAMETERS = "Insufficient parameters" + XW_ERROR_IMAGE_FILE_NOT_FOUND = "Image file not found" + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION = "Incorrect parameter or option" + XW_ERROR_NOT_SUPPORTED_COSTANT_MEMORY = ("Not supported in " + "constant_memory mode") diff --git a/xlsxwriter/test/core/test_returncodes.py b/xlsxwriter/test/core/test_returncodes.py new file mode 100644 index 000000000..fb142f397 --- /dev/null +++ b/xlsxwriter/test/core/test_returncodes.py @@ -0,0 +1,1142 @@ +############################################################################### +# +# Tests for XlsxWriter. +# +# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c), 2013-2022, John McNamara, jmcnamara@cpan.org +# + +import unittest +from io import StringIO +import datetime +import itertools +import warnings +import tempfile +import os +from ...returncodes import ReturnCode +from ...workbook import Workbook + + +class TestReturnCodes(unittest.TestCase): + """ + Test return codes from the different modules. + + """ + + _string_conversion_expected_result = "No error" + _testing_image_path = 'xlsxwriter/test/comparison/images/logo.png' + _testing_vba_bin_path = 'xlsxwriter/test/comparison/xlsx_files/vbaProject02.bin' + + def setUp(self): + self.fh = StringIO() + self.workbook = Workbook() + self.workbook._set_filehandle(self.fh) + + self.worksheet = self.workbook.add_worksheet() + + self.max_col = self.worksheet.xls_colmax + self.max_row = self.worksheet.xls_rowmax + + self.bold = self.workbook.add_format({'bold': True}) + + ########################################################################### + # + # Helper functions + # + ########################################################################### + + def _test_no_error(self, func): + """Test the no error return code of func + + Args: + func: Function with prototype def func() + """ + + exp = ReturnCode.XW_NO_ERROR + + got = func() + self.assertEqual(got, exp) + + def _test_cell_out_of_range(self, func, valid_r=0, valid_c=0): + """Test the out of range return code of func + + This tests only a single cell value + + Args: + func: Function with prototype def func(r,c), where r is the row + index and c the column index + valid_r (int, optional): Value for the valid row to be used in the + test when necessary. Defaults to 0. + other_c (int, optional): Value for the valid column to be used in + the test when necessary. Defaults to 0. + """ + + exp = ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE + + got = func(valid_r, self.max_col) + self.assertEqual(got, exp) + + got = func(self.max_row, valid_c) + self.assertEqual(got, exp) + + got = func(self.max_row, self.max_col) + self.assertEqual(got, exp) + + def _test_range_out_of_range(self, func, valid_r=0, valid_c=0): + """Test the out of range return code of func + + This can be used for functions accepting a range of cells. + + Args: + func: Function with prototype def func(r1,c1,r2,c2):, where (r1,c1) + is the starting cell and (r2,c2) is the ending cell of the + range to test + valid_r (int, optional): Value for the valid row to be used in the + test when necessary. Defaults to 0. + other_c (int, optional): Value for the valid column to be used in + the test when necessary. Defaults to 0. + """ + + exp = ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE + + # There are 16 cases; let's write them programmatically + for shall_be_valid in itertools.product([True, False], repeat=4): + # Skip all valid cases + if all(shall_be_valid): + continue + + r1 = valid_r if shall_be_valid[0] else self.max_row + c1 = valid_c if shall_be_valid[1] else self.max_col + r2 = valid_r if shall_be_valid[2] else self.max_row + c2 = valid_c if shall_be_valid[3] else self.max_col + + got = func(r1, c1, r2, c2) + self.assertEqual(got, exp) + + def _test_max_string_length(self, func): + """Test the max string length return code of func + + Args: + func: Function with prototype def func(s), where s is the string to + be written + """ + + long_string = " " * (self.worksheet.xls_strmax + 1) + exp = ReturnCode.XW_ERROR_MAX_STRING_LENGTH_EXCEEDED + got = func(long_string) + + self.assertEqual(got, exp) + + ########################################################################### + # + # Test string conversion + # + ########################################################################### + + def test_returncode_to_string_implicit(self): + """Test converting a return code to string. + + Implicit conversion (using StrEnum underlying str representation) + """ + retcode = ReturnCode.XW_NO_ERROR + got = retcode + + self.assertEqual(got, self._string_conversion_expected_result) + + def test_returncode_to_string_format(self): + """Test converting a return code to string. + + Using str.format() conversion + """ + retcode = ReturnCode.XW_NO_ERROR + got = "{0}".format(retcode) + + self.assertEqual(got, self._string_conversion_expected_result) + + def test_returncode_to_string_fstring(self): + """Test converting a return code to string. + + Using f-string conversion + """ + retcode = ReturnCode.XW_NO_ERROR + got = f'{retcode}' + + self.assertEqual(got, self._string_conversion_expected_result) + + ########################################################################### + # + # Test workbook object return codes + # + ########################################################################### + + def test_workbook_add_vba_project_no_error(self): + """worksheet.add_vba_project() returns XW_NO_ERROR + """ + + def func(): + return self.workbook.add_vba_project(self._testing_vba_bin_path) + self._test_no_error(func) + + def test_workbook_add_vba_project_vba_file_not_found(self): + """worksheet.add_vba_project() returns VBA_FILE_NOT_FOUND + """ + + exp = ReturnCode.XW_ERROR_VBA_FILE_NOT_FOUND + + # Ignore the warning "VBA project binary file not found" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + got = self.workbook.add_vba_project('unknown.bin') + self.assertEqual(got, exp) + + def test_workbook_set_custom_property_no_error(self): + """worksheet.set_custom_property() returns XW_NO_ERROR + """ + + def func(): + return self.workbook.set_custom_property('test', True) + self._test_no_error(func) + + def test_worksheet_set_custom_property_incorrect_parameter_or_option(self): + """worksheet.set_custom_property() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) The name and value parameters must be non-None + got = self.workbook.set_custom_property(None, None) + self.assertEqual(got, exp) + + def test_workbook_define_name_no_error(self): + """worksheet.define_name() returns XW_NO_ERROR + """ + + def func(): + return self.workbook.define_name('Test', 'A1') + self._test_no_error(func) + + def test_worksheet_define_name_parameter_or_option(self): + """worksheet.define_name() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Unknown sheet name + got = self.workbook.define_name('NoSheet!Test', 'A1') + self.assertEqual(got, exp) + + # 02) Invalid Excel characters + got = self.workbook.define_name('.', 'A1') + self.assertEqual(got, exp) + + # 03) Name looks like a cell name + got = self.workbook.define_name('A0', 'A1') + self.assertEqual(got, exp) + + # 04) Invalid name like a RC cell ref + got = self.workbook.define_name('R1C1', 'A1') + self.assertEqual(got, exp) + + ########################################################################### + # + # Test worksheet object return codes + # + ########################################################################### + + def test_worksheet_write_string_no_error(self): + """worksheet.write_string() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_string(0, 0, '') + self._test_no_error(func) + + def test_worksheet_write_string_out_of_range(self): + """worksheet.write_string() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r, c): + return self.worksheet.write_string(r, c, '') + self._test_cell_out_of_range(func) + + def test_worksheet_write_string_max_string_length(self): + """worksheet.write_string() returns MAX_STRING_LENGTH_EXCEEDED + """ + + def func(s): + return self.worksheet.write_string(0, 0, s) + self._test_max_string_length(func) + + def test_worksheet_write_number_no_error(self): + """worksheet.write_number() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_number(0, 0, 0) + self._test_no_error(func) + + def test_worksheet_write_number_out_of_range(self): + """worksheet.write_number() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r, c): + return self.worksheet.write_number(r, c, 3) + self._test_cell_out_of_range(func) + + def test_worksheet_write_blank_no_error(self): + """worksheet.write_blank() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_blank(0, 0, None, 'format') + self._test_no_error(func) + + # Test that without format even out of range is not returned + def func(): + return self.worksheet.write_blank(0, self.max_col, None) + self._test_no_error(func) + + def test_worksheet_write_blank_out_of_range(self): + """worksheet.write_blank() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r, c): + return self.worksheet.write_blank(r, c, None, 'format') + self._test_cell_out_of_range(func) + + def test_worksheet_write_formula_no_error(self): + """worksheet.write_formula() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_formula(0, 0, '=B2') + self._test_no_error(func) + + def test_worksheet_write_formula_out_of_range(self): + """worksheet.write_formula() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r, c): + return self.worksheet.write_formula(r, c, '=B2') + self._test_cell_out_of_range(func) + + def test_worksheet_write_formula_none_or_empty(self): + """worksheet.write_formula() returns XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY + """ + + # Ignore the warning "Formula can't be None or empty" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY + + got = self.worksheet.write_formula(0, 0, None) + self.assertEqual(got, exp) + + got = self.worksheet.write_formula(0, 0, '') + self.assertEqual(got, exp) + + def test_worksheet_write_array_formula_no_error(self): + """worksheet.write_array_formula() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_array_formula(0, 0, 0, 0, '') + self._test_no_error(func) + + def test_worksheet_write_array_formula_out_of_range(self): + """worksheet.write_array_formula() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r1, c1, r2, c2): + return self.worksheet.write_array_formula(r1, c1, r2, c2, '') + self._test_range_out_of_range(func) + + def test_worksheet_write_dynamic_array_formula_no_error(self): + """worksheet.write_dynamic_array_formula() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_dynamic_array_formula(0, 0, 0, 0, '') + self._test_no_error(func) + + def test_worksheet_write_dynamic_array_formula_out_of_range(self): + """worksheet.write_dynamic_array_formula() returns INDEX_OUT_OF_RANGE + """ + + def func(r1, c1, r2, c2): + return self.worksheet.write_dynamic_array_formula(r1, c1, r2, c2, '') + self._test_range_out_of_range(func) + + def test_worksheet_write_datetime_no_error(self): + """worksheet.write_datetime() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_datetime(0, 0, datetime.datetime.now()) + self._test_no_error(func) + + def test_worksheet_write_datetime_out_of_range(self): + """worksheet.write_datetime() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.write_datetime(r, c, datetime.datetime.now()) + self._test_cell_out_of_range(func) + + def test_worksheet_write_boolean_no_error(self): + """worksheet.write_boolean() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_boolean(0, 0, True) + self._test_no_error(func) + + def test_worksheet_write_boolean_out_of_range(self): + """worksheet.write_boolean() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.write_boolean(r, c, True) + self._test_cell_out_of_range(func) + + def test_worksheet_write_url_no_error(self): + """worksheet.write_url() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_url(0, 0, '') + self._test_no_error(func) + + def test_worksheet_write_url_out_of_range(self): + """worksheet.write_url() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.write_url(r, c, '') + self._test_cell_out_of_range(func) + + def test_worksheet_write_url_max_string_length(self): + """worksheet.write_url() returns MAX_STRING_LENGTH_EXCEEDED + """ + + # Ignore the warning "Ignoring URL since it exceeds Excel's string limit" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + def func(s): + return self.worksheet.write_url(0, 0, s) + self._test_max_string_length(func) + + def test_worksheet_write_url_max_url_length(self): + """worksheet.write_url() returns MAX_URL_LENGTH_EXCEEDED + """ + + # Ignore the warning "Ignoring URL '%s' with link or location/anchor" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + # Set a forced value for URL length + forced_url_length = 500 + + self.worksheet.max_url_length = forced_url_length + + long_url = " " * (forced_url_length + 1) + + exp = ReturnCode.XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED + got = self.worksheet.write_url(0, 0, long_url) + + self.assertEqual(got, exp) + + def test_worksheet_write_url_max_number_urls(self): + """worksheet.write_url() returns MAX_NUMBER_URLS_EXCEEDED + """ + + # Ignore the warning "Ignoring URL '%s' with link or location/anchor" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + # Set a forced value for URL length + max_urls_per_worksheet = 65530 + + exp = ReturnCode.XW_NO_ERROR + for _ in range(max_urls_per_worksheet): + got = self.worksheet.write_url(0, 0, '') + self.assertEqual(got, exp) + + exp = ReturnCode.XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED + got = self.worksheet.write_url(0, 0, '') + + self.assertEqual(got, exp) + + def test_worksheet_write_rich_string_no_error(self): + """worksheet.write_rich_string() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_rich_string(0, 0, 'a', self.bold, 'b') + self._test_no_error(func) + + def test_worksheet_write_rich_string_out_of_range(self): + """worksheet.write_rich_string() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.write_rich_string(r, c, 'a', self.bold, 'b') + self._test_cell_out_of_range(func) + + def test_worksheet_write_rich_string_max_string_length(self): + """worksheet.write_rich_string() returns MAX_STRING_LENGTH_EXCEEDED + """ + + # Ignore the warning "Ignoring URL since it exceeds Excel's string limit" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + # Removing the last char from s since the function will concatenate 'a' + def func(s): + return self.worksheet.write_rich_string(0, 0, s[:-1], self.bold, 'a') + self._test_max_string_length(func) + + def test_worksheet_write_rich_string_2_consecutive_formats(self): + """worksheet.write_rich_string() returns 2_CONSECUTIVE_FORMATS + """ + + # Ignore the warning "Excel doesn't allow 2 consecutive formats" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_2_CONSECUTIVE_FORMATS + + got = self.worksheet.write_rich_string(0, 0, 'a', self.bold, self.bold, 'b') + self.assertEqual(got, exp) + + def test_worksheet_write_rich_string_empty_string_used(self): + """worksheet.write_rich_string() returns EMPTY_STRING_USED + """ + + # Ignore the warning "Excel doesn't allow empty strings in rich strings" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_EMPTY_STRING_USED + + got = self.worksheet.write_rich_string(0, 0, '', self.bold, 'b') + self.assertEqual(got, exp) + + def test_worksheet_write_rich_string_insufficient_parameters(self): + """worksheet.write_rich_string() returns INSUFFICIENT_PARAMETERS + """ + + # Ignore the warning "You must specify more than 2 format/fragments" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INSUFFICIENT_PARAMETERS + + got = self.worksheet.write_rich_string(0, 0, 'a') + self.assertEqual(got, exp) + + def test_worksheet_write_row_no_error(self): + """worksheet.write_row() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_row(0, 0, [0, 1, 2]) + self._test_no_error(func) + + def test_worksheet_write_column_no_error(self): + """worksheet.write_column() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_column(0, 0, [0, 1, 2]) + self._test_no_error(func) + + def test_worksheet_insert_image_no_error(self): + """worksheet.insert_image() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.insert_image(0, 0, self._testing_image_path) + self._test_no_error(func) + + def test_worksheet_insert_image_out_of_range(self): + """worksheet.insert_image() returns INDEX_OUT_OF_RANGE + """ + + # Ignore the warning "Cannot insert image" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + def func(r, c): + return self.worksheet.insert_image(r, c, self._testing_image_path) + self._test_cell_out_of_range(func) + + def test_worksheet_insert_image_file_not_found(self): + """worksheet.insert_image() returns XW_ERROR_IMAGE_FILE_NOT_FOUND + """ + + # Ignore the warning "Image file not found" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_IMAGE_FILE_NOT_FOUND + + got = self.worksheet.insert_image(0, 0, 'xlsxwriter/nonexisting.png') + self.assertEqual(got, exp) + + def test_worksheet_insert_textbox_no_error(self): + """worksheet.insert_textbox() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.insert_textbox(0, 0, '') + self._test_no_error(func) + + def test_worksheet_insert_textbox_out_of_range(self): + """worksheet.insert_textbox() returns INDEX_OUT_OF_RANGE + """ + + # Ignore the warning "Cannot insert textbox" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + def func(r, c): + return self.worksheet.insert_textbox(r, c, '') + self._test_cell_out_of_range(func) + + def test_worksheet_insert_chart_no_error(self): + """worksheet.insert_chart() returns XW_NO_ERROR + """ + + chart = self.workbook.add_chart({'type': 'column'}) + + def func(): + return self.worksheet.insert_chart(0, 0, chart) + self._test_no_error(func) + + def test_worksheet_insert_chart_out_of_range(self): + """worksheet.insert_chart() returns INDEX_OUT_OF_RANGE + """ + + # Ignore the warning "Cannot insert chart" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + chart = self.workbook.add_chart({'type': 'column'}) + + def func(r, c): + return self.worksheet.insert_chart(r, c, chart) + self._test_cell_out_of_range(func) + + def test_worksheet_insert_chart_none(self): + """worksheet.insert_chart() returns None + """ + + chart = self.workbook.add_chart({'type': 'column'}) + + # Insert it the first time; no error + def func(): + return self.worksheet.insert_chart(0, 0, chart) + self._test_no_error(func) + + # Try to insert the same chart twice, but ignore the warning + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + got = self.worksheet.insert_chart(0, 0, chart) + self.assertIsNone(got) + + def test_worksheet_write_comment_no_error(self): + """worksheet.write_comment() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.write_comment(0, 0, '') + self._test_no_error(func) + + def test_worksheet_write_comment_out_of_range(self): + """worksheet.write_comment() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.write_comment(r, c, '') + self._test_cell_out_of_range(func) + + def test_worksheet_write_comment_max_string_length(self): + """worksheet.write_comment() returns MAX_STRING_LENGTH_EXCEEDED + """ + + def func(s): + return self.worksheet.write_comment(0, 0, s) + self._test_max_string_length(func) + + def test_worksheet_set_background_no_error(self): + """worksheet.set_background() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.set_background(self._testing_image_path) + self._test_no_error(func) + + def test_worksheet_set_background_file_not_found(self): + """worksheet.set_background() returns XW_ERROR_IMAGE_FILE_NOT_FOUND + """ + + # Ignore the warning "Image file not found" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_IMAGE_FILE_NOT_FOUND + + got = self.worksheet.set_background('xlsxwriter/nonexisting.png') + self.assertEqual(got, exp) + + def test_worksheet_set_column_no_error(self): + """worksheet.set_column() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.set_column(0, 0, 10) + self._test_no_error(func) + + def test_worksheet_set_column_out_of_range(self): + """worksheet.set_column() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.set_column(r, c, 10) + self._test_cell_out_of_range(func) + + def test_worksheet_set_column_pixels_no_error(self): + """worksheet.set_column_pixels() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.set_column_pixels(0, 0, 10) + self._test_no_error(func) + + def test_worksheet_set_column_pixels_out_of_range(self): + """worksheet.set_column_pixels() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.set_column_pixels(r, c, 10) + self._test_cell_out_of_range(func) + + def test_worksheet_set_row_no_error(self): + """worksheet.set_row() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.set_row(0, 10) + self._test_no_error(func) + + def test_worksheet_set_row_out_of_range(self): + """worksheet.set_row() returns INDEX_OUT_OF_RANGE + """ + + exp = ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE + + got = self.worksheet.set_row(self.max_row, 10) + self.assertEqual(got, exp) + + def test_worksheet_set_row_pixels_no_error(self): + """worksheet.set_row_pixels() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.set_row_pixels(0, 10) + self._test_no_error(func) + + def test_worksheet_set_row_pixels_out_of_range(self): + """worksheet.set_row_pixels() returns INDEX_OUT_OF_RANGE + """ + + exp = ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE + + got = self.worksheet.set_row_pixels(self.max_row, 10) + self.assertEqual(got, exp) + + def test_worksheet_merge_range_no_error(self): + """worksheet.merge_range() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.merge_range(0, 0, 0, 1, '') + self._test_no_error(func) + + def test_worksheet_merge_range_out_of_range(self): + """worksheet.merge_range() returns INDEX_OUT_OF_RANGE + + This is already tested in worksheet.test_range_return_values, but for + completeness sake it is also repeated here + """ + + def func(r1, c1, r2, c2): + return self.worksheet.merge_range(r1 - 1 if r1 == r2 else r1, c1 - 1 if c1 == c2 else c1, r2, c2, '') + self._test_range_out_of_range(func) + + def test_worksheet_merge_range_none(self): + """worksheet.merge_range() returns None + """ + + # Ignore the warning "Can't merge single cell" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + got = self.worksheet.merge_range(0, 0, 0, 0, '') + self.assertIsNone(got) + + def test_worksheet_data_validation_no_error(self): + """worksheet.data_validation() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'list', 'source': ['a']}) + self._test_no_error(func) + + def test_worksheet_data_validation_out_of_range(self): + """worksheet.data_validation() returns INDEX_OUT_OF_RANGE + """ + + def func(r1, c1, r2, c2): + return self.worksheet.data_validation(r1, c1, r2, c2, {'validate': 'list', 'source': ['a']}) + self._test_range_out_of_range(func) + + def test_worksheet_data_validation_incorrect_parameter_or_option(self): + """worksheet.data_validation() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Unknown parameter + got = self.worksheet.data_validation(0, 0, 0, 0, {'unknown_param': 0}) + self.assertEqual(got, exp) + + # 02) Parameter 'validate' is required + got = self.worksheet.data_validation(0, 0, 0, 0, {}) + self.assertEqual(got, exp) + + # 03) Unknown validation type + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'unknown'}) + self.assertEqual(got, exp) + + # 04) No action is required + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any'}) + self.assertEqual(got, exp) + + # 05) 'criteria' is a required parameter (for some validate) + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'integer'}) + self.assertEqual(got, exp) + + # 06) Unknown criteria type + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'integer', 'criteria': 'unknown'}) + self.assertEqual(got, exp) + + # 07) 'Between' and 'Not between' criteria require 2 values + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'integer', 'criteria': 'between'}) + self.assertEqual(got, exp) + + # 08) Unknown criteria type for parameter 'error_type' + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any', 'input_title': ' ', 'error_type': 'unknown'}) + self.assertEqual(got, exp) + + # 09) Length of input title + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any', 'input_title': ' ' * 33}) + self.assertEqual(got, exp) + + # 10) Length of error title + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any', 'input_title': ' ', 'error_title': ' ' * 33}) + self.assertEqual(got, exp) + + # 11) Length of input message + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any', 'input_title': ' ', 'input_message': ' ' * 256}) + self.assertEqual(got, exp) + + # 12) Length of error message + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'any', 'input_title': ' ', 'error_message': ' ' * 256}) + self.assertEqual(got, exp) + + # 13) Length of list items + got = self.worksheet.data_validation(0, 0, 0, 0, {'validate': 'list', 'source': [' ' * 256]}) + self.assertEqual(got, exp) + + def test_worksheet_conditional_format_no_error(self): + """worksheet.conditional_format() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'cell', 'criteria': '>=', 'value': 50, 'format': self.bold}) + self._test_no_error(func) + + def test_worksheet_conditional_format_out_of_range(self): + """worksheet.conditional_format() returns INDEX_OUT_OF_RANGE + """ + + def func(r1, c1, r2, c2): + return self.worksheet.conditional_format(r1, c1, r2, c2, {'type': 'cell', 'criteria': '>=', 'value': 50, 'format': self.bold}) + self._test_range_out_of_range(func) + + def test_worksheet_conditional_format_incorrect_parameter_or_option(self): + """worksheet.conditional_format() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Unknown parameter + got = self.worksheet.conditional_format(0, 0, 0, 0, {'unknown_param': 0}) + self.assertEqual(got, exp) + + # 02) Parameter 'type' is required + got = self.worksheet.conditional_format(0, 0, 0, 0, {}) + self.assertEqual(got, exp) + + # 03) Unknown value for parameter 'type' + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'unknown'}) + self.assertEqual(got, exp) + + # 04) Conditional format 'value' must be a datetime object. + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'date', 'value': ''}) + self.assertEqual(got, exp) + + # 05) Conditional format 'minimum' must be a datetime object. + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'date', 'minimum': ''}) + self.assertEqual(got, exp) + + # 06) Conditional format 'maximum' must be a datetime object. + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'date', 'maximum': ''}) + self.assertEqual(got, exp) + + # 07) The 'icon_style' parameter must be specified + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'icon_set'}) + self.assertEqual(got, exp) + + # 08) Unknown icon_style + got = self.worksheet.conditional_format(0, 0, 0, 0, {'type': 'icon_set', 'icon_style': 'unknown'}) + self.assertEqual(got, exp) + + def test_worksheet_add_table_no_error(self): + """worksheet.add_table() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.add_table(0, 0, 1, 0) + self._test_no_error(func) + + def test_worksheet_add_table_not_supported_constant_memory(self): + """worksheet.add_table() returns NOT_SUPPORTED_COSTANT_MEMORY + """ + # Here we must use an actual file because the worksheet file handle is + # not cleaned up correctly when using the StringIO + + (fd, filepath) = tempfile.mkstemp() + os.close(fd) + + with Workbook(filepath, dict(constant_memory=True)) as tempworkbook: + tempworksheet = tempworkbook.add_worksheet() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_NOT_SUPPORTED_COSTANT_MEMORY + + got = tempworksheet.add_table(0, 0, 1, 0) + self.assertEqual(got, exp) + + os.unlink(filepath) + + def test_worksheet_add_table_out_of_range(self): + """worksheet.add_table() returns INDEX_OUT_OF_RANGE + """ + + def func(r1, c1, r2, c2): + return self.worksheet.add_table(r1, c1, r2, c2) + self._test_range_out_of_range(func) + + def test_worksheet_add_table_incorrect_parameter_or_option(self): + """worksheet.add_table() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Unknown parameter + got = self.worksheet.add_table(0, 0, 0, 0, {'unknown_param': 0}) + self.assertEqual(got, exp) + + # 02) At least one data row + got = self.worksheet.add_table(0, 0, 0, 0, {}) + self.assertEqual(got, exp) + + # 03) Name cannot contain spaces + got = self.worksheet.add_table(0, 0, 1, 0, {'name': 'My Name'}) + self.assertEqual(got, exp) + + # 04) Invalid Excel characters + got = self.worksheet.add_table(0, 0, 1, 0, {'name': '.'}) + self.assertEqual(got, exp) + + # 05) Name looks like a cell name + got = self.worksheet.add_table(0, 0, 1, 0, {'name': 'A0'}) + self.assertEqual(got, exp) + + # 06) Invalid name like a RC cell ref + got = self.worksheet.add_table(0, 0, 1, 0, {'name': 'R1C1'}) + self.assertEqual(got, exp) + + # 07) Duplicate header name + got = self.worksheet.add_table(0, 0, 1, 1, {'columns': [{'header': 'a'}, {'header': 'a'}]}) + self.assertEqual(got, exp) + + def test_worksheet_add_sparkline_no_error(self): + """worksheet.add_sparkline() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.add_sparkline(0, 0, {'range': 'A1:E1'}) + self._test_no_error(func) + + def test_worksheet_add_sparkline_out_of_range(self): + """worksheet.add_sparkline() returns INDEX_OUT_OF_RANGE + """ + + def func(r, c): + return self.worksheet.add_sparkline(r, c, {'range': 'A1:E1'}) + self._test_cell_out_of_range(func) + + def test_worksheet_add_sparkline_incorrect_parameter_or_option(self): + """worksheet.add_sparkline() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Unknown parameter + got = self.worksheet.add_sparkline(0, 0, {'unknown': 0}) + self.assertEqual(got, exp) + + # 02) Parameter 'range' is required + got = self.worksheet.add_sparkline(0, 0, {}) + self.assertEqual(got, exp) + + # 03) Parameter 'type' must be 'line', 'column' or 'win_loss' + got = self.worksheet.add_sparkline(0, 0, {'range': 'A1:E1', 'type': 'unknown'}) + self.assertEqual(got, exp) + + # 04) Must have the same number of location and range + got = self.worksheet.add_sparkline(0, 0, {'range': ['A1:E1', 'E2:E3']}) + self.assertEqual(got, exp) + + def test_worksheet_unprotect_range_no_error(self): + """worksheet.unprotect_range() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.unprotect_range('A1') + self._test_no_error(func) + + def test_worksheet_unprotect_range_incorrect_parameter_or_option(self): + """worksheet.unprotect_range() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore Cell range must be specified + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + got = self.worksheet.unprotect_range(None) + self.assertEqual(got, exp) + + def test_worksheet_insert_button_no_error(self): + """worksheet.insert_button() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.insert_button(0, 0) + self._test_no_error(func) + + def test_worksheet_insert_button_out_of_range(self): + """worksheet.insert_button() returns INDEX_OUT_OF_RANGE + """ + + # Ignore Cannot insert button + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + def func(r, c): + return self.worksheet.insert_button(r, c) + self._test_cell_out_of_range(func) + + def test_worksheet_print_area_no_error(self): + """worksheet.print_area() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.print_area(0, 0, 10, 10) + self._test_no_error(func) + + def test_worksheet_ignore_errors_no_error(self): + """worksheet.ignore_errors() returns XW_NO_ERROR + """ + + def func(): + return self.worksheet.ignore_errors({'eval_error': True}) + self._test_no_error(func) + + def test_worksheet_ignore_errors_incorrect_parameter_or_option(self): + """worksheet.ignore_errors() returns INCORRECT_PARAMETER_OR_OPTION + """ + + # Ignore the warnings + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=UserWarning) + + exp = ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION + + # 01) Parameter is None + got = self.worksheet.ignore_errors() + self.assertEqual(got, exp) + + # 02) Unknown parameter + got = self.worksheet.ignore_errors({'unknown': 0}) + self.assertEqual(got, exp) diff --git a/xlsxwriter/test/worksheet/test_range_return_values.py b/xlsxwriter/test/worksheet/test_range_return_values.py index 3df12fb19..751172113 100644 --- a/xlsxwriter/test/worksheet/test_range_return_values.py +++ b/xlsxwriter/test/worksheet/test_range_return_values.py @@ -8,6 +8,7 @@ import unittest from ...worksheet import Worksheet +from ...returncodes import ReturnCode class TestRangeReturnValues(unittest.TestCase): @@ -21,7 +22,7 @@ def test_range_return_values(self): max_row = 1048576 max_col = 16384 - bound_error = -1 + bound_error = ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Test some out of bound values. got = worksheet.write_string(max_row, 0, 'Foo') diff --git a/xlsxwriter/workbook.py b/xlsxwriter/workbook.py index 3ffa640c3..85af2488b 100644 --- a/xlsxwriter/workbook.py +++ b/xlsxwriter/workbook.py @@ -43,6 +43,7 @@ from .exceptions import UnsupportedImageFormat from .exceptions import FileCreateError from .exceptions import FileSizeError +from .returncodes import ReturnCode class Workbook(xmlwriter.XMLwriter): @@ -294,12 +295,13 @@ def add_vba_project(self, vba_project, is_stream=False): is_stream: vba_project is an in memory byte stream. Returns: - Nothing. + XW_NO_ERROR: Success. + XW_ERROR_VBA_FILE_NOT_FOUND: VBA project binary file not found """ if not is_stream and not os.path.exists(vba_project): warn("VBA project binary file '%s' not found." % vba_project) - return -1 + return ReturnCode.XW_ERROR_VBA_FILE_NOT_FOUND if self.vba_codename is None: self.vba_codename = 'ThisWorkbook' @@ -307,6 +309,8 @@ def add_vba_project(self, vba_project, is_stream=False): self.vba_project = vba_project self.vba_is_stream = is_stream + return ReturnCode.XW_NO_ERROR + def close(self): """ Call finalization code and close file. @@ -403,13 +407,15 @@ def set_custom_property(self, name, value, property_type=None): property_type: The type of the custom property. Optional. Returns: - Nothing. + XW_NO_ERROR: Success. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ if name is None or value is None: warn("The name and value parameters must be non-None in " "set_custom_property()") - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION if property_type is None: # Determine the property type from the Python type. @@ -437,6 +443,8 @@ def set_custom_property(self, name, value, property_type=None): self.custom_properties.append((name, value, property_type)) + return ReturnCode.XW_NO_ERROR + def set_calc_mode(self, mode, calc_id=None): """ Set the Excel calculation mode for the workbook. @@ -473,7 +481,9 @@ def define_name(self, name, formula): formula: The cell or range that the defined name refers to. Returns: - Nothing. + XW_NO_ERROR: Success. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ sheet_index = None @@ -495,7 +505,7 @@ def define_name(self, name, formula): # Warn if the sheet index wasn't found. if sheet_index is None: warn("Unknown sheet name '%s' in defined_name()" % sheetname) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: # Use -1 to indicate global names. sheet_index = -1 @@ -504,22 +514,24 @@ def define_name(self, name, formula): if (not re.match(r'^[\w\\][\w\\.]*$', name, re.UNICODE) or re.match(r'^\d', name)): warn("Invalid Excel characters in defined_name(): '%s'" % name) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Warn if the defined name looks like a cell name. if re.match(r'^[a-zA-Z][a-zA-Z]?[a-dA-D]?[0-9]+$', name): warn("Name looks like a cell name in defined_name(): '%s'" % name) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Warn if the name looks like a R1C1 cell reference. if (re.match(r'^[rcRC]$', name) or re.match(r'^[rcRC]\d+[rcRC]\d+$', name)): warn("Invalid name '%s' like a RC cell ref in defined_name()" % name) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION self.defined_names.append([name, sheet_index, formula, False]) + return ReturnCode.XW_NO_ERROR + def worksheets(self): """ Return a list of the worksheet objects in the workbook. diff --git a/xlsxwriter/worksheet.py b/xlsxwriter/worksheet.py index b276d848f..21014f469 100644 --- a/xlsxwriter/worksheet.py +++ b/xlsxwriter/worksheet.py @@ -40,6 +40,7 @@ from .utility import preserve_whitespace from .utility import quote_sheetname from .exceptions import DuplicateTableName +from .returncodes import ReturnCode # Compile performance critical regular expressions. re_control_chars_1 = re.compile('(_x[0-9a-fA-F]{4}_)') @@ -441,9 +442,21 @@ def write(self, row, col, *args): *args: Args to pass to sub functions. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - other: Return value of called method. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String longer than 32767 + characters. + XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY: Formula can't be None or + empty. + XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED: URL longer than Excel + limit of characters. + XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED: Exceeds Excel limit of + 65,530 urls per + worksheet. + XW_ERROR_2_CONSECUTIVE_FORMATS: 2 consecutive formats used. + XW_ERROR_EMPTY_STRING_USED: Empty string used. + XW_ERROR_INSUFFICIENT_PARAMETERS: Insufficient parameters. """ return self._write(row, col, *args) @@ -539,9 +552,11 @@ def write_string(self, row, col, string, cell_format=None): format: An optional cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: String truncated to 32k characters. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String truncated to 32k + characters. """ return self._write_string(row, col, string, cell_format) @@ -549,16 +564,16 @@ def write_string(self, row, col, string, cell_format=None): # Undecorated version of write_string(). def _write_string(self, row, col, string, cell_format=None): - str_error = 0 + str_error = ReturnCode.XW_NO_ERROR # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Check that the string is < 32767 chars. if len(string) > self.xls_strmax: string = string[:self.xls_strmax] - str_error = -2 + str_error = ReturnCode.XW_ERROR_MAX_STRING_LENGTH_EXCEEDED # Write a shared string or an in-line string in constant_memory mode. if not self.constant_memory: @@ -587,8 +602,9 @@ def write_number(self, row, col, number, cell_format=None): cell_format: An optional cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ return self._write_number(row, col, number, cell_format) @@ -611,7 +627,7 @@ def _write_number(self, row, col, number, cell_format=None): # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Write previous row if in in-line string constant_memory mode. if self.constant_memory and row > self.previous_row: @@ -620,7 +636,7 @@ def _write_number(self, row, col, number, cell_format=None): # Store the cell data in the worksheet data table. self.table[row][col] = cell_number_tuple(number, cell_format) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_blank(self, row, col, blank, cell_format=None): @@ -635,8 +651,9 @@ def write_blank(self, row, col, blank, cell_format=None): cell_format: An optional cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ return self._write_blank(row, col, blank, cell_format) @@ -645,11 +662,11 @@ def write_blank(self, row, col, blank, cell_format=None): def _write_blank(self, row, col, blank, cell_format=None): # Don't write a blank cell unless it has a format. if cell_format is None: - return 0 + return ReturnCode.XW_NO_ERROR # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Write previous row if in in-line string constant_memory mode. if self.constant_memory and row > self.previous_row: @@ -658,7 +675,7 @@ def _write_blank(self, row, col, blank, cell_format=None): # Store the cell data in the worksheet data table. self.table[row][col] = cell_blank_tuple(cell_format) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_formula(self, row, col, formula, cell_format=None, value=0): @@ -673,9 +690,11 @@ def write_formula(self, row, col, formula, cell_format=None, value=0): value: An optional value for the formula. Default is 0. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: Formula can't be None or empty. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY: Formula can't be None or + empty. """ # Check that row and col are valid and store max and min values. @@ -684,11 +703,11 @@ def write_formula(self, row, col, formula, cell_format=None, value=0): # Undecorated version of write_formula(). def _write_formula(self, row, col, formula, cell_format=None, value=0): if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if formula is None or formula == '': warn("Formula can't be None or empty") - return -1 + return ReturnCode.XW_ERROR_FORMULA_CANT_BE_NONE_OR_EMPTY # Check for dynamic array functions. if (re_dynamic_function.search(formula)): @@ -711,7 +730,7 @@ def _write_formula(self, row, col, formula, cell_format=None, value=0): # Store the cell data in the worksheet data table. self.table[row][col] = cell_formula_tuple(formula, cell_format, value) - return 0 + return ReturnCode.XW_NO_ERROR @convert_range_args def write_array_formula(self, first_row, first_col, last_row, last_col, @@ -729,8 +748,9 @@ def write_array_formula(self, first_row, first_col, last_row, last_col, value: An optional value for the formula. Default is 0. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ # Check for dynamic array functions. @@ -761,15 +781,16 @@ def write_dynamic_array_formula(self, first_row, first_col, value: An optional value for the formula. Default is 0. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ error = self._write_array_formula(first_row, first_col, last_row, last_col, formula, cell_format, value, 'dynamic') - if error == 0: + if error == ReturnCode.XW_NO_ERROR: self.has_dynamic_arrays = True return error @@ -956,9 +977,10 @@ def _write_array_formula(self, first_row, first_col, last_row, last_col, # Check that row and col are valid and store max and min values. if self._check_dimensions(first_row, first_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE + if self._check_dimensions(last_row, last_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Define array range if first_row == last_row and first_col == last_col: @@ -988,7 +1010,7 @@ def _write_array_formula(self, first_row, first_col, last_row, last_col, if row != first_row or col != first_col: self._write_number(row, col, 0, cell_format) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_datetime(self, row, col, date, cell_format=None): @@ -1002,8 +1024,9 @@ def write_datetime(self, row, col, date, cell_format=None): cell_format: A cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ return self._write_datetime(row, col, date, cell_format) @@ -1013,7 +1036,7 @@ def _write_datetime(self, row, col, date, cell_format=None): # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Write previous row if in in-line string constant_memory mode. if self.constant_memory and row > self.previous_row: @@ -1029,7 +1052,7 @@ def _write_datetime(self, row, col, date, cell_format=None): # Store the cell data in the worksheet data table. self.table[row][col] = cell_number_tuple(number, cell_format) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_boolean(self, row, col, boolean, cell_format=None): @@ -1043,8 +1066,9 @@ def write_boolean(self, row, col, boolean, cell_format=None): cell_format: An optional cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ return self._write_boolean(row, col, boolean, cell_format) @@ -1054,7 +1078,7 @@ def _write_boolean(self, row, col, boolean, cell_format=None): # Check that row and col are valid and store max and min values. if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Write previous row if in in-line string constant_memory mode. if self.constant_memory and row > self.previous_row: @@ -1068,7 +1092,7 @@ def _write_boolean(self, row, col, boolean, cell_format=None): # Store the cell data in the worksheet data table. self.table[row][col] = cell_boolean_tuple(value, cell_format) - return 0 + return ReturnCode.XW_NO_ERROR # Write a hyperlink. This is comprised of two elements: the displayed # string and the non-displayed link. The displayed string is the same as @@ -1091,12 +1115,18 @@ def write_url(self, row, col, url, cell_format=None, format: An optional cell Format object. string: An optional display string for the hyperlink. tip: An optional tooltip. + Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: String longer than 32767 characters. - -3: URL longer than Excel limit of 255 characters. - -4: Exceeds Excel limit of 65,530 urls per worksheet. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String longer than 32767 + characters. + XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED: URL longer than Excel + limit of characters. + XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED: Exceeds Excel limit of + 65,530 urls per + worksheet. """ return self._write_url(row, col, url, cell_format, string, tip) @@ -1106,7 +1136,7 @@ def _write_url(self, row, col, url, cell_format=None, # Check that row and col are valid and store max and min values if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Set the displayed string to the URL unless defined by the user. if string is None: @@ -1135,11 +1165,10 @@ def _write_url(self, row, col, url, cell_format=None, string = string.replace('mailto:', '') # Check that the string is < 32767 chars - str_error = 0 if len(string) > self.xls_strmax: warn("Ignoring URL since it exceeds Excel's string limit of " "32767 characters") - return -2 + return ReturnCode.XW_ERROR_MAX_STRING_LENGTH_EXCEEDED # Copy string for use in hyperlink elements. url_str = string @@ -1174,7 +1203,7 @@ def _write_url(self, row, col, url, cell_format=None, warn("Ignoring URL '%s' with link or location/anchor > %d " "characters since it exceeds Excel's limit for URLS" % (url, max_url)) - return -3 + return ReturnCode.XW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED # Check the limit of URLS per worksheet. self.hlink_count += 1 @@ -1182,7 +1211,7 @@ def _write_url(self, row, col, url, cell_format=None, if self.hlink_count > 65530: warn("Ignoring URL '%s' since it exceeds Excel's limit of " "65,530 URLS per worksheet." % url) - return -4 + return ReturnCode.XW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED # Write previous row if in in-line string constant_memory mode. if self.constant_memory and row > self.previous_row: @@ -1193,7 +1222,7 @@ def _write_url(self, row, col, url, cell_format=None, cell_format = self.default_url_format # Write the hyperlink string. - self._write_string(row, col, string, cell_format) + str_error = self._write_string(row, col, string, cell_format) # Store the hyperlink data in a separate structure. self.hyperlinks[row][col] = { @@ -1216,12 +1245,14 @@ def write_rich_string(self, row, col, *args): cell_format: Optional Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: String truncated to 32k characters. - -3: 2 consecutive formats used. - -4: Empty string used. - -5: Insufficient parameters. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String longer than 32767 + characters. + XW_ERROR_2_CONSECUTIVE_FORMATS: 2 consecutive formats used. + XW_ERROR_EMPTY_STRING_USED: Empty string used. + XW_ERROR_INSUFFICIENT_PARAMETERS: Insufficient parameters. """ @@ -1237,7 +1268,7 @@ def _write_rich_string(self, row, col, *args): # Check that row and col are valid and store max and min values if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # If the last arg is a format we use it as the cell format. if isinstance(tokens[-1], Format): @@ -1262,7 +1293,7 @@ def _write_rich_string(self, row, col, *args): if len(tokens) <= 2: warn("You must specify more than 2 format/fragments for rich " "strings. Ignoring input in write_rich_string().") - return -5 + return ReturnCode.XW_ERROR_INSUFFICIENT_PARAMETERS for token in tokens: if not isinstance(token, Format): @@ -1278,7 +1309,7 @@ def _write_rich_string(self, row, col, *args): if token == '': warn("Excel doesn't allow empty strings in rich strings. " "Ignoring input in write_rich_string().") - return -4 + return ReturnCode.XW_ERROR_EMPTY_STRING_USED # Keep track of actual string str_length. str_length += len(token) @@ -1288,7 +1319,7 @@ def _write_rich_string(self, row, col, *args): if previous == 'format' and pos > 0: warn("Excel doesn't allow 2 consecutive formats in rich " "strings. Ignoring input in write_rich_string().") - return -3 + return ReturnCode.XW_ERROR_2_CONSECUTIVE_FORMATS # Token is a format object. Add it to the fragment list. fragments.append(token) @@ -1323,7 +1354,7 @@ def _write_rich_string(self, row, col, *args): if str_length > self.xls_strmax: warn("String length must be less than or equal to Excel's limit " "of 32,767 characters in write_rich_string().") - return -2 + return ReturnCode.XW_ERROR_MAX_STRING_LENGTH_EXCEEDED # Write a shared string or an in-line string in constant_memory mode. if not self.constant_memory: @@ -1338,7 +1369,7 @@ def _write_rich_string(self, row, col, *args): # Store the cell data in the worksheet data table. self.table[row][col] = cell_string_tuple(string_index, cell_format) - return 0 + return ReturnCode.XW_NO_ERROR def add_write_handler(self, user_type, user_function): """ @@ -1366,17 +1397,17 @@ def write_row(self, row, col, data, cell_format=None): data: A list of tokens to be written with write(). format: An optional cell Format object. Returns: - 0: Success. + XW_NO_ERROR: Success. other: Return value of write() method. """ for token in data: error = self._write(row, col, token, cell_format) - if error: + if error != ReturnCode.XW_NO_ERROR: return error col += 1 - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_column(self, row, col, data, cell_format=None): @@ -1389,17 +1420,17 @@ def write_column(self, row, col, data, cell_format=None): data: A list of tokens to be written with write(). format: An optional cell Format object. Returns: - 0: Success. + XW_NO_ERROR: Success. other: Return value of write() method. """ for token in data: error = self._write(row, col, token, cell_format) - if error: + if error != ReturnCode.XW_NO_ERROR: return error row += 1 - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def insert_image(self, row, col, filename, options=None): @@ -1413,14 +1444,16 @@ def insert_image(self, row, col, filename, options=None): options: Position, scale, url and data stream of the image. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_IMAGE_FILE_NOT_FOUND: Image file not found. """ # Check insert (row, col) without storing. if self._check_dimensions(row, col, True, True): warn('Cannot insert image at (%d, %d).' % (row, col)) - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if options is None: options = {} @@ -1441,12 +1474,12 @@ def insert_image(self, row, col, filename, options=None): if not image_data and not os.path.exists(filename): warn("Image file '%s' not found." % filename) - return -1 + return ReturnCode.XW_ERROR_IMAGE_FILE_NOT_FOUND self.images.append([row, col, filename, x_offset, y_offset, x_scale, y_scale, url, tip, anchor, image_data, description, decorative]) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def insert_textbox(self, row, col, text, options=None): @@ -1460,14 +1493,15 @@ def insert_textbox(self, row, col, text, options=None): options: Textbox options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ # Check insert (row, col) without storing. if self._check_dimensions(row, col, True, True): warn('Cannot insert textbox at (%d, %d).' % (row, col)) - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if text is None: text = '' @@ -1486,7 +1520,7 @@ def insert_textbox(self, row, col, text, options=None): self.shapes.append([row, col, x_offset, y_offset, x_scale, y_scale, text, anchor, options, description, decorative]) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def insert_chart(self, row, col, chart, options=None): @@ -1500,14 +1534,16 @@ def insert_chart(self, row, col, chart, options=None): options: Position and scale of the chart. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + None: The chart (or the combined one) was already inserted. """ # Check insert (row, col) without storing. if self._check_dimensions(row, col, True, True): warn('Cannot insert chart at (%d, %d).' % (row, col)) - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if options is None: options = {} @@ -1550,7 +1586,7 @@ def insert_chart(self, row, col, chart, options=None): x_scale, y_scale, anchor, description, decorative]) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def write_comment(self, row, col, comment, options=None): @@ -1564,9 +1600,11 @@ def write_comment(self, row, col, comment, options=None): options: Comment formatting options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: String longer than 32k characters. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_MAX_STRING_LENGTH_EXCEEDED: String longer than 32767 + characters. """ if options is None: @@ -1574,11 +1612,11 @@ def write_comment(self, row, col, comment, options=None): # Check that row and col are valid and store max and min values if self._check_dimensions(row, col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Check that the comment string is < 32767 chars. if len(comment) > self.xls_strmax: - return -2 + return ReturnCode.XW_ERROR_MAX_STRING_LENGTH_EXCEEDED self.has_vml = 1 self.has_comments = 1 @@ -1586,7 +1624,7 @@ def write_comment(self, row, col, comment, options=None): # Store the options of the cell comment, to process on file close. self.comments[row][col] = [row, col, comment, options] - return 0 + return ReturnCode.XW_NO_ERROR def show_comments(self): """ @@ -1609,17 +1647,20 @@ def set_background(self, filename, is_byte_stream=False): filename: Path and filename for in supported formats. is_byte_stream: File is a stream of bytes. Returns: - Nothing. + XW_NO_ERROR: Success. + XW_ERROR_IMAGE_FILE_NOT_FOUND: Image file not found """ if not is_byte_stream and not os.path.exists(filename): warn("Image file '%s' not found." % filename) - return -1 + return ReturnCode.XW_ERROR_IMAGE_FILE_NOT_FOUND self.background_bytes = is_byte_stream self.background_image = filename + return ReturnCode.XW_NO_ERROR + def set_comments_author(self, author): """ Set the default author of the cell comments. @@ -1734,8 +1775,9 @@ def set_column(self, first_col, last_col, width=None, cell_format=None, options: Dict of options such as hidden and level. Returns: - 0: Success. - -1: Column number is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ if options is None: @@ -1761,9 +1803,9 @@ def set_column(self, first_col, last_col, width=None, cell_format=None, # Check that each column is valid and store the max and min values. if self._check_dimensions(0, last_col, ignore_row, ignore_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if self._check_dimensions(0, first_col, ignore_row, ignore_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Set the limits for the outline levels (0 <= x <= 7). if level < 0: @@ -1792,7 +1834,7 @@ def set_column(self, first_col, last_col, width=None, cell_format=None, if cell_format: self.col_formats[col] = cell_format - return 0 + return ReturnCode.XW_NO_ERROR @convert_column_args def set_column_pixels(self, first_col, last_col, width=None, @@ -1809,8 +1851,9 @@ def set_column_pixels(self, first_col, last_col, width=None, options: Dict of options such as hidden and level. Returns: - 0: Success. - -1: Column number is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ if width is not None: @@ -1830,8 +1873,9 @@ def set_row(self, row, height=None, cell_format=None, options=None): options: Dict of options such as hidden, level and collapsed. Returns: - 0: Success. - -1: Row number is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ if options is None: @@ -1845,7 +1889,7 @@ def set_row(self, row, height=None, cell_format=None, options=None): # Check that row is valid. if self._check_dimensions(row, min_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if height is None: height = self.default_row_height @@ -1878,7 +1922,7 @@ def set_row(self, row, height=None, cell_format=None, options=None): # Store the row sizes for use when calculating image vertices. self.row_sizes[row] = [height, hidden] - return 0 + return ReturnCode.XW_NO_ERROR def set_row_pixels(self, row, height=None, cell_format=None, options=None): """ @@ -1891,8 +1935,9 @@ def set_row_pixels(self, row, height=None, cell_format=None, options=None): options: Dict of options such as hidden, level and collapsed. Returns: - 0: Success. - -1: Row number is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ if height is not None: @@ -1938,16 +1983,18 @@ def merge_range(self, first_row, first_col, last_row, last_col, cell_format: Cell Format object. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. other: Return value of write(). + None: A single cell was (tried to be) merged """ # Merge a range of cells. The first cell should contain the data and # the others should be blank. All cells should have the same format. # Excel doesn't allow a single cell to be merged - if first_row == last_row and first_col == last_col: + if (first_row, first_col) == (last_row, last_col): warn("Can't merge single cell") return @@ -1959,24 +2006,25 @@ def merge_range(self, first_row, first_col, last_row, last_col, # Check that row and col are valid and store max and min values. if self._check_dimensions(first_row, first_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if self._check_dimensions(last_row, last_col): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Store the merge range. self.merge.append([first_row, first_col, last_row, last_col]) # Write the first cell - self._write(first_row, first_col, data, cell_format) + error = self._write(first_row, first_col, data, cell_format) # Pad out the rest of the area with formatted blank cells. for row in range(first_row, last_row + 1): for col in range(first_col, last_col + 1): if row == first_row and col == first_col: continue - self._write_blank(row, col, '', cell_format) + error2 = self._write_blank(row, col, '', cell_format) + error = error if error != ReturnCode.XW_NO_ERROR else error2 - return 0 + return error @convert_range_args def autofilter(self, first_row, first_col, last_row, last_col): @@ -2121,15 +2169,17 @@ def data_validation(self, first_row, first_col, last_row, last_col, options: Data validation options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: Incorrect parameter or option. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ # Check that row and col are valid without storing the values. if self._check_dimensions(first_row, first_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if self._check_dimensions(last_row, last_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if options is None: options = {} @@ -2161,7 +2211,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, for param_key in options.keys(): if param_key not in valid_parameters: warn("Unknown parameter '%s' in data_validation()" % param_key) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Map alternative parameter names 'source' or 'minimum' to 'value'. if 'source' in options: @@ -2172,7 +2222,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, # 'validate' is a required parameter. if 'validate' not in options: warn("Parameter 'validate' is required in data_validation()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # List of valid validation types. valid_types = { @@ -2194,7 +2244,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, if not options['validate'] in valid_types: warn("Unknown validation type '%s' for parameter " "'validate' in data_validation()" % options['validate']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: options['validate'] = valid_types[options['validate']] @@ -2203,7 +2253,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, if (options['validate'] == 'none' and options.get('input_title') is None and options.get('input_message') is None): - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # The any, list and custom validations don't have a criteria so we use # a default of 'between'. @@ -2216,7 +2266,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, # 'criteria' is a required parameter. if 'criteria' not in options: warn("Parameter 'criteria' is required in data_validation()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Valid criteria types. criteria_types = { @@ -2242,7 +2292,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, if not options['criteria'] in criteria_types: warn("Unknown criteria type '%s' for parameter " "'criteria' in data_validation()" % options['criteria']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: options['criteria'] = criteria_types[options['criteria']] @@ -2252,7 +2302,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, if 'maximum' not in options: warn("Parameter 'maximum' is required in data_validation() " "when using 'between' or 'not between' criteria") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: options['maximum'] = None @@ -2269,7 +2319,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, elif not options['error_type'] in error_types: warn("Unknown criteria type '%s' for parameter 'error_type' " "in data_validation()" % options['error_type']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: options['error_type'] = error_types[options['error_type']] @@ -2291,27 +2341,27 @@ def data_validation(self, first_row, first_col, last_row, last_col, if options.get('input_title') and len(options['input_title']) > 32: warn("Length of input title '%s' exceeds Excel's limit of 32" % options['input_title']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Check that the error title doesn't exceed the maximum length. if options.get('error_title') and len(options['error_title']) > 32: warn("Length of error title '%s' exceeds Excel's limit of 32" % options['error_title']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Check that the input message doesn't exceed the maximum length. if (options.get('input_message') and len(options['input_message']) > 255): warn("Length of input message '%s' exceeds Excel's limit of 255" % options['input_message']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Check that the error message doesn't exceed the maximum length. if (options.get('error_message') and len(options['error_message']) > 255): warn("Length of error message '%s' exceeds Excel's limit of 255" % options['error_message']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Check that the input list doesn't exceed the maximum length. if options['validate'] == 'list' and type(options['value']) is list: @@ -2319,7 +2369,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, if len(formula) > 255: warn("Length of list items '%s' exceeds Excel's limit of " "255, use a formula range instead" % formula) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Set some defaults if they haven't been defined by the user. if 'ignore_blank' not in options: @@ -2341,7 +2391,7 @@ def data_validation(self, first_row, first_col, last_row, last_col, # Store the validation information until we close the worksheet. self.validations.append(options) - return 0 + return ReturnCode.XW_NO_ERROR @convert_range_args def conditional_format(self, first_row, first_col, last_row, last_col, @@ -2357,15 +2407,17 @@ def conditional_format(self, first_row, first_col, last_row, last_col, options: Conditional format options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: Incorrect parameter or option. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ # Check that row and col are valid without storing the values. if self._check_dimensions(first_row, first_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if self._check_dimensions(last_row, last_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if options is None: options = {} @@ -2417,12 +2469,12 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if param_key not in valid_parameter: warn("Unknown parameter '%s' in conditional_format()" % param_key) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # 'type' is a required parameter. if 'type' not in options: warn("Parameter 'type' is required in conditional_format()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Valid types. valid_type = { @@ -2450,7 +2502,7 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if options['type'] not in valid_type: warn("Unknown value '%s' for parameter 'type' " "in conditional_format()" % options['type']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: if options['type'] == 'bottom': options['direction'] = 'bottom' @@ -2503,7 +2555,7 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if not supported_datetime(options['value']): warn("Conditional format 'value' must be a " "datetime object.") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: date_time = self._convert_date_time(options['value']) # Format date number to the same precision as Excel. @@ -2513,7 +2565,7 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if not supported_datetime(options['minimum']): warn("Conditional format 'minimum' must be a " "datetime object.") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: date_time = self._convert_date_time(options['minimum']) options['minimum'] = "%.16g" % date_time @@ -2522,7 +2574,7 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if not supported_datetime(options['maximum']): warn("Conditional format 'maximum' must be a " "datetime object.") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: date_time = self._convert_date_time(options['maximum']) options['maximum'] = "%.16g" % date_time @@ -2554,13 +2606,13 @@ def conditional_format(self, first_row, first_col, last_row, last_col, if not options.get('icon_style'): warn("The 'icon_style' parameter must be specified when " "'type' == 'icon_set' in conditional_format()") - return -3 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Check for valid icon styles. if options['icon_style'] not in valid_icons: warn("Unknown icon_style '%s' in conditional_format()" % options['icon_style']) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: options['icon_style'] = valid_icons[options['icon_style']] @@ -2827,7 +2879,7 @@ def conditional_format(self, first_row, first_col, last_row, last_col, else: self.cond_formats[cell_range] = [options] - return 0 + return ReturnCode.XW_NO_ERROR @convert_range_args def add_table(self, first_row, first_col, last_row, last_col, @@ -2843,10 +2895,13 @@ def add_table(self, first_row, first_col, last_row, last_col, options: Table format options. (Optional) Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: Incorrect parameter or option. - -3: Not supported in constant_memory mode. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. + XW_ERROR_NOT_SUPPORTED_COSTANT_MEMORY: Not supported in + constant_memory mode. """ table = {} col_formats = {} @@ -2859,13 +2914,13 @@ def add_table(self, first_row, first_col, last_row, last_col, if self.constant_memory: warn("add_table() isn't supported in 'constant_memory' mode") - return -3 + return ReturnCode.XW_ERROR_NOT_SUPPORTED_COSTANT_MEMORY # Check that row and col are valid without storing the values. if self._check_dimensions(first_row, first_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if self._check_dimensions(last_row, last_col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE # Swap last row/col for first row/col as necessary. if first_row > last_row: @@ -2892,7 +2947,7 @@ def add_table(self, first_row, first_col, last_row, last_col, for param_key in options.keys(): if param_key not in valid_parameter: warn("Unknown parameter '%s' in add_table()" % param_key) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Turn on Excel's defaults. options['banded_rows'] = options.get('banded_rows', True) @@ -2906,7 +2961,7 @@ def add_table(self, first_row, first_col, last_row, last_col, if num_rows < 0: warn("Must have at least one data row in in add_table()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Set the table options. table['show_first_col'] = options.get('first_column', False) @@ -2923,25 +2978,25 @@ def add_table(self, first_row, first_col, last_row, last_col, if ' ' in name: warn("Name '%s' in add_table() cannot contain spaces" % name) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Warn if the name contains invalid chars as defined by Excel. if (not re.match(r'^[\w\\][\w\\.]*$', name, re.UNICODE) or re.match(r'^\d', name)): warn("Invalid Excel characters in add_table(): '%s'" % name) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Warn if the name looks like a cell name. if re.match(r'^[a-zA-Z][a-zA-Z]?[a-dA-D]?[0-9]+$', name): warn("Name looks like a cell name in add_table(): '%s'" % name) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Warn if the name looks like a R1C1 cell reference. if (re.match(r'^[rcRC]$', name) or re.match(r'^[rcRC]\d+[rcRC]\d+$', name)): warn("Invalid name '%s' like a RC cell ref in add_table()" % name) - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Set the table style. if 'style' in options: @@ -3020,7 +3075,8 @@ def add_table(self, first_row, first_col, last_row, last_col, if name in seen_names: warn("Duplicate header name in add_table(): '%s'" % name) - return -2 + return \ + ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: seen_names[name] = True @@ -3113,7 +3169,7 @@ def add_table(self, first_row, first_col, last_row, last_col, # Store the table data. self.tables.append(table) - return 0 + return ReturnCode.XW_NO_ERROR @convert_cell_args def add_sparkline(self, row, col, options=None): @@ -3126,15 +3182,17 @@ def add_sparkline(self, row, col, options=None): options: Sparkline formatting options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. - -2: Incorrect parameter or option. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ # Check that row and col are valid without storing the values. if self._check_dimensions(row, col, True, True): - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE sparkline = {'locations': [xl_rowcol_to_cell(row, col)]} @@ -3175,12 +3233,12 @@ def add_sparkline(self, row, col, options=None): for param_key in options.keys(): if param_key not in valid_parameters: warn("Unknown parameter '%s' in add_sparkline()" % param_key) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # 'range' is a required parameter. if 'range' not in options: warn("Parameter 'range' is required in add_sparkline()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Handle the sparkline type. spark_type = options.get('type', 'line') @@ -3188,7 +3246,7 @@ def add_sparkline(self, row, col, options=None): if spark_type not in ('line', 'column', 'win_loss'): warn("Parameter 'type' must be 'line', 'column' " "or 'win_loss' in add_sparkline()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION if spark_type == 'win_loss': spark_type = 'stacked' @@ -3213,7 +3271,7 @@ def add_sparkline(self, row, col, options=None): if range_count != location_count: warn("Must have the same number of location and range " "parameters in add_sparkline()") - return -2 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Store the count. sparkline['count'] = len(sparkline['locations']) @@ -3302,7 +3360,7 @@ def add_sparkline(self, row, col, options=None): self.sparklines.append(sparkline) - return 0 + return ReturnCode.XW_NO_ERROR @convert_range_args def set_selection(self, first_row, first_col, last_row, last_col): @@ -3539,12 +3597,14 @@ def unprotect_range(self, cell_range, range_name=None, password=None): password: An optional password string. (undocumented) Returns: - Nothing. + XW_NO_ERROR: Success. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ if cell_range is None: warn('Cell range must be specified in unprotect_range()') - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION # Sanitize the cell range. cell_range = cell_range.lstrip('=') @@ -3560,6 +3620,8 @@ def unprotect_range(self, cell_range, range_name=None, password=None): self.protected_ranges.append((cell_range, range_name, password)) + return ReturnCode.XW_NO_ERROR + @convert_cell_args def insert_button(self, row, col, options=None): """ @@ -3571,14 +3633,15 @@ def insert_button(self, row, col, options=None): options: Button formatting options. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE: Row or column is out of + worksheet bounds. """ # Check insert (row, col) without storing. if self._check_dimensions(row, col, True, True): warn('Cannot insert button at (%d, %d).' % (row, col)) - return -1 + return ReturnCode.XW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE if options is None: options = {} @@ -3589,7 +3652,7 @@ def insert_button(self, row, col, options=None): self.has_vml = 1 - return 0 + return ReturnCode.XW_NO_ERROR ########################################################################### # @@ -3967,13 +4030,13 @@ def print_area(self, first_row, first_col, last_row, last_col): last_col: The last column of the cell range. Returns: - 0: Success. - -1: Row or column is out of worksheet bounds. + XW_NO_ERROR: Success. + None : Max print area selected """ # Set the print area in the current worksheet. - # Ignore max print area since it is the same as no area for Excel. + # Ignore max print area since it is the same as no area for Excel. if (first_row == 0 and first_col == 0 and last_row == self.xls_rowmax - 1 and last_col == self.xls_colmax - 1): @@ -3984,7 +4047,7 @@ def print_area(self, first_row, first_col, last_row, last_col): last_row, last_col) self.print_area_range = area - return 0 + return ReturnCode.XW_NO_ERROR def print_across(self): """ @@ -4119,12 +4182,13 @@ def ignore_errors(self, options=None): options: A dict of ignore errors keys with cell range values. Returns: - 0: Success. - -1: Incorrect parameter or option. + XW_NO_ERROR: Success. + XW_ERROR_INCORRECT_PARAMETER_OR_OPTION: Incorrect parameter or + option. """ if options is None: - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION else: # Copy the user defined options so they aren't modified. options = options.copy() @@ -4146,11 +4210,11 @@ def ignore_errors(self, options=None): for param_key in options.keys(): if param_key not in valid_parameters: warn("Unknown parameter '%s' in ignore_errors()" % param_key) - return -1 + return ReturnCode.XW_ERROR_INCORRECT_PARAMETER_OR_OPTION self.ignored_errors = options - return 0 + return ReturnCode.XW_NO_ERROR ########################################################################### #