Skip to content

Commit

Permalink
table: fix issue with @ in comments in table formulas
Browse files Browse the repository at this point in the history
Closes #1075
  • Loading branch information
jmcnamara committed Aug 30, 2024
1 parent 2dcfb2a commit d963212
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
2 changes: 1 addition & 1 deletion xlsxwriter/test/worksheet/test_prepare_formula.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ...worksheet import Worksheet


class TestCalculateSpans(unittest.TestCase):
class TestPrepareFormula(unittest.TestCase):
"""
Test the _prepare_formula Worksheet method for different formula types.
Expand Down
44 changes: 44 additions & 0 deletions xlsxwriter/test/worksheet/test_prepare_table_formula.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
###############################################################################
#
# Tests for XlsxWriter.
#
# SPDX-License-Identifier: BSD-2-Clause
# Copyright (c), 2013-2024, John McNamara, jmcnamara@cpan.org
#

import unittest
from io import StringIO
from ...worksheet import Worksheet


class TestPrepareTableFormula(unittest.TestCase):
"""
Test the _prepare_table_formula Worksheet method for different formula types.
"""

def test_prepare_table_formula(self):
self.fh = StringIO()
self.worksheet = Worksheet()
self.worksheet._set_filehandle(self.fh)

testcases = [
["", ""],
["@", "[#This Row],"],
['"Comment @"', r'"Comment @"'],
[
"SUM(Table1[@[Column1]:[Column3]])",
"SUM(Table1[[#This Row],[Column1]:[Column3]])",
],
[
"""HYPERLINK(CONCAT("http://myweb.com:1677/'@md=d&path/to/sour/...'@/",[@CL],"?ac=10"),[@CL])""",
"""HYPERLINK(CONCAT("http://myweb.com:1677/'@md=d&path/to/sour/...'@/",[[#This Row],CL],"?ac=10"),[[#This Row],CL])""",
],
]

for testcase in testcases:
formula = testcase[0]
exp = testcase[1]
got = self.worksheet._prepare_table_formula(formula)

self.assertEqual(exp, got)
33 changes: 32 additions & 1 deletion xlsxwriter/worksheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,37 @@ def _prepare_formula(self, formula, expand_future_functions=False):

return formula

# Escape/expand table functions. This mainly involves converting Excel 2010
# "@" table ref to 2007 "[#This Row],". We parse the string to avoid
# replacements in string literals within the formula.
@staticmethod
def _prepare_table_formula(formula):
if "@" not in formula:
# No escaping required.
return formula

escaped_formula = []
in_string_literal = False

for char in formula:
# Match the start/end of string literals to avoid escaping
# references in strings.
if char == '"':
in_string_literal = not in_string_literal

# Copy the string literal.
if in_string_literal:
escaped_formula.append(char)
continue

# Replace table reference.
if char == "@":
escaped_formula.append("[#This Row],")
else:
escaped_formula.append(char)

return ("").join(escaped_formula)

# Undecorated version of write_array_formula() and
# write_dynamic_array_formula().
def _write_array_formula(
Expand Down Expand Up @@ -3463,7 +3494,7 @@ def add_table(self, first_row, first_col, last_row, last_col, options=None):
formula = formula.lstrip("=")

# Convert Excel 2010 "@" ref to 2007 "#This Row".
formula = formula.replace("@", "[#This Row],")
formula = self._prepare_table_formula(formula)

# Escape any future functions.
formula = self._prepare_formula(formula, True)
Expand Down

0 comments on commit d963212

Please sign in to comment.