Skip to content

Commit

Permalink
Merge pull request #1 from reclosedev/more-attrs
Browse files Browse the repository at this point in the history
Add support for more attirbutes: comment, hyperlink, font, alignment, fill, protection
  • Loading branch information
9seconds committed Sep 23, 2015
2 parents 206d183 + c647b5b commit 35278c7
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ python:
- "pypy"

install:
- pip install --use-mirrors -r requirements/package.txt -r requirements/qa.txt
- pip install -r requirements/package.txt -r requirements/qa.txt
- pip install coveralls

script:
Expand Down
42 changes: 42 additions & 0 deletions surveyor/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import openpyxl
import openpyxl.utils
import openpyxl.comments
import openpyxl.styles
import six

import surveyor.classes.simple
Expand Down Expand Up @@ -271,12 +273,30 @@ def stylize(self, cells):
return cells


StyleInfo = collections.namedtuple("StyleInfo", ["attribute", "constructor"])


class Cell(BaseElement):

TAG_NAME = "td"

ATTR_SEPARATOR = "-"

ATTR_CLASS = "class"
ATTR_NUMBER_FORMAT = "number_format"
ATTR_HYPERLINK = "hyperlink"
ATTR_COMMENT = "comment"
ATTR_COMMENT_AUTHOR = "comment{0}author".format(ATTR_SEPARATOR)

STYLE_ATTRIBUTES = {
"font": StyleInfo("font", openpyxl.styles.Font),
"pattern-fill": StyleInfo("fill", openpyxl.styles.PatternFill),
"gradient-fill": StyleInfo("fill", openpyxl.styles.GradientFill),
"alignment": StyleInfo("alignment", openpyxl.styles.Alignment),
"protection": StyleInfo("protection", openpyxl.styles.Protection),
# TODO border
}
STYLE_PREFIXES = tuple(STYLE_ATTRIBUTES.keys())

DEFAULT_STYLER = surveyor.classes.simple.Cell

Expand All @@ -287,17 +307,39 @@ def __init__(self, element):
self.value = surveyor.utils.guess_text(element.text)
# check openpyxl.styles.numbers
self.number_format = element.attrib.get(self.ATTR_NUMBER_FORMAT)
self.hyperlink = element.attrib.get(self.ATTR_HYPERLINK)

comment_text = element.attrib.get(self.ATTR_COMMENT)
if comment_text:
self.comment = openpyxl.comments.Comment(comment_text, element.attrib.get(self.ATTR_COMMENT_AUTHOR))
else:
self.comment = None

self.styles_by_prefix = collections.defaultdict(dict)
for attr, value in element.attrib.items():
if attr.startswith(self.STYLE_PREFIXES):
prefix, name = attr.rsplit(self.ATTR_SEPARATOR, 1)
self.styles_by_prefix[prefix][name] = value
# TODO check for multiple type of fills (maybe by the same StyleInfo.attribute)

def collect(self, element, row_idx=1, col_idx=1):
cell = element.cell(row=row_idx, column=col_idx)
cell.value = self.value
if self.hyperlink is not None:
cell.hyperlink = self.hyperlink
if self.comment is not None:
cell.comment = self.comment

return cell

def apply_inline_styles(self, cell):
if self.number_format is not None:
cell.number_format = self.number_format

for prefix, kwargs in self.styles_by_prefix.items():
style_info = self.STYLE_ATTRIBUTES[prefix]
style_object = style_info.constructor(**kwargs)
setattr(cell, style_info.attribute, style_object)
return cell

def stylize(self, cell):
Expand Down
167 changes: 167 additions & 0 deletions tests/test_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import unicode_literals

import pytest
import openpyxl.styles

import surveyor.parse as parse

Expand Down Expand Up @@ -128,3 +129,169 @@ def test_check_inline_number_format(number_format):
workbook = workbook.process()

assert workbook.worksheets[0].cell(row=1, column=1).number_format == number_format


# noinspection PyUnresolvedReferences
@pytest.mark.parametrize("hyperlink", (
"http:",
"aaa",
"http://google.com",
))
def test_hyperlink(hyperlink):
xml = """
<workbook>
<sheet>
<table>
<tr>
<td hyperlink="{0}">1</td>
</tr>
</table>
</sheet>
</workbook>
""".format(hyperlink).strip()

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

assert workbook.worksheets[0].cell(row=1, column=1).hyperlink == hyperlink


# noinspection PyUnresolvedReferences
@pytest.mark.parametrize("comment, author", (
("", None),
("comment", None),
("comment", "author"),
))
def test_comment(comment, author):
attributes = "comment='{0}'".format(comment)
if author is not None:
attributes += " comment-author='{0}'".format(author)

xml = """
<workbook>
<sheet>
<table>
<tr>
<td {0}>1</td>
</tr>
</table>
</sheet>
</workbook>
""".format(attributes).strip()

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
if not comment:
assert cell.comment is None
else:
assert cell.comment.text == comment
if author:
assert cell.comment.author == author


def test_font_styles():
xml = """
<workbook>
<sheet>
<table>
<tr>
<td font-name="name" font-sz="21" font-family="4">1</td>
</tr>
</table>
</sheet>
</workbook>
"""

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
assert cell.font.name == "name"
assert cell.font.sz == 21
assert cell.font.family == 4


def test_pattern_fill_styles():
xml = """
<workbook>
<sheet>
<table>
<tr>
<td pattern-fill-patternType="solid" pattern-fill-fgColor="0d0d0d">1</td>
</tr>
</table>
</sheet>
</workbook>
"""

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
assert cell.fill.patternType == "solid"
assert cell.fill.fgColor == openpyxl.styles.Color("0d0d0d")


def test_gradient_fill_styles():
xml = """
<workbook>
<sheet>
<table>
<tr>
<td gradient-fill-degree="10" gradient-fill-left="5">1</td>
</tr>
</table>
</sheet>
</workbook>
"""

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
assert cell.fill.degree == 10
assert cell.fill.left == 5


def test_alignment_styles():
xml = """
<workbook>
<sheet>
<table>
<tr>
<td alignment-horizontal="right" alignment-vertical="top">1</td>
</tr>
</table>
</sheet>
</workbook>
"""

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
assert cell.alignment.horizontal == "right"
assert cell.alignment.vertical == "top"


def test_protection_styles():
xml = """
<workbook>
<sheet>
<table>
<tr>
<td protection-locked="0" protection-hidden="1">1</td>
</tr>
</table>
</sheet>
</workbook>
"""

workbook = parse.parse_fileobj(xml)
workbook = workbook.process()

cell = workbook.worksheets[0].cell(row=1, column=1)
assert not cell.protection.locked
assert cell.protection.hidden

0 comments on commit 35278c7

Please sign in to comment.