Skip to content

Commit aea6c38

Browse files
committed
Merge request for the updates since the original python3
1 parent 37a20fe commit aea6c38

File tree

8 files changed

+165
-45
lines changed

8 files changed

+165
-45
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ python:
66
- "3.3"
77

88
install:
9-
- "pip install pytest Twisted coveralls . --use-mirrors"
9+
- "pip install pytest Twisted coveralls pytz . --use-mirrors"
1010
script:
1111
- "coverage run $(which trial) test_parsley"
1212
- "coverage run -a $(which trial) ometa"

examples/iso8601.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import datetime
2+
import pytz
3+
4+
from parsley import makeGrammar
5+
6+
# See www.ietf.org/rfc/rfc3339.txt
7+
8+
_iso_8601_definition = r"""
9+
year = <digit{4}>:Y -> int(Y)
10+
month = <digit{2}>:m -> int(m)
11+
day = <digit{2}>:d -> int(d)
12+
13+
hour = <digit{2}>:H -> int(H)
14+
minute = <digit{2}>:M -> int(M)
15+
second = <digit{2}>:S -> int(S)
16+
fraction = '.' <digit+>:frac -> int(float('0.' + frac) * 10 ** 6)
17+
18+
sign = ('-' -> -1) | ('+' -> 1)
19+
numeric_offset = sign:s hour:h ':' minute:m -> FixedOffset(s * (h * 60 + m))
20+
utc = 'Z' -> UTC
21+
offset = utc | numeric_offset
22+
23+
naive_time = hour:h ':' minute:m ':' second:s (fraction | -> 0):ms
24+
-> time(h, m, s, ms)
25+
time = naive_time:t offset:o -> t.replace(tzinfo=o)
26+
date = year:y '-' month:m '-' day:d -> date(y, m, d)
27+
28+
datetime = date:d 'T' time:t -> datetime.combine(d, t)
29+
"""
30+
31+
32+
DateTimeParser = makeGrammar(
33+
_iso_8601_definition,
34+
{
35+
'FixedOffset': pytz.FixedOffset,
36+
'date': datetime.date,
37+
'time': datetime.time,
38+
'datetime': datetime.datetime,
39+
'UTC': pytz.UTC,
40+
},
41+
)

examples/test_iso8601.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import datetime
2+
import unittest
3+
4+
try:
5+
import pytz
6+
from iso8601 import DateTimeParser
7+
except ImportError:
8+
skip = 'pytz is not installed or usable'
9+
else:
10+
skip = None
11+
12+
13+
class TestDatetimeParsing(unittest.TestCase):
14+
if skip is not None:
15+
skip = skip
16+
17+
def test_date(self):
18+
self.assertEqual(
19+
datetime.date(2001, 12, 25),
20+
DateTimeParser('2001-12-25').date())
21+
22+
def test_naive_time(self):
23+
self.assertEqual(
24+
datetime.time(13, 59, 43),
25+
DateTimeParser('13:59:43').naive_time())
26+
27+
def test_fractional_naive_time(self):
28+
self.assertEqual(
29+
datetime.time(13, 59, 43, 880000),
30+
DateTimeParser('13:59:43.88').naive_time())
31+
32+
def test_utc_time(self):
33+
self.assertEqual(
34+
datetime.time(13, 59, 43, tzinfo=pytz.UTC),
35+
DateTimeParser('13:59:43Z').time())
36+
37+
def test_fractional_utc_time(self):
38+
self.assertEqual(
39+
datetime.time(13, 59, 43, 880000, tzinfo=pytz.UTC),
40+
DateTimeParser('13:59:43.88Z').time())
41+
42+
def test_timezone_time(self):
43+
self.assertEqual(
44+
datetime.time(13, 59, 43, tzinfo=pytz.FixedOffset(60)),
45+
DateTimeParser('13:59:43+01:00').time())
46+
47+
def test_fractional_timezone_time(self):
48+
self.assertEqual(
49+
datetime.time(13, 59, 43, 770000, tzinfo=pytz.FixedOffset(60)),
50+
DateTimeParser('13:59:43.77+01:00').time())
51+
52+
def test_numeric_offset(self):
53+
get_offset = lambda x: DateTimeParser(x).numeric_offset()
54+
self.assertEqual(pytz.FixedOffset(0), get_offset('+00:00'))
55+
self.assertEqual(pytz.FixedOffset(90), get_offset('+01:30'))
56+
self.assertEqual(pytz.FixedOffset(-150), get_offset('-02:30'))
57+
58+
def test_datetime(self):
59+
self.assertEqual(
60+
datetime.datetime(
61+
2001, 12, 25, 13, 59, 43, 770000, tzinfo=pytz.UTC),
62+
DateTimeParser('2001-12-25T13:59:43.77Z').datetime())

ometa/interp.py

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11
import string
2-
3-
try:
4-
xrange
5-
except NameError:
6-
xrange = range
7-
try:
8-
basestring
9-
except NameError:
10-
basestring = str
11-
122
from ometa.runtime import (InputStream, ParseError, EOFError, ArgInput,
133
joinErrors, expected, LeftRecursion)
144

@@ -30,13 +20,13 @@ class TrampolinedGrammarInterpreter(object):
3020
An interpreter for OMeta grammars that processes input
3121
incrementally.
3222
"""
33-
def __init__(self, grammar, ruleName, callback=None, globals=None):
23+
def __init__(self, grammar, rule, callback=None, globals=None):
3424
self.grammar = grammar
3525
self.position = 0
3626
self.callback = callback
3727
self.globals = globals or {}
3828
self.rules = decomposeGrammar(grammar)
39-
self.next_ = self.apply(ruleName, None, ())
29+
self.next = self.setNext(rule)
4030
self._localsStack = []
4131
self.currentResult = None
4232
self.input = InputStream([], 0)
@@ -55,7 +45,7 @@ def receive(self, buf):
5545
raise ValueError("Can't feed a parser that's been ended.")
5646
self.input.data.extend(buf)
5747
x = None
58-
for x in self.next_:
48+
for x in self.next:
5949
if x is _feed_me:
6050
return x
6151
if self.callback:
@@ -72,12 +62,18 @@ def end(self):
7262
return
7363
self.ended = True
7464
x = None
75-
for x in self.next_:
65+
for x in self.next:
7666
pass
7767
if self.callback:
7868
self.callback(*x)
7969

8070

71+
def setNext(self, rule):
72+
if not isinstance(rule, tuple):
73+
rule = (rule, )
74+
return self.apply(rule[0], None, rule[1:])
75+
76+
8177
## Implementation note: each method, instead of being a function
8278
## returning a value, is a generator that will yield '_feed_me' an
8379
## arbitrary number of times, then finally yield the value of the
@@ -92,12 +88,8 @@ def _apply(self, rule, ruleName, args):
9288
@param args: A sequence of arguments to it.
9389
"""
9490
if args:
95-
if basestring is str:
96-
attrname = '__code__'
97-
else:
98-
attrname = 'func_code'
99-
if ((not getattr(rule, attrname, None))
100-
or getattr(rule, attrname).co_argcount - 1 != len(args)):
91+
if ((not getattr(rule, 'func_code', None))
92+
or rule.func_code.co_argcount - 1 != len(args)):
10193
for arg in args[::-1]:
10294
self.input = ArgInput(arg, self.input)
10395
g = rule()
@@ -162,10 +154,15 @@ def apply(self, ruleName, codeName, args):
162154
Invoke a rule, optionally with arguments.
163155
"""
164156
argvals = []
165-
for a in args:
166-
for x in self._eval(a):
167-
if x is _feed_me: yield x
168-
argvals.append(x[0])
157+
# we tell whether a rule is a manually set one by the codeName
158+
# if it's None, then we think it's set by setNext
159+
if codeName is None:
160+
argvals = args
161+
else:
162+
for a in args:
163+
for x in self._eval(a):
164+
if x is _feed_me: yield x
165+
argvals.append(x[0])
169166
_locals = {}
170167
self._localsStack.append(_locals)
171168
try:
@@ -263,7 +260,7 @@ def parse_Or(self, expr):
263260
self.currentError = joinErrors(errors)
264261
yield x
265262
return
266-
except ParseError as err:
263+
except ParseError, err:
267264
errors.append(err)
268265
self.input = i
269266
raise self.err(joinErrors(errors))
@@ -282,8 +279,7 @@ def parse_Many(self, expr, ans=None):
282279
if x is _feed_me: yield x
283280
ans.append(x[0])
284281
self.currentError = x[1]
285-
except ParseError as e:
286-
err = e
282+
except ParseError, err:
287283
self.input = m
288284
break
289285
yield ans, err
@@ -336,8 +332,7 @@ def parse_Repeat(self, min, max, expr):
336332
if x is _feed_me: yield x
337333
v, e = x
338334
ans.append(v)
339-
except ParseError as err:
340-
e = err
335+
except ParseError, e:
341336
self.input = m
342337
break
343338
yield ans, e
@@ -384,10 +379,10 @@ def parse_Label(self, expr, label_term):
384379
for x in self._eval(expr):
385380
if x is _feed_me:
386381
yield x
387-
print("^^ %s" % label)
382+
print "^^", label
388383
self.currentError = x[1].withMessage([("Custom Exception:", label, None)])
389384
yield x[0], self.currentError
390-
except ParseError as e:
385+
except ParseError, e:
391386
raise self.err(e.withMessage([("Custom Exception:", label, None)]))
392387

393388

@@ -472,7 +467,7 @@ def rule_letter(self):
472467
except EOFError:
473468
yield _feed_me
474469
val, p = self.input.head()
475-
if val in getattr(string, 'letters', string.ascii_letters):
470+
if val in string.letters:
476471
self.input = self.input.tail()
477472
yield val, p
478473
else:
@@ -508,9 +503,6 @@ def __init__(self, grammar, base, globals=None):
508503
self.rules = {}
509504
self._localsStack = []
510505
self._globals = globals or {}
511-
if basestring is str:
512-
self._globals['basestring'] = str
513-
self._globals['unichr'] = chr
514506
self.rules = decomposeGrammar(grammar)
515507
self.run = None
516508
self._spanStart = 0
@@ -562,7 +554,7 @@ def _eval(self, run, expr):
562554
try:
563555
val, err = self._eval(run, args[0])
564556
return val, err.withMessage([("Custom Exception:", label, None)])
565-
except ParseError as e:
557+
except ParseError, e:
566558
raise e.withMessage([("Custom Exception:", label, None)])
567559

568560
elif name == "Token":
@@ -578,8 +570,7 @@ def _eval(self, run, expr):
578570
m = run.input
579571
v, _ = self._eval(run, args[0])
580572
ans.append(v)
581-
except ParseError as e:
582-
err = e
573+
except ParseError, err:
583574
run.input = m
584575
break
585576
return ans, err
@@ -607,8 +598,7 @@ def _eval(self, run, expr):
607598
m = run.input
608599
v, e = self._eval(run, args[2])
609600
ans.append(v)
610-
except ParseError as err:
611-
e = err
601+
except ParseError, e:
612602
run.input = m
613603
break
614604
return ans, e
@@ -630,7 +620,7 @@ def _eval(self, run, expr):
630620
ret, err = x
631621
errors.append(err)
632622
return ret, joinErrors(errors)
633-
except ParseError as err:
623+
except ParseError, err:
634624
errors.append(err)
635625
run.input = m
636626
raise joinErrors(errors)
@@ -640,7 +630,7 @@ def _eval(self, run, expr):
640630
m = run.input
641631
try:
642632
self._eval(run, args[0])
643-
except ParseError as err:
633+
except ParseError, err:
644634
run.input = m
645635
return True, run.input.nullError()
646636
else:

ometa/test/test_tube.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def setUp(self):
3434
_grammar = r"""
3535
delimiter = '\r\n'
3636
initial = <(~delimiter anything)*>:val delimiter -> receiver.receive(val)
37+
witharg :arg1 :arg2 = <(~delimiter anything)*>:a delimiter -> receiver.receive(arg1+arg2+a)
3738
"""
3839
self.grammar = self._parseGrammar(_grammar)
3940

@@ -75,3 +76,16 @@ def test_bindings(self):
7576
bindings = {'SMALL_INT': 3}
7677
TrampolinedParser(self._parseGrammar(grammar), receiver, bindings).receive('0')
7778
self.assertEqual(receiver.received, [3])
79+
80+
81+
def test_currentRuleWithArgs(self):
82+
"""
83+
TrampolinedParser should be able to invoke curruent rule with args.
84+
"""
85+
receiver = TrampolinedReceiver()
86+
receiver.currentRule = "witharg", "nice ", "day"
87+
trampolinedParser = TrampolinedParser(self.grammar, receiver, {})
88+
buf = b' oh yes\r\n'
89+
for c in iterbytes(buf):
90+
trampolinedParser.receive(c)
91+
self.assertEqual(receiver.received, ["nice day oh yes"])

ometa/tube.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _setupInterp(self):
2626
'initial'.
2727
"""
2828
self._interp = TrampolinedGrammarInterpreter(
29-
grammar=self.grammar, ruleName=self.receiver.currentRule,
29+
grammar=self.grammar, rule=self.receiver.currentRule,
3030
callback=None, globals=self.bindings)
3131

3232

terml/nodes.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ def __eq__(self, other):
3434
return False
3535

3636

37+
def __hash__(self):
38+
return hash((Term, self.tag, self.data, self.args))
39+
40+
3741
def __repr__(self):
3842
return "term('%s')" % (self._unparse(4).replace("'", "\\'"))
3943

@@ -115,6 +119,9 @@ def __ne__(self, other):
115119
def __repr__(self):
116120
return "Tag(%r)" % (self.name,)
117121

122+
def __hash__(self):
123+
return hash((Tag, self.name))
124+
118125
def _unparse(self, indentLevel=0):
119126
return self.name
120127

terml/test/test_terml.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from twisted.trial import unittest
22
from ometa.runtime import ParseError
3-
from terml.nodes import Tag, Term, coerceToTerm, TermMaker
3+
from terml.nodes import Tag, Term, coerceToTerm, TermMaker, termMaker
44
from terml.parser import TermLParser, character, parseTerm
55

66

@@ -156,3 +156,9 @@ def test_coerce(self):
156156
coerceToTerm({3: 4, "a": character('x'), (2, 3): [4, 5]}),
157157
parseTerm('{"a": \'x\', 3: 4, [2, 3]: [4, 5]}'))
158158

159+
160+
def test_hash(self):
161+
t = TermMaker()
162+
a = t.Arbitrary('foo')
163+
b = t.Arbitrary('foo')
164+
self.assertEqual(hash(a), hash(b))

0 commit comments

Comments
 (0)