def dehydrate_datetime(value): """ Dehydrator for `datetime` values. :param value: :type value: datetime :return: """ def seconds_and_nanoseconds(dt): if isinstance(dt, datetime): dt = DateTime.from_native(dt) zone_epoch = DateTime(1970, 1, 1, tzinfo=dt.tzinfo) t = dt.to_clock_time() - zone_epoch.to_clock_time() return t.seconds, t.nanoseconds tz = value.tzinfo if tz is None: # without time zone value = utc.localize(value) seconds, nanoseconds = seconds_and_nanoseconds(value) return Structure(b"d", seconds, nanoseconds) elif hasattr(tz, "zone") and tz.zone: # with named time zone seconds, nanoseconds = seconds_and_nanoseconds(value) return Structure(b"f", seconds, nanoseconds, tz.zone) else: # with time offset seconds, nanoseconds = seconds_and_nanoseconds(value) return Structure(b"F", seconds, nanoseconds, tz.utcoffset(value).seconds)
def dehydrate_point(value): """ Dehydrator for Point data. :param value: :type value: Point :return: """ dim = len(value) if dim == 2: return Structure(b"X", value.srid, *value) elif dim == 3: return Structure(b"Y", value.srid, *value) else: raise ValueError("Cannot dehydrate Point with %d dimensions" % dim)
def assertion(data, _): assert data == [[ Structure(b"R", data[0][0][0], data[0][1], data[0][2], "KNOWS", {"since": 1999}), data[0][1], data[0][2], ]]
def test_can_hydrate_node_structure(self): struct = Structure(b'N', 123, ["Person"], {"name": "Alice"}) alice, = self.hydrant.hydrate([struct]) self.assertEqual(alice.id, 123) self.assertEqual(alice.labels, {"Person"}) self.assertEqual(set(alice.keys()), {"name"}) self.assertEqual(alice.get("name"), "Alice")
def dehydrate_date(value): """ Dehydrator for `date` values. :param value: :type value: Date :return: """ return Structure(b"D", value.toordinal() - UNIX_EPOCH_DATE.toordinal())
def test_can_hydrate_date_time_structure(self): struct = Structure(b'd', 1539344261, 474716862) dt, = self.hydrant.hydrate([struct]) self.assertEqual(dt.year, 2018) self.assertEqual(dt.month, 10) self.assertEqual(dt.day, 12) self.assertEqual(dt.hour, 11) self.assertEqual(dt.minute, 37) self.assertEqual(dt.second, 41.474716862)
def test_can_hydrate_in_dict(self): struct = Structure(b'N', 123, ["Person"], {"name": "Alice"}) alice_in_dict, = self.hydrant.hydrate([{"foo": struct}]) self.assertIsInstance(alice_in_dict, dict) alice = alice_in_dict["foo"] self.assertEqual(alice.id, 123) self.assertEqual(alice.labels, {"Person"}) self.assertEqual(set(alice.keys()), {"name"}) self.assertEqual(alice.get("name"), "Alice")
def test_can_hydrate_in_list(self): struct = Structure(b'N', 123, ["Person"], {"name": "Alice"}) alice_in_list, = self.hydrant.hydrate([[struct]]) self.assertIsInstance(alice_in_list, list) alice, = alice_in_list self.assertEqual(alice.id, 123) self.assertEqual(alice.labels, {"Person"}) self.assertEqual(set(alice.keys()), {"name"}) self.assertEqual(alice.get("name"), "Alice")
def test_relationship(self): self._test( "CREATE (a)-[r:KNOWS {since:1999}]->(b) RETURN r, id(a), id(b)", {}, lambda d, m: self.assertEqual(d, [[ Structure(b"R", d[0][0][0], d[0][1], d[0][2], "KNOWS", {"since": 1999}), d[0][1], d[0][2], ]]))
def dehydrate_duration(value): """ Dehydrator for `duration` values. :param value: :type value: Duration :return: """ return Structure(b"E", value.months, value.days, value.seconds, int(1000000000 * value.subseconds))
def dehydrate_time(value): """ Dehydrator for `time` values. :param value: :type value: Time :return: """ if isinstance(value, Time): nanoseconds = int(value.ticks * 1000000000) elif isinstance(value, time): nanoseconds = (3600000000000 * value.hour + 60000000000 * value.minute + 1000000000 * value.second + 1000 * value.microsecond) else: raise TypeError("Value must be a neotime.Time or a datetime.time") if value.tzinfo: return Structure(b"T", nanoseconds, value.tzinfo.utcoffset(value).seconds) else: return Structure(b"t", nanoseconds)
def dehydrate_timedelta(value): """ Dehydrator for `timedelta` values. :param value: :type value: timedelta :return: """ months = 0 days = value.days seconds = value.seconds nanoseconds = 1000 * value.microseconds return Structure(b"E", months, days, seconds, nanoseconds)
def _unpack(self): marker = self.read_u8() if marker == -1: raise ValueError("Nothing to unpack") # Tiny Integer if 0x00 <= marker <= 0x7F: return marker elif 0xF0 <= marker <= 0xFF: return marker - 0x100 # Null elif marker == 0xC0: return None # Float elif marker == 0xC1: value, = struct_unpack(">d", self.read(8)) return value # Boolean elif marker == 0xC2: return False elif marker == 0xC3: return True # Integer elif marker == 0xC8: return struct_unpack(">b", self.read(1))[0] elif marker == 0xC9: return struct_unpack(">h", self.read(2))[0] elif marker == 0xCA: return struct_unpack(">i", self.read(4))[0] elif marker == 0xCB: return struct_unpack(">q", self.read(8))[0] # Bytes elif marker == 0xCC: size, = struct_unpack(">B", self.read(1)) return self.read(size).tobytes() elif marker == 0xCD: size, = struct_unpack(">H", self.read(2)) return self.read(size).tobytes() elif marker == 0xCE: size, = struct_unpack(">I", self.read(4)) return self.read(size).tobytes() else: marker_high = marker & 0xF0 # String if marker_high == 0x80: # TINY_STRING return decode(self.read(marker & 0x0F), "utf-8") elif marker == 0xD0: # STRING_8: size, = struct_unpack(">B", self.read(1)) return decode(self.read(size), "utf-8") elif marker == 0xD1: # STRING_16: size, = struct_unpack(">H", self.read(2)) return decode(self.read(size), "utf-8") elif marker == 0xD2: # STRING_32: size, = struct_unpack(">I", self.read(4)) return decode(self.read(size), "utf-8") # List elif 0x90 <= marker <= 0x9F or 0xD4 <= marker <= 0xD7: return list(self._unpack_list_items(marker)) # Map elif 0xA0 <= marker <= 0xAF or 0xD8 <= marker <= 0xDB: return self._unpack_map(marker) # Structure elif 0xB0 <= marker <= 0xBF or 0xDC <= marker <= 0xDD: size, tag = self._unpack_structure_header(marker) value = Structure(tag, *([None] * size)) for i in range(len(value)): value[i] = self._unpack() return value elif marker == 0xDF: # END_OF_STREAM: return EndOfStream else: raise ValueError("Unknown PackStream marker %02X" % marker)
def test_hydrating_unknown_structure_returns_same(self): struct = Structure(b'?', "foo") mystery, = self.hydrant.hydrate([struct]) self.assertEqual(mystery, struct)
def assertion(data, _): assert data == [[ Structure(b"N", data[0][0][0], ["Person"], {"name": "Alice"}), ]]
def test_tiny_struct(self): self.assert_packable(Structure(b"Z", u"A", 1), b"\xB2Z\x81A\x01")
def test_empty_struct(self): self.assert_packable(Structure(b"X"), b"\xB0X")
def test_illegal_signature(self): with self.assertRaises(ValueError): self.assert_packable(Structure(b"XXX"), b"\xB0XXX")
def test_node(self): self._test( "CREATE (a:Person {name:'Alice'}) RETURN a", {}, lambda d, m: self.assertEqual(d, [[ Structure(b"N", d[0][0][0], ["Person"], {"name": "Alice"}), ]]))