Skip to content
This repository was archived by the owner on Nov 19, 2018. It is now read-only.

Commit 4ab4b6a

Browse files
author
Kamil Sambor
committed
Merge pull request #37 from pydot/bug/36
Adjusted quoting to DOT lang specification
2 parents a142f0a + 9d2f8fa commit 4ab4b6a

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

pydot_ng/__init__.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,13 @@ def __repr__(self):
198198
return "frozendict(%s)" % dict.__repr__(self)
199199

200200

201-
dot_keywords = ['graph', 'subgraph', 'digraph', 'node', 'edge', 'strict']
202-
203-
id_re_alpha_nums = re.compile('^[_a-zA-Z][a-zA-Z0-9_,]*$', re.UNICODE)
204-
id_re_alpha_nums_with_ports = re.compile(
205-
'^[_a-zA-Z][a-zA-Z0-9_,:\"]*[a-zA-Z0-9_,\"]+$', re.UNICODE)
206-
id_re_num = re.compile('^[0-9,]+$', re.UNICODE)
207-
id_re_with_port = re.compile('^([^:]*):([^:]*)$', re.UNICODE)
208-
id_re_dbl_quoted = re.compile('^\".*\"$', re.S | re.UNICODE)
209-
id_re_html = re.compile('^<.*>$', re.S | re.UNICODE)
201+
# cases when no qoutes needed, from http://www.graphviz.org/doc/info/lang.html
202+
dot_keywords = ('graph', 'subgraph', 'digraph', 'node', 'edge', 'strict')
203+
id_alpha_num = re.compile(r'^[_a-zA-Z\200-\377][_a-zA-Z0-9\200-\377]*$',
204+
re.UNICODE)
205+
id_num = re.compile(r'^[-]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)$', re.UNICODE)
206+
id_html = re.compile(r'^<.*>$', re.DOTALL | re.UNICODE)
207+
id_quoted = re.compile(r'^".*"$', re.DOTALL | re.UNICODE)
210208

211209

212210
def needs_quotes(s):
@@ -228,19 +226,18 @@ def needs_quotes(s):
228226
if s in dot_keywords:
229227
return False
230228

231-
chars = [ord(c) for c in s if ord(c) > 0x7f or ord(c) == 0]
232-
if chars and not id_re_dbl_quoted.match(s) and not id_re_html.match(s):
233-
return True
234-
235229
for test_re in [
236-
id_re_alpha_nums, id_re_num, id_re_dbl_quoted,
237-
id_re_html, id_re_alpha_nums_with_ports]:
230+
id_alpha_num,
231+
id_num,
232+
id_html,
233+
id_quoted,
234+
]:
238235
if test_re.match(s):
239236
return False
240237

241-
m = id_re_with_port.match(s)
242-
if m:
243-
return needs_quotes(m.group(1)) or needs_quotes(m.group(2))
238+
chars = [ord(c) for c in s if ord(c) > 0x7f or ord(c) == 0]
239+
if chars and not id_quoted.match(s) and not id_html.match(s):
240+
return True
244241

245242
return True
246243

test/test_pydot.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,33 @@ def test_quoting(self):
285285
data = g.create(format='jpe')
286286
self.assertEqual(len(data) > 0, True)
287287

288+
289+
class TestQuoting(unittest.TestCase):
290+
291+
def test_quote_cases(self):
292+
checks = (
293+
('A:', '"A:"'),
294+
(':B', '":B"'),
295+
('A:B', '"A:B"'),
296+
('1A', '"1A"'),
297+
('A', 'A'),
298+
('11', '11'),
299+
('_xyz', '_xyz'),
300+
('.11', '.11'),
301+
('-.09', '-.09'),
302+
('1.8', '1.8'),
303+
('', '""'),
304+
('"1abc"', '"1abc"'),
305+
('@', '"@"'),
306+
('ÿ', 'ÿ'),
307+
('$GUID__/ffb73e1c-7495-40b3-9618-9e5462fc89c7',
308+
'"$GUID__/ffb73e1c-7495-40b3-9618-9e5462fc89c7"')
309+
)
310+
311+
for input, expected in checks:
312+
self.assertEqual(pydot.quote_if_necessary(input), expected)
313+
314+
288315
if __name__ == '__main__':
289316
suite = unittest.TestLoader().loadTestsFromTestCase(TestGraphAPI)
290317
unittest.TextTestRunner(verbosity=2).run(suite)

0 commit comments

Comments
 (0)