flow.record 3.21.dev14__tar.gz → 3.21.dev15__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 (96) hide show
  1. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/PKG-INFO +1 -1
  2. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/tools/rdump.py +25 -37
  3. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/version.py +3 -3
  4. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/PKG-INFO +1 -1
  5. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/tools/test_rdump.py +35 -0
  6. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/.git-blame-ignore-revs +0 -0
  7. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/.gitattributes +0 -0
  8. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/COPYRIGHT +0 -0
  9. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/LICENSE +0 -0
  10. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/MANIFEST.in +0 -0
  11. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/README.md +0 -0
  12. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/__init__.py +0 -0
  13. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/filesystem.py +0 -0
  14. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/passivedns.py +0 -0
  15. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/records.json +0 -0
  16. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/selectors.py +0 -0
  17. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/examples/tcpconn.py +0 -0
  18. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/__init__.py +0 -0
  19. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/__init__.py +0 -0
  20. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/archive.py +0 -0
  21. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/avro.py +0 -0
  22. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/broker.py +0 -0
  23. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/csvfile.py +0 -0
  24. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/duckdb.py +0 -0
  25. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/elastic.py +0 -0
  26. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/jsonfile.py +0 -0
  27. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/line.py +0 -0
  28. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/mongo.py +0 -0
  29. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/split.py +0 -0
  30. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/splunk.py +0 -0
  31. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/sqlite.py +0 -0
  32. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/stream.py +0 -0
  33. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/text.py +0 -0
  34. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/adapter/xlsx.py +0 -0
  35. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/base.py +0 -0
  36. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/context.py +0 -0
  37. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/exceptions.py +0 -0
  38. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/__init__.py +0 -0
  39. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/credential.py +0 -0
  40. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/net/__init__.py +0 -0
  41. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/net/ip.py +0 -0
  42. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/net/ipv4.py +0 -0
  43. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/net/tcp.py +0 -0
  44. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/fieldtypes/net/udp.py +0 -0
  45. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/jsonpacker.py +0 -0
  46. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/packer.py +0 -0
  47. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/selector.py +0 -0
  48. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/stream.py +0 -0
  49. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/tools/__init__.py +0 -0
  50. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/tools/geoip.py +0 -0
  51. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/utils.py +0 -0
  52. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow/record/whitelist.py +0 -0
  53. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/SOURCES.txt +0 -0
  54. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/dependency_links.txt +0 -0
  55. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/entry_points.txt +0 -0
  56. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/requires.txt +0 -0
  57. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/flow.record.egg-info/top_level.txt +0 -0
  58. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/pyproject.toml +0 -0
  59. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/setup.cfg +0 -0
  60. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/__init__.py +0 -0
  61. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/_data/.gitkeep +0 -0
  62. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/_docs/Makefile +0 -0
  63. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/_docs/conf.py +0 -0
  64. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/_docs/index.rst +0 -0
  65. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/_utils.py +0 -0
  66. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/__init__.py +0 -0
  67. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_avro.py +0 -0
  68. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_csv.py +0 -0
  69. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_elastic.py +0 -0
  70. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_json.py +0 -0
  71. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_line.py +0 -0
  72. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_splunk.py +0 -0
  73. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_sqlite_duckdb.py +0 -0
  74. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_text.py +0 -0
  75. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/adapter/test_xlsx.py +0 -0
  76. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/conftest.py +0 -0
  77. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/fieldtypes/__init__.py +0 -0
  78. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/fieldtypes/test_fieldtypes.py +0 -0
  79. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/fieldtypes/test_ip.py +0 -0
  80. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/packer/__init__.py +0 -0
  81. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/packer/test_json_packer.py +0 -0
  82. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/packer/test_packer.py +0 -0
  83. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/__init__.py +0 -0
  84. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/test_adapter.py +0 -0
  85. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/test_context.py +0 -0
  86. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/test_descriptor.py +0 -0
  87. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/test_multi_timestamp.py +0 -0
  88. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/record/test_record.py +0 -0
  89. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/selector/__init__.py +0 -0
  90. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/selector/test_compiled.py +0 -0
  91. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/selector/test_selectors.py +0 -0
  92. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/test_deprecations.py +0 -0
  93. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/test_regressions.py +0 -0
  94. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/test_utils.py +0 -0
  95. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tests/tools/__init__.py +0 -0
  96. {flow_record-3.21.dev14 → flow_record-3.21.dev15}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flow.record
3
- Version: 3.21.dev14
3
+ Version: 3.21.dev15
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
@@ -393,50 +393,38 @@ def main(argv: list[str] | None = None) -> int:
393
393
  ret = 0
394
394
 
395
395
  try:
396
- record_writer = RecordWriter(uri)
397
- for count, rec in enumerate(record_iterator, start=1): # noqa: B007
398
- if args.record_source is not None:
399
- rec._source = args.record_source
400
- if args.record_classification is not None:
401
- rec._classification = args.record_classification
402
- if record_field_rewriter:
403
- rec = record_field_rewriter.rewrite(rec)
404
-
405
- if args.list:
406
- # Dump RecordDescriptors
407
- desc = rec._desc
408
- if desc.descriptor_hash not in seen_desc:
409
- seen_desc.add(desc.descriptor_hash)
410
- print(f"# {desc}")
411
- print(desc.definition())
412
- print()
413
- else:
414
- # Dump Records
415
- if args.multi_timestamp:
416
- for record in iter_timestamped_records(rec):
417
- record_writer.write(record)
396
+ with RecordWriter(uri) as record_writer:
397
+ for count, rec in enumerate(record_iterator, start=1): # noqa: B007
398
+ if args.record_source is not None:
399
+ rec._source = args.record_source
400
+ if args.record_classification is not None:
401
+ rec._classification = args.record_classification
402
+ if record_field_rewriter:
403
+ rec = record_field_rewriter.rewrite(rec)
404
+
405
+ if args.list:
406
+ # Dump RecordDescriptors
407
+ desc = rec._desc
408
+ if desc.descriptor_hash not in seen_desc:
409
+ seen_desc.add(desc.descriptor_hash)
410
+ print(f"# {desc}")
411
+ print(desc.definition())
412
+ print()
418
413
  else:
419
- record_writer.write(rec)
420
-
414
+ # Dump Records
415
+ if args.multi_timestamp:
416
+ for record in iter_timestamped_records(rec):
417
+ record_writer.write(record)
418
+ else:
419
+ record_writer.write(rec)
420
+ except (BrokenPipeError, OSError):
421
+ raise
421
422
  except Exception as e:
422
423
  print_error(e)
423
-
424
- # Prevent throwing an exception twice when deconstructing the record writer.
425
- if hasattr(record_writer, "exception") and record_writer.exception is e:
426
- record_writer.exception = None
427
-
428
424
  ret = 1
429
-
430
425
  finally:
431
426
  if progress_monitor:
432
427
  progress_monitor.stop()
433
- if record_writer:
434
- # Exceptions raised in threads can be thrown when deconstructing the writer.
435
- try:
436
- record_writer.__exit__()
437
- except Exception as e:
438
- print_error(e)
439
- ret = 1
440
428
 
441
429
  if (args.list or args.stats) and not args.progress:
442
430
  stats = f"Processed {ctx.read} records (matched={ctx.matched}, unmatched={ctx.unmatched})"
@@ -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.21.dev14'
32
- __version_tuple__ = version_tuple = (3, 21, 'dev14')
31
+ __version__ = version = '3.21.dev15'
32
+ __version_tuple__ = version_tuple = (3, 21, 'dev15')
33
33
 
34
- __commit_id__ = commit_id = 'gf2606d148'
34
+ __commit_id__ = commit_id = 'ge5a9f567a'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flow.record
3
- Version: 3.21.dev14
3
+ Version: 3.21.dev15
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
@@ -762,3 +762,38 @@ def test_record_rdump_stats(tmp_path: Path, capsys: pytest.CaptureFixture) -> No
762
762
  rdump.main(["--list", "--stats", str(tmp_path / "test.records")])
763
763
  captured = capsys.readouterr()
764
764
  assert "Processed 100 records (matched=100, unmatched=0)" in captured.out
765
+
766
+
767
+ @pytest.mark.skipif(platform.system() == "Windows", reason="skipping this test on Windows")
768
+ def test_rdump_catch_sigpipe(tmp_path: Path) -> None:
769
+ """Test if rdump properly suppresses BrokenPipeError when writing to a closed file handle."""
770
+
771
+ TestRecord = RecordDescriptor(
772
+ "test/record",
773
+ [
774
+ ("varint", "count"),
775
+ ("string", "foo"),
776
+ ],
777
+ )
778
+
779
+ path = tmp_path / "test.records"
780
+ with RecordWriter(path) as writer:
781
+ for i in range(10):
782
+ writer.write(TestRecord(count=i, foo="bar"))
783
+
784
+ # rdump test.records | head -n 2
785
+ proc = subprocess.Popen(
786
+ f"rdump {path} | head -n 2",
787
+ shell=True,
788
+ text=True,
789
+ stderr=subprocess.PIPE,
790
+ stdout=subprocess.PIPE,
791
+ )
792
+
793
+ stdout, stderr = proc.communicate()
794
+ exit_code = proc.wait()
795
+ assert exit_code == 0
796
+ assert stderr == "" # We don't expect any BrokenPipeError
797
+ assert "test/record count=0" in stdout
798
+ assert "test/record count=1" in stdout
799
+ assert len(stdout.splitlines()) == 2