Skip to content

Commit

Permalink
support #inst notation
Browse files Browse the repository at this point in the history
  • Loading branch information
sunng87 committed Oct 19, 2012
1 parent cad2021 commit 1a5a002
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 7 deletions.
46 changes: 42 additions & 4 deletions clj.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@
# clojure boolean true => python boolean true
# clojure nil => python None
#
# clojure datetime => python datetime
#


__all__ = ["dump", "dumps", "load", "loads"]

import os
from cStringIO import StringIO

from datetime import datetime
import pyrfc3339
import pytz

def number(v):
if '.' in v:
return float(v)
Expand All @@ -67,6 +73,14 @@ def decode(self):
v = self.__read_token()
if len(self.value_stack) == 0:
return v

def __seek_back(self, size):
self.fd.seek(self.fd.tell()-size, 0)

def __read_and_back(self, size):
s = self.fd.read(size)
self.__seek_back(size)
return s

def __get_type_from_char(self, c):
"""return a tuple of type information
Expand All @@ -86,15 +100,18 @@ def __get_type_from_char(self, c):
elif c == '"':
return ("string", False, None)
elif c == '#':
return ("set", True, "}")
if self.__read_and_back(1) == '{':
return ("set", True, "}")
if self.__read_and_back(4) == 'inst':
return ("datetime", False, None)
elif c == '{':
return ("dict", True, "}")
elif c == '(':
return ("list", True, ")")
elif c == '[':
return ('list', True, "]")
else:
return (None, False, None)

return (None, False, None)

def __read_fd(self, size):
if size == 1:
Expand Down Expand Up @@ -178,7 +195,7 @@ def __read_token(self):
## [23[12]]
## this is a valid clojure form
if e in _COLL_OPEN_CHARS:
self.fd.seek(-1, os.SEEK_CUR)
self.__seek_back(1)

elif t == "keyword":
buf = [] ##skip the leading ":"
Expand All @@ -200,6 +217,18 @@ def __read_token(self):
e = c
#v = u''.join(buf).decode('unicode-escape')
v = ''.join(buf).decode('string-escape')

elif t == "datetime":
## skip "inst"
self.__read_fd(4)

## read next value as string
s = self.__read_token()
if not isinstance(s, str):
raise ValueError('Str expected, but got %s' % str(s))
e = '"'
v = pyrfc3339.parse(s)

else:
if c not in _COLL_CLOSE_CHARS:
raise ValueError('Unexpected char: "%s" at line %d, col %d' % (c, self.cur_line, self.cur_pos))
Expand Down Expand Up @@ -253,6 +282,8 @@ def get_type(self,t):
return ("list", True)
elif isinstance(t, set):
return ("set", True)
elif isinstance(t, datetime):
return ("datetime", False)
else:
return ("unknown", False)

Expand Down Expand Up @@ -306,6 +337,13 @@ def __do_encode(self, d):
fd.write('false')
elif t == 'None':
fd.write('nil')
elif t == 'datetime':
s = d.strftime("%Y-%m-%dT%H:%M:%S%z")
if not d.tzinfo:
## replace naive datetime
d = d.replace(tzinfo=pytz.utc)
s = pyrfc3339.generate(d)
fd.write("#inst \"%s\"" % s)
else:
fd.write('"'+str(d)+'"')

Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
long_desc=open('README.rst','r').read()

setup(name="pyclj",
version="0.1.9.1",
version="0.2.0",
author="Sun Ning",
author_email="sunng@about.me",
description="clojure literal reader and writer for python",
long_description=long_desc,
url="http://github.com/sunng87/pyclj",
install_requires=["pyRFC3339"],
license='mit',
py_modules=['clj'],
classifiers=['Development Status :: 4 - Beta',
Expand Down
8 changes: 6 additions & 2 deletions tests/clj-test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import unittest
import clj
import pytz
from datetime import datetime

class CljLoadTest(unittest.TestCase):
def setUp(self):
Expand All @@ -24,7 +26,8 @@ def setUp(self):
"{:a [1 2 3] :b #{23.1 43.1 33.1}}": {"a":[1,2,3], "b":set([23.1,43.1,33.1])},
"{:a 1 :b [32 32 43] :c 4}": {"a":1,"b":[32,32,43],"c":4},
"\\你": "你",
"[23[34][32][4]]": [23,[34],[32],[4]]}
"[23[34][32][4]]": [23,[34],[32],[4]],
"#inst \"2012-10-19T22:19:03.000-00:00\"": datetime(2012, 10, 19, 22, 19, 3, tzinfo=pytz.utc)}

def test_all_data(self):
for k,v in self.data.items():
Expand Down Expand Up @@ -53,7 +56,8 @@ def setUp(self):
"{}": {},
'{"a" 1 "b" 2}':{"a":1, "b":2},
'#{1}': set([1]),
'["h" nil [1 2 3] {"w" true}]':["h",None,[1,2,3],{"w":True}]
'["h" nil [1 2 3] {"w" true}]':["h",None,[1,2,3],{"w":True}],
'#inst "2012-10-19T14:16:54Z"':datetime(2012,10,19,14,16,54,907)
}

def test_all_data(self):
Expand Down

0 comments on commit 1a5a002

Please sign in to comment.