-
Notifications
You must be signed in to change notification settings - Fork 1
SL-19314: Recast llsd serialization to write to a stream. #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
7f78b62
2dc9497
99f19cb
dc753af
2fce8eb
65c047b
aef973e
02cd015
ca0650a
2bc7c2c
c9d34f2
ba99d6c
2a19caf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -346,21 +346,16 @@ class LLSDNotationFormatter(LLSDBaseFormatter): | |
|
||
See http://wiki.secondlife.com/wiki/LLSD#Notation_Serialization | ||
""" | ||
__slots__ = [] | ||
|
||
def LLSD(self, v): | ||
return self._generate(v.thing) | ||
def UNDEF(self, v): | ||
return b'!' | ||
self.stream.write(b'!') | ||
def BOOLEAN(self, v): | ||
if v: | ||
return b'true' | ||
else: | ||
return b'false' | ||
self.stream.write(b'true' if v else b'false') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naive Q since I'm probably missing a lot of context. These were publicish methods that someone might use to generate fragments of notation format for a value before. Did nobody actually use them for such a purpose because this would break every such use? Should these all be renamed "_" (they're modifying an internal object)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have always assumed that the historical names of these methods were chosen to emphasize the communication between LLSDBaseFormatter and its subclasses. I've never seen any That said, yes, those methods are intended solely for internal use by that class hierarchy. Perhaps they should be prefixed with an underscore. If we're going to break hypothetical consumers, better to break them overtly with |
||
def INTEGER(self, v): | ||
return B("i%d") % v | ||
self.stream.write(B("i%d") % v) | ||
def REAL(self, v): | ||
return B("r%r") % v | ||
self.stream.write(B("r%r") % v) | ||
def UUID(self, v): | ||
# latin-1 is the byte-to-byte encoding, mapping \x00-\xFF -> | ||
# \u0000-\u00FF. It's also the fastest encoding, I believe, from | ||
|
@@ -370,24 +365,42 @@ def UUID(self, v): | |
# error behavior in case someone passes an invalid hex string, with | ||
# things other than 0-9a-fA-F, so that they will fail in the UUID | ||
# decode, rather than with a UnicodeError. | ||
return B("u%s") % str(v).encode('latin-1') | ||
self.stream.writelines([b"u", str(v).encode('latin-1')]) | ||
def BINARY(self, v): | ||
return b'b64"' + base64.b64encode(v).strip() + b'"' | ||
self.stream.writelines([b'b64"', base64.b64encode(v).strip(), b'"']) | ||
|
||
def STRING(self, v): | ||
return B("'%s'") % _str_to_bytes(v).replace(b"\\", b"\\\\").replace(b"'", b"\\'") | ||
self.stream.writelines([b"'", self._esc(v), b"'"]) | ||
def URI(self, v): | ||
return B('l"%s"') % _str_to_bytes(v).replace(b"\\", b"\\\\").replace(b'"', b'\\"') | ||
self.stream.writelines([b'l"', self._esc(v, b'"'), b'"']) | ||
def DATE(self, v): | ||
return B('d"%s"') % _format_datestr(v) | ||
self.stream.writelines([b'd"', _format_datestr(v), b'"']) | ||
def ARRAY(self, v): | ||
return B("[%s]") % b','.join([self._generate(item) for item in v]) | ||
self.stream.write(b'[') | ||
delim = b'' | ||
for item in v: | ||
self.stream.write(delim) | ||
self._generate(item) | ||
delim = b',' | ||
self.stream.write(b']') | ||
def MAP(self, v): | ||
return B("{%s}") % b','.join([B("'%s':%s") % (_str_to_bytes(UnicodeType(key)).replace(b"\\", b"\\\\").replace(b"'", b"\\'"), self._generate(value)) | ||
for key, value in v.items()]) | ||
self.stream.write(b'{') | ||
delim = b'' | ||
for key, value in v.items(): | ||
self.stream.writelines([delim, b"'", self._esc(UnicodeType(key)), b"':"]) | ||
self._generate(value) | ||
delim = b',' | ||
self.stream.write(b'}') | ||
|
||
def _esc(self, data, quote=b"'"): | ||
return _str_to_bytes(data).replace(b"\\", b"\\\\").replace(quote, b'\\'+quote) | ||
|
||
def _generate(self, something): | ||
"Generate notation from a single python object." | ||
""" | ||
Serialize a python object to self.stream as application/llsd+notation | ||
|
||
:param something: a python object (typically a dict) to be serialized. | ||
""" | ||
t = type(something) | ||
handler = self.type_map.get(t) | ||
if handler: | ||
|
@@ -401,14 +414,8 @@ def _generate(self, something): | |
raise LLSDSerializationError( | ||
"Cannot serialize unknown type: %s (%s)" % (t, something)) | ||
|
||
def format(self, something): | ||
""" | ||
Format a python object as application/llsd+notation | ||
|
||
:param something: a python object (typically a dict) to be serialized. | ||
:returns: Returns a LLSD notation formatted string. | ||
""" | ||
return self._generate(something) | ||
# _write() method is an alias for _generate() | ||
_write = _generate | ||
|
||
|
||
def format_notation(something): | ||
|
@@ -423,6 +430,32 @@ def format_notation(something): | |
return LLSDNotationFormatter().format(something) | ||
|
||
|
||
def write_notation(stream, something): | ||
""" | ||
Serialize to passed binary 'stream' a python object 'something' as | ||
application/llsd+notation. | ||
|
||
:param stream: a binary stream open for writing. | ||
:param something: a python object (typically a dict) to be serialized. | ||
|
||
See http://wiki.secondlife.com/wiki/LLSD#Notation_Serialization | ||
""" | ||
return LLSDNotationFormatter().write(stream, something) | ||
|
||
|
||
def write_notation(stream, something): | ||
""" | ||
Serialize to passed binary 'stream' a python object 'something' as | ||
application/llsd+notation. | ||
|
||
:param stream: a binary stream open for writing. | ||
:param something: a python object (typically a dict) to be serialized. | ||
|
||
See http://wiki.secondlife.com/wiki/LLSD#Notation_Serialization | ||
""" | ||
return LLSDNotationFormatter().write(stream, something) | ||
|
||
|
||
Comment on lines
+433
to
+445
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did this code get duplicated? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why yes! git is good, but clearly not perfect. |
||
def parse_notation(something): | ||
""" | ||
This is the basic public interface for parsing llsd+notation. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only thing this definition binds is 'stream' which is a reference and so is really just an argument. A single 'def _format_list(stream, something):' at the same level is better, yes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is. Of course I inherited that nested definition from older code, but it's a change worth making.