flow.record 3.22.dev9__tar.gz → 3.22.dev10__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.
Files changed (97) hide show
  1. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/PKG-INFO +1 -1
  2. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/__init__.py +1 -0
  3. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/version.py +3 -3
  4. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/PKG-INFO +1 -1
  5. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/fieldtypes/test_fieldtypes.py +81 -1
  6. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/.git-blame-ignore-revs +0 -0
  7. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/.gitattributes +0 -0
  8. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/COPYRIGHT +0 -0
  9. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/LICENSE +0 -0
  10. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/MANIFEST.in +0 -0
  11. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/README.md +0 -0
  12. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/__init__.py +0 -0
  13. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/filesystem.py +0 -0
  14. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/passivedns.py +0 -0
  15. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/records.json +0 -0
  16. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/selectors.py +0 -0
  17. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/examples/tcpconn.py +0 -0
  18. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/__init__.py +0 -0
  19. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/__init__.py +0 -0
  20. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/archive.py +0 -0
  21. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/avro.py +0 -0
  22. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/broker.py +0 -0
  23. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/csvfile.py +0 -0
  24. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/duckdb.py +0 -0
  25. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/elastic.py +0 -0
  26. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/jsonfile.py +0 -0
  27. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/line.py +0 -0
  28. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/mongo.py +0 -0
  29. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/split.py +0 -0
  30. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/splunk.py +0 -0
  31. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/sqlite.py +0 -0
  32. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/stream.py +0 -0
  33. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/text.py +0 -0
  34. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/adapter/xlsx.py +0 -0
  35. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/base.py +0 -0
  36. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/context.py +0 -0
  37. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/exceptions.py +0 -0
  38. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/credential.py +0 -0
  39. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/net/__init__.py +0 -0
  40. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/net/ip.py +0 -0
  41. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/net/ipv4.py +0 -0
  42. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/net/tcp.py +0 -0
  43. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/fieldtypes/net/udp.py +0 -0
  44. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/jsonpacker.py +0 -0
  45. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/packer.py +0 -0
  46. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/selector.py +0 -0
  47. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/stream.py +0 -0
  48. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/tools/__init__.py +0 -0
  49. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/tools/geoip.py +0 -0
  50. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/tools/rdump.py +0 -0
  51. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/utils.py +0 -0
  52. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow/record/whitelist.py +0 -0
  53. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/SOURCES.txt +0 -0
  54. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/dependency_links.txt +0 -0
  55. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/entry_points.txt +0 -0
  56. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/requires.txt +0 -0
  57. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/flow.record.egg-info/top_level.txt +0 -0
  58. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/pyproject.toml +0 -0
  59. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/setup.cfg +0 -0
  60. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/__init__.py +0 -0
  61. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/_data/.gitkeep +0 -0
  62. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/_docs/Makefile +0 -0
  63. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/_docs/conf.py +0 -0
  64. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/_docs/index.rst +0 -0
  65. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/_utils.py +0 -0
  66. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/__init__.py +0 -0
  67. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_avro.py +0 -0
  68. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_csv.py +0 -0
  69. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_elastic.py +0 -0
  70. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_json.py +0 -0
  71. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_line.py +0 -0
  72. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_splunk.py +0 -0
  73. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_sqlite_duckdb.py +0 -0
  74. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_text.py +0 -0
  75. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/adapter/test_xlsx.py +0 -0
  76. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/conftest.py +0 -0
  77. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/fieldtypes/__init__.py +0 -0
  78. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/fieldtypes/test_boolean.py +0 -0
  79. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/fieldtypes/test_ip.py +0 -0
  80. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/packer/__init__.py +0 -0
  81. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/packer/test_json_packer.py +0 -0
  82. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/packer/test_packer.py +0 -0
  83. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/__init__.py +0 -0
  84. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/test_adapter.py +0 -0
  85. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/test_context.py +0 -0
  86. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/test_descriptor.py +0 -0
  87. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/test_multi_timestamp.py +0 -0
  88. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/record/test_record.py +0 -0
  89. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/selector/__init__.py +0 -0
  90. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/selector/test_compiled.py +0 -0
  91. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/selector/test_selectors.py +0 -0
  92. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/test_deprecations.py +0 -0
  93. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/test_regressions.py +0 -0
  94. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/test_utils.py +0 -0
  95. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/tools/__init__.py +0 -0
  96. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tests/tools/test_rdump.py +0 -0
  97. {flow_record-3.22.dev9 → flow_record-3.22.dev10}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flow.record
3
- Version: 3.22.dev9
3
+ Version: 3.22.dev10
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
@@ -308,6 +308,7 @@ class datetime(_dt, FieldType):
308
308
  arg.second,
309
309
  arg.microsecond,
310
310
  tzinfo,
311
+ fold=arg.fold,
311
312
  )
312
313
  else:
313
314
  obj = _dt.__new__(cls, *args, **kwargs)
@@ -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.dev9'
32
- __version_tuple__ = version_tuple = (3, 22, 'dev9')
31
+ __version__ = version = '3.22.dev10'
32
+ __version_tuple__ = version_tuple = (3, 22, 'dev10')
33
33
 
34
- __commit_id__ = commit_id = 'ga30f10d5d'
34
+ __commit_id__ = commit_id = 'ga594c193b'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flow.record
3
- Version: 3.22.dev9
3
+ Version: 3.22.dev10
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
@@ -13,6 +13,7 @@ import pytest
13
13
  import flow.record.fieldtypes
14
14
  from flow.record import RecordDescriptor, RecordReader, RecordWriter, fieldtypes
15
15
  from flow.record.fieldtypes import (
16
+ HAS_ZONE_INFO,
16
17
  PY_312_OR_HIGHER,
17
18
  PY_313_OR_HIGHER,
18
19
  TYPE_POSIX,
@@ -28,6 +29,9 @@ from flow.record.fieldtypes import (
28
29
  )
29
30
  from flow.record.fieldtypes import datetime as dt
30
31
 
32
+ if HAS_ZONE_INFO:
33
+ from flow.record.fieldtypes import ZoneInfo
34
+
31
35
  if TYPE_CHECKING:
32
36
  from collections.abc import Callable
33
37
 
@@ -427,7 +431,7 @@ def test_datetime() -> None:
427
431
  ("2006-11-10T14:29:55.585192699999999-07:00", datetime(2006, 11, 10, 21, 29, 55, 585192, tzinfo=UTC)),
428
432
  ],
429
433
  )
430
- def test_datetime_formats(tmp_path: pathlib.Path, value: str, expected_dt: datetime) -> None:
434
+ def test_datetime_formats(tmp_path: pathlib.Path, value: str | datetime | float, expected_dt: datetime) -> None:
431
435
  TestRecord = RecordDescriptor(
432
436
  "test/datetime",
433
437
  [
@@ -448,6 +452,82 @@ def test_datetime_formats(tmp_path: pathlib.Path, value: str, expected_dt: datet
448
452
  assert record.dt == expected_dt
449
453
 
450
454
 
455
+ DATETIME_FOLD_PARAMS = [
456
+ (datetime(2023, 1, 1, tzinfo=UTC, fold=1), datetime(2023, 1, 1, tzinfo=UTC)),
457
+ ]
458
+ if HAS_ZONE_INFO:
459
+ DATETIME_FOLD_PARAMS.append(
460
+ (
461
+ datetime(2025, 10, 26, 2, 0, 3, tzinfo=ZoneInfo("Europe/Amsterdam"), fold=1),
462
+ datetime(2025, 10, 26, 1, 0, 3, tzinfo=UTC),
463
+ ),
464
+ )
465
+
466
+
467
+ @pytest.mark.skipif(not HAS_ZONE_INFO, reason="ZoneInfo is required for testing datetime fold parameter")
468
+ @pytest.mark.parametrize(("value", "expected_dt"), DATETIME_FOLD_PARAMS)
469
+ def test_datetime_formats_fold(tmp_path: pathlib.Path, value: datetime, expected_dt: datetime) -> None:
470
+ """test whether datetime accepts fold parameters and converts it correctly"""
471
+ TestRecord = RecordDescriptor(
472
+ "test/datetime",
473
+ [
474
+ ("datetime", "dt"),
475
+ ],
476
+ )
477
+ record = TestRecord(dt=value)
478
+ assert record.dt.fold == 1
479
+ assert record.dt.astimezone(UTC) == expected_dt
480
+
481
+ # test packing / serialization of datetime fields
482
+ path = tmp_path / "datetime.records"
483
+ with RecordWriter(path) as writer:
484
+ writer.write(record)
485
+
486
+ # test unpacking / deserialization of datetime fields
487
+ with RecordReader(path) as reader:
488
+ record = next(iter(reader))
489
+ # Need to convert it to UTC specifically as the timezones do not match
490
+ assert record.dt.astimezone(UTC) == expected_dt
491
+
492
+
493
+ @pytest.mark.skipif(not HAS_ZONE_INFO, reason="ZoneInfo is required for testing datetime fold parameter")
494
+ def test_datetime_fold_example() -> None:
495
+ """
496
+ Test datetime fold parameter during daylight saving time changes in the Netherlands, which has a
497
+ timezone offset of +01:00 during wintertime and +02:00 during summertime.
498
+ """
499
+
500
+ TestRecord = RecordDescriptor(
501
+ "test/datetime",
502
+ [
503
+ ("datetime", "dt"),
504
+ ],
505
+ )
506
+
507
+ # 2025-10-26 is the date of the end of daylight saving time in the Netherlands.
508
+ # At 3:00 AM the clock goes back to 2:00 AM, so 2:00 AM occurs twice. The first occurrence has fold=0
509
+ record = TestRecord("2025-10-26T00:00:00+00:00")
510
+ nl_dt = record.dt.astimezone(ZoneInfo("Europe/Amsterdam"))
511
+ assert nl_dt.isoformat() == "2025-10-26T02:00:00+02:00"
512
+ assert nl_dt.hour == 2
513
+ assert nl_dt.fold == 0
514
+
515
+ # test that both datetimes are considered equal when converted to UTC
516
+ record2 = TestRecord(nl_dt)
517
+ assert record.dt.astimezone(UTC) == record2.dt.astimezone(UTC)
518
+
519
+ # wintertime, the clock goes back from 3:00 AM to 2:00 AM, so 2:00 AM occurs twice. The second occurrence has fold=1
520
+ record = TestRecord("2025-10-26T01:00:00+00:00")
521
+ nl_dt = record.dt.astimezone(ZoneInfo("Europe/Amsterdam"))
522
+ assert nl_dt.isoformat() == "2025-10-26T02:00:00+01:00"
523
+ assert nl_dt.hour == 2
524
+ assert nl_dt.fold == 1
525
+
526
+ # test that both datetimes are considered equal when converted to UTC
527
+ record2 = TestRecord(nl_dt)
528
+ assert record.dt.astimezone(UTC) == record2.dt.astimezone(UTC)
529
+
530
+
451
531
  def test_digest() -> None:
452
532
  TestRecord = RecordDescriptor(
453
533
  "test/digest",