Skip to content

Commit 8658e6c

Browse files
Resolve code smell issues
1 parent a413b72 commit 8658e6c

5 files changed

Lines changed: 47 additions & 65 deletions

File tree

docx/opc/customprops.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
NS_VT = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
1515

16+
1617
class CustomProperties(object):
1718
"""
1819
Corresponds to part named ``/docProps/custom.xml``, containing the custom
@@ -21,50 +22,51 @@ class CustomProperties(object):
2122
def __init__(self, element):
2223
self._element = element
2324

24-
def __getitem__( self, item ):
25+
def __getitem__(self, item):
2526
prop = self.lookup(item)
26-
if prop is not None :
27-
# print(etree.tostring(prop, pretty_print=True))
27+
if prop is not None:
2828
elm = prop[0]
2929
if elm.tag == '{%s}i4' % NS_VT:
3030
try:
3131
return int(elm.text)
32-
except:
32+
except ValueError:
3333
return elm.text
3434
elif elm.tag == '{%s}bool' % NS_VT:
3535
return True if elm.text == '1' else False
3636
return elm.text
3737

38-
def __setitem__( self, key, value ):
38+
def __setitem__(self, key, value):
3939
prop = self.lookup(key)
40-
if prop is None :
41-
elmType = 'lpwstr'
40+
if prop is None:
41+
elm_type = 'lpwstr'
4242
if isinstance(value, bool):
43-
elmType = 'bool'
43+
elm_type = 'bool'
4444
value = str(1 if value else 0)
4545
elif isinstance(value, numbers.Number):
46-
elmType = 'i4'
46+
elm_type = 'i4'
4747
value = str(int(value))
48-
prop = etree.SubElement( self._element, "property" )
49-
elm = etree.SubElement(prop, '{%s}%s' %(NS_VT, elmType), nsmap = {'vt':NS_VT} )
48+
prop = etree.SubElement(self._element, "property")
49+
elm = etree.SubElement(prop, '{%s}%s' % (NS_VT, elm_type), nsmap={'vt': NS_VT})
5050
elm.text = value
5151
prop.set("name", key)
52+
# magic number "FMTID_UserDefinedProperties"
53+
# MS doc ref: https://learn.microsoft.com/de-de/windows/win32/stg/predefined-property-set-format-identifiers
5254
prop.set("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
53-
prop.set("pid", "%s" % str(len(self._element) + 1))
55+
prop.set("pid", str(len(self._element) + 1))
5456
else:
5557
elm = prop[0]
5658
if elm.tag == '{%s}i4' % NS_VT:
5759
elm.text = str(int(value))
5860
elif elm.tag == '{%s}bool' % NS_VT:
5961
elm.text = str(1 if value else 0)
6062
else:
61-
elm.text = '%s' % str(value)
63+
elm.text = str(value)
6264

63-
def __len__( self ):
65+
def __len__(self):
6466
return len(self._element)
6567

6668
def lookup(self, item):
67-
for child in self._element :
68-
if child.get("name") == item :
69+
for child in self._element:
70+
if child.get("name") == item:
6971
return child
70-
return None
72+
return None

docx/opc/parts/customprops.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@
1010

1111
from lxml import etree
1212

13-
from datetime import datetime
14-
15-
from ..constants import CONTENT_TYPE as CT
16-
from ..customprops import CustomProperties
17-
from ...oxml.customprops import CT_CustomProperties
18-
from ..packuri import PackURI
19-
from ..part import XmlPart
13+
from docx.opc.constants import CONTENT_TYPE as CT
14+
from docx.opc.customprops import CustomProperties
15+
from docx.oxml.customprops import CT_CustomProperties
16+
from docx.opc.packuri import PackURI
17+
from docx.opc.part import XmlPart
2018

2119
# configure XML parser
2220
parser_lookup = etree.ElementDefaultClassLookup(element=CT_CustomProperties)
@@ -35,7 +33,6 @@ def ct_parse_xml(xml):
3533
return root_element
3634

3735

38-
3936
class CustomPropertiesPart(XmlPart):
4037
"""
4138
Corresponds to part named ``/docProps/custom.xml``, containing the custom

docx/oxml/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ def register_element_cls(tag, cls):
4242
def register_element_cls_ns(tag, ns, cls):
4343
"""
4444
Register *cls* to be constructed when the oxml parser encounters an
45-
element with matching *tag*. *tag* is a string of the form
46-
``nspfx:tagroot``, e.g. ``'w:document'``.
45+
element with matching *tag*.
46+
*tag* is a string of the form ``tagroot``, e.g. ``'Properties'``,
47+
while the namespace is given explicitely by the *ns* argument.
4748
"""
4849
namespace = element_class_lookup.get_namespace(ns)
4950
namespace[tag] = cls

docx/oxml/customprops.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
absolute_import, division, print_function, unicode_literals
99
)
1010

11+
from datetime import datetime, timedelta
1112
import re
1213

13-
from datetime import datetime, timedelta
14-
from lxml import etree
15-
from .ns import nsdecls, qn
16-
from .xmlchemy import BaseOxmlElement, ZeroOrOne
17-
from . import parse_xml
14+
from docx.oxml.ns import nsdecls, qn
15+
from docx.oxml.xmlchemy import BaseOxmlElement
16+
from docx.oxml import parse_xml
17+
1818

1919
class CT_CustomProperties(BaseOxmlElement):
2020
"""
@@ -24,17 +24,18 @@ class CT_CustomProperties(BaseOxmlElement):
2424
"""
2525

2626
_customProperties_tmpl = (
27-
'<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" %s/>\n' % nsdecls('vt')
27+
'<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" %s/>\n' % nsdecls('vt')
2828
)
29+
_offset_pattern = re.compile("([+-])(\\d\\d):(\\d\\d)")
2930

3031
@classmethod
3132
def new(cls):
3233
"""
3334
Return a new ``<property>`` element
3435
"""
3536
xml = cls._customProperties_tmpl
36-
customProperties = parse_xml(xml)
37-
return customProperties
37+
custom_properties = parse_xml(xml)
38+
return custom_properties
3839

3940
def _datetime_of_element(self, property_name):
4041
element = getattr(self, property_name)
@@ -75,8 +76,6 @@ def _offset_dt(cls, dt, offset_str):
7576
td = timedelta(hours=hours, minutes=minutes)
7677
return dt + td
7778

78-
_offset_pattern = re.compile('([+-])(\d\d):(\d\d)')
79-
8079
@classmethod
8180
def _parse_W3CDTF_to_datetime(cls, w3cdtf_str):
8281
# valid W3CDTF date cases:
@@ -102,8 +101,7 @@ def _parse_W3CDTF_to_datetime(cls, w3cdtf_str):
102101
except ValueError:
103102
continue
104103
if dt is None:
105-
tmpl = "could not parse W3CDTF datetime string '%s'"
106-
raise ValueError(tmpl % w3cdtf_str)
104+
raise ValueError("could not parse W3CDTF datetime string '%s'" % {w3cdtf_str})
107105
if len(offset_str) == 6:
108106
return cls._offset_dt(dt, offset_str)
109107
return dt
@@ -113,18 +111,15 @@ def _set_element_datetime(self, prop_name, value):
113111
Set date/time value of child element having *prop_name* to *value*.
114112
"""
115113
if not isinstance(value, datetime):
116-
tmpl = (
117-
"property requires <type 'datetime.datetime'> object, got %s"
118-
)
119-
raise ValueError(tmpl % type(value))
114+
raise ValueError("property requires <type 'datetime.datetime'> object, got %s" % type(value))
120115
element = self._get_or_add(prop_name)
121116
dt_str = value.strftime('%Y-%m-%dT%H:%M:%SZ')
122117
element.text = dt_str
123118
if prop_name in ('created', 'modified'):
124-
# These two require an explicit 'xsi:type="dcterms:W3CDTF"'
125-
# attribute. The first and last line are a hack required to add
119+
# These two require an explicit 'xsi:type="dcterms:W3CDTF"' attribute.
120+
# The first and last line are a hack required to add
126121
# the xsi namespace to the root element rather than each child
127-
# element in which it is referenced
122+
# element in which it is referenced.
128123
self.set(qn('xsi:foo'), 'bar')
129124
element.set(qn('xsi:type'), 'dcterms:W3CDTF')
130125
del self.attrib[qn('xsi:foo')]
@@ -135,10 +130,7 @@ def _set_element_text(self, prop_name, value):
135130
"""
136131
value = str(value)
137132
if len(value) > 255:
138-
tmpl = (
139-
"exceeded 255 char limit for property, got:\n\n'%s'"
140-
)
141-
raise ValueError(tmpl % value)
133+
raise ValueError("exceeded 255 char limit for property, got:\n\n'%s'" % value)
142134
element = self._get_or_add(prop_name)
143135
element.text = value
144136

@@ -153,4 +145,3 @@ def _text_of_element(self, property_name):
153145
if element.text is None:
154146
return ''
155147
return element.text
156-

tests/opc/parts/test_customprops.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,21 @@
88
absolute_import, division, print_function, unicode_literals
99
)
1010

11-
from datetime import datetime, timedelta
12-
1311
import pytest
1412

1513
from docx.opc.customprops import CustomProperties
1614
from docx.opc.parts.customprops import CustomPropertiesPart
1715
from docx.oxml.customprops import CT_CustomProperties
1816

19-
from ...unitutil.mock import class_mock, instance_mock
17+
from tests.unitutil.mock import class_mock, instance_mock
2018

2119

2220
class DescribeCustomPropertiesPart(object):
2321

24-
def it_provides_access_to_its_custom_props_object(self, customprops_fixture):
25-
custom_properties_part, CustomProperties_ = customprops_fixture
22+
def it_provides_access_to_its_custom_props_object(self, element_, mock_custom_properties_):
23+
custom_properties_part = CustomPropertiesPart(None, None, element_, None)
2624
custom_properties = custom_properties_part.custom_properties
27-
CustomProperties_.assert_called_once_with(custom_properties_part.element)
25+
mock_custom_properties_.assert_called_once_with(custom_properties_part.element)
2826
assert isinstance(custom_properties, CustomProperties)
2927

3028
def it_can_create_a_default_custom_properties_part(self):
@@ -36,14 +34,7 @@ def it_can_create_a_default_custom_properties_part(self):
3634
# fixtures ---------------------------------------------
3735

3836
@pytest.fixture
39-
def customprops_fixture(self, element_, CustomProperties_):
40-
custom_properties_part = CustomPropertiesPart(None, None, element_, None)
41-
return custom_properties_part, CustomProperties_
42-
43-
# fixture components -----------------------------------
44-
45-
@pytest.fixture
46-
def CustomProperties_(self, request):
37+
def mock_custom_properties_(self, request):
4738
return class_mock(request, 'docx.opc.parts.customprops.CustomProperties')
4839

4940
@pytest.fixture

0 commit comments

Comments
 (0)