flow.record 3.22.dev4__tar.gz → 3.22.dev6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/PKG-INFO +1 -1
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/sqlite.py +5 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/jsonpacker.py +14 -7
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/version.py +3 -3
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/PKG-INFO +1 -1
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/SOURCES.txt +1 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_sqlite_duckdb.py +13 -8
- flow_record-3.22.dev6/tests/fieldtypes/test_boolean.py +35 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/fieldtypes/test_fieldtypes.py +0 -30
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/packer/test_json_packer.py +10 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/.git-blame-ignore-revs +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/.gitattributes +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/COPYRIGHT +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/LICENSE +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/MANIFEST.in +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/README.md +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/filesystem.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/passivedns.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/records.json +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/selectors.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/examples/tcpconn.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/archive.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/avro.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/broker.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/csvfile.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/duckdb.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/elastic.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/jsonfile.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/line.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/mongo.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/split.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/splunk.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/stream.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/text.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/adapter/xlsx.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/base.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/context.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/exceptions.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/credential.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/net/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/net/ip.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/net/ipv4.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/net/tcp.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/fieldtypes/net/udp.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/packer.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/selector.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/stream.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/tools/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/tools/geoip.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/tools/rdump.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/utils.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow/record/whitelist.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/dependency_links.txt +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/entry_points.txt +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/requires.txt +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/flow.record.egg-info/top_level.txt +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/pyproject.toml +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/setup.cfg +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/_data/.gitkeep +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/_docs/Makefile +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/_docs/conf.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/_docs/index.rst +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/_utils.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_avro.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_csv.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_elastic.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_json.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_line.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_splunk.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_text.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/adapter/test_xlsx.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/conftest.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/fieldtypes/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/fieldtypes/test_ip.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/packer/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/packer/test_packer.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/test_adapter.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/test_context.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/test_descriptor.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/test_multi_timestamp.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/record/test_record.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/selector/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/selector/test_compiled.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/selector/test_selectors.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/test_deprecations.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/test_regressions.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/test_utils.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/tools/__init__.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tests/tools/test_rdump.py +0 -0
- {flow_record-3.22.dev4 → flow_record-3.22.dev6}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flow.record
|
|
3
|
-
Version: 3.22.
|
|
3
|
+
Version: 3.22.dev6
|
|
4
4
|
Summary: A library for defining and creating structured data (called records) that can be streamed to disk or piped to other tools that use flow.record
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -204,6 +204,11 @@ class SqliteReader(AbstractReader):
|
|
|
204
204
|
if match_record_with_context(record, selector, ctx):
|
|
205
205
|
yield record
|
|
206
206
|
|
|
207
|
+
def close(self) -> None:
|
|
208
|
+
if self.con:
|
|
209
|
+
self.con.close()
|
|
210
|
+
self.con = None
|
|
211
|
+
|
|
207
212
|
|
|
208
213
|
class SqliteWriter(AbstractWriter):
|
|
209
214
|
"""SQLite writer."""
|
|
@@ -49,12 +49,7 @@ class JsonRecordPacker:
|
|
|
49
49
|
serial["_type"] = "record"
|
|
50
50
|
serial["_recorddescriptor"] = obj._desc.identifier
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
# Boolean field types should be cast to a bool instead of staying ints
|
|
54
|
-
if field_type == "boolean" and isinstance(serial[field_name], int):
|
|
55
|
-
serial[field_name] = bool(serial[field_name])
|
|
56
|
-
|
|
57
|
-
return serial
|
|
52
|
+
return self.convert_basic_types(serial)
|
|
58
53
|
if isinstance(obj, RecordDescriptor):
|
|
59
54
|
return {
|
|
60
55
|
"_type": "recorddescriptor",
|
|
@@ -102,7 +97,19 @@ class JsonRecordPacker:
|
|
|
102
97
|
return RecordDescriptor._unpack(*data)
|
|
103
98
|
return obj
|
|
104
99
|
|
|
105
|
-
def
|
|
100
|
+
def convert_basic_types(self, obj: Any) -> Any:
|
|
101
|
+
"""Explicitly convert some basic types when packing to JSON."""
|
|
102
|
+
if isinstance(obj, fieldtypes.boolean):
|
|
103
|
+
return bool(obj)
|
|
104
|
+
if isinstance(obj, dict):
|
|
105
|
+
return {k: self.convert_basic_types(v) for k, v in obj.items()}
|
|
106
|
+
if isinstance(obj, list):
|
|
107
|
+
return [self.convert_basic_types(item) for item in obj]
|
|
108
|
+
return obj
|
|
109
|
+
|
|
110
|
+
def pack(self, obj: Record | RecordDescriptor | dict) -> str:
|
|
111
|
+
if isinstance(obj, dict):
|
|
112
|
+
obj = self.convert_basic_types(obj)
|
|
106
113
|
return json.dumps(obj, default=self.pack_obj, indent=self.indent)
|
|
107
114
|
|
|
108
115
|
def unpack(self, d: str) -> RecordDescriptor | Record:
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '3.22.
|
|
32
|
-
__version_tuple__ = version_tuple = (3, 22, '
|
|
31
|
+
__version__ = version = '3.22.dev6'
|
|
32
|
+
__version_tuple__ = version_tuple = (3, 22, 'dev6')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g668138538'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flow.record
|
|
3
|
-
Version: 3.22.
|
|
3
|
+
Version: 3.22.dev6
|
|
4
4
|
Summary: A library for defining and creating structured data (called records) that can be streamed to disk or piped to other tools that use flow.record
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import sqlite3
|
|
4
|
+
from contextlib import closing
|
|
4
5
|
from datetime import datetime, timezone
|
|
5
6
|
from typing import TYPE_CHECKING, Any, NamedTuple
|
|
6
7
|
|
|
@@ -136,7 +137,7 @@ def test_write_to_sqlite(tmp_path: Path, count: int, db: Database) -> None:
|
|
|
136
137
|
writer.write(record)
|
|
137
138
|
|
|
138
139
|
record_count = 0
|
|
139
|
-
with db.connector.connect(str(db_path)) as con:
|
|
140
|
+
with closing(db.connector.connect(str(db_path))) as con:
|
|
140
141
|
cursor = con.execute("SELECT COUNT(*) FROM 'test/record'")
|
|
141
142
|
record_count = cursor.fetchone()[0]
|
|
142
143
|
|
|
@@ -157,7 +158,7 @@ def test_read_from_sqlite(tmp_path: Path, db: Database) -> None:
|
|
|
157
158
|
"""Tests basic reading from a SQLite database."""
|
|
158
159
|
# Generate a SQLite database
|
|
159
160
|
db_path = tmp_path / "records.db"
|
|
160
|
-
with db.connector.connect(str(db_path)) as con:
|
|
161
|
+
with closing(db.connector.connect(str(db_path))) as con:
|
|
161
162
|
con.execute(
|
|
162
163
|
"""
|
|
163
164
|
CREATE TABLE 'test/record' (
|
|
@@ -176,6 +177,7 @@ def test_read_from_sqlite(tmp_path: Path, db: Database) -> None:
|
|
|
176
177
|
""",
|
|
177
178
|
(f"record{i}", f"foobar{i}".encode(), dt_isoformat, 3.14 + i),
|
|
178
179
|
)
|
|
180
|
+
con.commit()
|
|
179
181
|
|
|
180
182
|
# Read the SQLite database using flow.record
|
|
181
183
|
with RecordReader(f"{db.scheme}://{db_path}") as reader:
|
|
@@ -251,7 +253,7 @@ def test_write_zero_records(tmp_path: Path, db: Database) -> None:
|
|
|
251
253
|
assert writer
|
|
252
254
|
|
|
253
255
|
# test if it's a valid database
|
|
254
|
-
with db.connector.connect(str(db_path)) as con:
|
|
256
|
+
with closing(db.connector.connect(str(db_path))) as con:
|
|
255
257
|
assert con.execute("SELECT * FROM sqlite_master").fetchall() == []
|
|
256
258
|
|
|
257
259
|
|
|
@@ -272,9 +274,10 @@ def test_write_zero_records(tmp_path: Path, db: Database) -> None:
|
|
|
272
274
|
def test_non_strict_sqlite_fields(tmp_path: Path, sqlite_coltype: str, sqlite_value: Any, expected_value: Any) -> None:
|
|
273
275
|
"""SQLite by default is non strict, meaning that the value could be of different type than the column type."""
|
|
274
276
|
db = tmp_path / "records.db"
|
|
275
|
-
with sqlite3.connect(db) as con:
|
|
277
|
+
with closing(sqlite3.connect(db)) as con:
|
|
276
278
|
con.execute(f"CREATE TABLE 'strict-test' (field {sqlite_coltype})")
|
|
277
279
|
con.execute("INSERT INTO 'strict-test' VALUES(?)", (sqlite_value,))
|
|
280
|
+
con.commit()
|
|
278
281
|
|
|
279
282
|
with RecordReader(f"sqlite://{db}") as reader:
|
|
280
283
|
record = next(iter(reader))
|
|
@@ -294,10 +297,11 @@ def test_invalid_table_names_quoting(tmp_path: Path, invalid_table_name: str) ->
|
|
|
294
297
|
|
|
295
298
|
# Creating the tables with these invalid_table_names in SQLite is no problem
|
|
296
299
|
db = tmp_path / "records.db"
|
|
297
|
-
with sqlite3.connect(db) as con:
|
|
300
|
+
with closing(sqlite3.connect(db)) as con:
|
|
298
301
|
con.execute(f"CREATE TABLE [{invalid_table_name}] (field TEXT, field2 TEXT)")
|
|
299
302
|
con.execute(f"INSERT INTO [{invalid_table_name}] VALUES(?, ?)", ("hello", "world"))
|
|
300
303
|
con.execute(f"INSERT INTO [{invalid_table_name}] VALUES(?, ?)", ("goodbye", "planet"))
|
|
304
|
+
con.commit()
|
|
301
305
|
|
|
302
306
|
# However, these invalid_table_names should raise an exception when reading
|
|
303
307
|
with (
|
|
@@ -320,10 +324,11 @@ def test_invalid_field_names_quoting(tmp_path: Path, invalid_field_name: str) ->
|
|
|
320
324
|
|
|
321
325
|
# Creating the table with invalid field name in SQLite is no problem
|
|
322
326
|
db = tmp_path / "records.db"
|
|
323
|
-
with sqlite3.connect(db) as con:
|
|
327
|
+
with closing(sqlite3.connect(db)) as con:
|
|
324
328
|
con.execute(f"CREATE TABLE [test] (field TEXT, [{invalid_field_name}] TEXT)")
|
|
325
329
|
con.execute("INSERT INTO [test] VALUES(?, ?)", ("hello", "world"))
|
|
326
330
|
con.execute("INSERT INTO [test] VALUES(?, ?)", ("goodbye", "planet"))
|
|
331
|
+
con.commit()
|
|
327
332
|
|
|
328
333
|
# However, these field names are invalid in flow.record and should raise an exception
|
|
329
334
|
with (
|
|
@@ -365,7 +370,7 @@ def test_batch_size(
|
|
|
365
370
|
writer.write(next(records))
|
|
366
371
|
|
|
367
372
|
# test count of records in table (no flush yet if batch_size > 1)
|
|
368
|
-
with db.connector.connect(str(db_path)) as con:
|
|
373
|
+
with closing(db.connector.connect(str(db_path))) as con:
|
|
369
374
|
x = con.execute('SELECT COUNT(*) FROM "test/record"')
|
|
370
375
|
assert x.fetchone()[0] is expected_first
|
|
371
376
|
|
|
@@ -374,7 +379,7 @@ def test_batch_size(
|
|
|
374
379
|
writer.write(next(records))
|
|
375
380
|
|
|
376
381
|
# test count of records in table after flush
|
|
377
|
-
with db.connector.connect(str(db_path)) as con:
|
|
382
|
+
with closing(db.connector.connect(str(db_path))) as con:
|
|
378
383
|
x = con.execute('SELECT COUNT(*) FROM "test/record"')
|
|
379
384
|
assert x.fetchone()[0] == expected_second
|
|
380
385
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from flow.record.base import RecordDescriptor
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_boolean() -> None:
|
|
9
|
+
TestRecord = RecordDescriptor(
|
|
10
|
+
"test/boolean",
|
|
11
|
+
[
|
|
12
|
+
("boolean", "booltrue"),
|
|
13
|
+
("boolean", "boolfalse"),
|
|
14
|
+
],
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
r = TestRecord(True, False)
|
|
18
|
+
assert bool(r.booltrue) is True
|
|
19
|
+
assert bool(r.boolfalse) is False
|
|
20
|
+
|
|
21
|
+
r = TestRecord(1, 0)
|
|
22
|
+
assert bool(r.booltrue) is True
|
|
23
|
+
assert bool(r.boolfalse) is False
|
|
24
|
+
|
|
25
|
+
assert str(r.booltrue) == "True"
|
|
26
|
+
assert str(r.boolfalse) == "False"
|
|
27
|
+
|
|
28
|
+
assert repr(r.booltrue) == "True"
|
|
29
|
+
assert repr(r.boolfalse) == "False"
|
|
30
|
+
|
|
31
|
+
with pytest.raises(ValueError, match="Value not a valid boolean value"):
|
|
32
|
+
TestRecord(2, -1)
|
|
33
|
+
|
|
34
|
+
with pytest.raises(ValueError, match="invalid literal for int"):
|
|
35
|
+
TestRecord("True", "False")
|
|
@@ -293,36 +293,6 @@ def test_dictlist() -> None:
|
|
|
293
293
|
assert r.hits[1]["b"] == 4
|
|
294
294
|
|
|
295
295
|
|
|
296
|
-
def test_boolean() -> None:
|
|
297
|
-
TestRecord = RecordDescriptor(
|
|
298
|
-
"test/boolean",
|
|
299
|
-
[
|
|
300
|
-
("boolean", "booltrue"),
|
|
301
|
-
("boolean", "boolfalse"),
|
|
302
|
-
],
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
r = TestRecord(True, False)
|
|
306
|
-
assert bool(r.booltrue) is True
|
|
307
|
-
assert bool(r.boolfalse) is False
|
|
308
|
-
|
|
309
|
-
r = TestRecord(1, 0)
|
|
310
|
-
assert bool(r.booltrue) is True
|
|
311
|
-
assert bool(r.boolfalse) is False
|
|
312
|
-
|
|
313
|
-
assert str(r.booltrue) == "True"
|
|
314
|
-
assert str(r.boolfalse) == "False"
|
|
315
|
-
|
|
316
|
-
assert repr(r.booltrue) == "True"
|
|
317
|
-
assert repr(r.boolfalse) == "False"
|
|
318
|
-
|
|
319
|
-
with pytest.raises(ValueError, match="Value not a valid boolean value"):
|
|
320
|
-
r = TestRecord(2, -1)
|
|
321
|
-
|
|
322
|
-
with pytest.raises(ValueError, match="invalid literal for int"):
|
|
323
|
-
r = TestRecord("True", "False")
|
|
324
|
-
|
|
325
|
-
|
|
326
296
|
def test_float() -> None:
|
|
327
297
|
TestRecord = RecordDescriptor(
|
|
328
298
|
"test/float",
|
|
@@ -93,6 +93,16 @@ def test_record_pack_bool_regression() -> None:
|
|
|
93
93
|
# pack the json string back to a record and make sure it is the same as before
|
|
94
94
|
assert packer.unpack(data) == record
|
|
95
95
|
|
|
96
|
+
# Make sure the same applies to an OrderedDict, which is how JsonRecordPacker is invoked for
|
|
97
|
+
# the Elastic adapter.
|
|
98
|
+
rdict = record._asdict()
|
|
99
|
+
data = packer.pack(rdict)
|
|
100
|
+
assert data.startswith('{"some_varint": 1, "some_uint": 0, "some_boolean": false, ')
|
|
101
|
+
|
|
102
|
+
# test that packer.pack has no side effects on rdict
|
|
103
|
+
assert rdict == record._asdict()
|
|
104
|
+
assert isinstance(rdict["some_boolean"], fieldtypes.boolean)
|
|
105
|
+
|
|
96
106
|
|
|
97
107
|
def test_record_pack_surrogateescape() -> None:
|
|
98
108
|
TestRecord = RecordDescriptor(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|