Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
440 lines (426 loc) · 23 KB
/
Copy pathpyproject.toml
File metadata and controls
440 lines (426 loc) · 23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
[build-system]
requires = [
# 69.0.0 is the first release that ships ``pcapkit/py.typed`` unasked
# (pypa/setuptools#3136, in its NEWS.rst): nothing here declares the file, so
# a wheel built with 68.2.2 or older leaves it out and type checkers read the
# package as untyped (#2062). Measured on both sides of the bump. It is also
# above 62.3.0, the floor for ``package-data`` globs that read ``**`` as any
# depth, which the ``pcapkit._extern`` entry below needs (#1814) -- 61.0.0
# and 62.2.0 read it as ``*``, measured. 69.0.0 still
# supports Python 3.8, the ``requires-python`` floor.
"setuptools>=69.0.0",
]
build-backend = "setuptools.build_meta"
[project]
name = "pypcapkit"
# ``readme`` is static (#1968). There is no ``setup.py`` (#2061), so
# ``fetch_project_file`` in Dependabot's Python file fetcher fetches
# ``pyproject.toml`` in its place, and its Pipfile updater writes that file as is:
# only a ``setup.py`` is stubbed. A static ``readme`` keeps the Pipfile's editable
# ``pypcapkit`` from depending on what a stub would supply.
dynamic = [ "version" ]
authors = [
{ name="Jarry Shaw", email="jarryshaw@icloud.com" },
]
maintainers = [
{ name="Jarry Shaw" },
]
license = { text="BSD 3-Clause License" }
# 3.8 is the floor (#2051): the sources use 3.8 syntax (assignment expressions,
# positional-only parameters) and nothing converts them for an older Python, as
# the ``bpc-*`` backport tools are no longer maintained. No upper bound: there is no
# Python 4 for one to exclude, and a cap here is copied into the metadata of
# every project that depends on this one.
#
# CI sorts versions into tiers (#1633), declared in .github/python-versions.toml
# (#1660), which a tier change edits. **3.11 through 3.15** are supported and
# blocking. **3.8 through 3.10** are KTLO: end-of-life, still built and tested,
# never blocking, and a failure there is a warning on a green leg (#1672). The
# ``PCAP_CT`` extra needs 3.10 regardless.
requires-python = ">=3.8"
description = "PyPCAPKit: comprehensive network packet analysis library"
readme = { file = "README.md", content-type = "text/markdown" }
keywords = [ "network", "pcap", "packet" ]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Environment :: MacOS X",
"Environment :: Win32 (MS Windows)",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"Intended Audience :: Science/Research",
"Intended Audience :: System Administrators",
"Intended Audience :: Telecommunications Industry",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
# The supported tier only (#1633). A version classifier is a claim of
# support, which the KTLO tier (3.8-3.10) is by definition not: its tests
# may fail, as a warning that blocks nothing. ``requires-python`` above is
# what keeps those versions installable.
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Security",
"Topic :: System :: Networking",
"Topic :: System :: Networking :: Monitoring",
"Topic :: Utilities",
"Typing :: Typed",
]
dependencies = [
"dictdumper>=0.8.5", # for formatted output -- the floor fixing #772/#1448 upstream
"chardet", # for bytes decode
"aenum", # for const types
"tbtrim>=0.2.1", # for refined exceptions
# version compatibility
"typing-extensions; python_version < '3.11'",
]
[project.urls]
homepage = "https://jarryshaw.github.io/PyPCAPKit/"
documentation = "https://jarryshaw.github.io/PyPCAPKit/"
repository = "https://github.com/JarryShaw/PyPCAPKit"
changelog = "https://jarryshaw.github.io/PyPCAPKit/changelog.html"
[project.scripts]
pcapkit-cli = "pcapkit.__main__:main"
pcapkit-vendor = "pcapkit.vendor.__main__:main"
[project.optional-dependencies]
# for CLI display
cli = [ "emoji" ]
# for ESP payload decryption, c.f. pcapkit.protocols.internet.esp
#
# Capped below 46 on PyPy older than 3.11 (#2040), and nowhere else, which the
# complementary marker on the first line keeps. 45.0.7 is the newest release
# with a manylinux ``pp310`` wheel: 46.0.0 through 46.0.3 ship ``pp310`` wheels
# for macOS x86_64 and Windows only, and 46.0.4 onwards none at all. Without the
# cap, pip on a Linux PyPy 3.10 builds the newest release's sdist, and that
# build stops at PyO3's minimum supported version, 3.11. ``all`` below repeats
# both lines.
crypto = [
"cryptography>=3.4; platform_python_implementation != 'PyPy' or python_version >= '3.11'",
"cryptography>=3.4,<46; platform_python_implementation == 'PyPy' and python_version < '3.11'",
]
# for NGAP decoding, c.f. pcapkit.protocols.application.ngap. Counted among
# ``all``'s *core addons* by the owner's ruling on #910 -- everything needed for
# the library itself to work at full functionality -- even though the
# ``pycrate`` this needs is not a free addition:
#
# * Size. ``pycrate`` ships every specification it has ever compiled in one
# distribution: installing it lands ~238 MB of ``pycrate_asn1dir`` (87 spec
# modules) to obtain the one 4.9 MB ``NGAP.py`` this needs. That is a 50x
# multiplier over the useful part, to support one application protocol.
# * Licence. ``pycrate`` is LGPL-2.1+ where this package is BSD-3-Clause. That
# is fine as an optional import a user chooses, and it is a real thing for
# ``pip install pypcapkit[all]`` to pull in without being asked: LGPL
# carries obligations on redistribution that a BSD-licensed dependent may
# not want.
#
# #910's owner accepted that trade deliberately, over the size and licence
# costs above -- see the ``all`` extra's own comment below for the rest of that
# ruling. This extra
# still exists on its own, for installing NGAP support without the ``cli`` and
# ``crypto`` core addons ``all`` bundles it with.
#
# No version floor: NGAP has shipped precompiled in ``pycrate_asn1dir`` for many
# releases and the entry points used here (``NGAP_PDU.from_aper`` and
# ``to_aper`` among them) are long-standing. Verified against 0.8.1, which is
# pure Python with no compiled extension, so there is no toolchain prerequisite
# either.
NGAP = [ "pycrate" ]
# for normal users
DPKT = [ "dpkt" ]
# The floor is measured, #1572: on scapy 2.5.0 a PCAP-NG interface's
# ``if_tsresol`` is lost after a comment option without a newline, so a
# nanosecond interface reads as microseconds, and ``packet2dict`` reports DNS
# records and field order differently. 2.6.0, the next release, fixes them all.
Scapy = [ "scapy>=2.6.0" ]
PyShark = [ "pyshark" ]
# pypcap ships no wheels, so this compiles a C extension against libpcap and
# needs both its headers and its shared library present; deliberately kept out
# of ``all`` for that reason, c.f. the note below.
#
# The version bound is not caution, it is measured. pypcap 1.3.0 compiles a
# ``pcap.c`` that was pre-generated by Cython 0.29.32 and does not run Cython at
# build time, and that generated file does not compile against the Python 3.12+ C
# API. With libpcap present and found, a real build succeeds on 3.10 and 3.11 and
# fails on 3.12 (``ob_digit``, ``curexc_traceback``) and on 3.14 (those two plus
# ``ma_version_tag`` and the arity of ``_PyLong_AsByteArray``). Without the
# marker pip hands the sdist to a 3.12+ interpreter and the user meets a compiler
# error instead of a resolver message; upstream sets no ``requires_python`` of
# its own, and is unmaintained.
PyPCAP = [ "pypcap; python_version < '3.12'" ]
# ``pcap-ct`` is what covers 3.12+, and it is a *separate extra* rather than a
# complementary marker on ``PyPCAP`` above, for the reasons below, the first
# decisive:
#
# * They are two engines, not one engine with two backends -- ``engine='pypcap'``
# selects ``PyPCAP`` and ``engine='pcap_ct'`` selects ``PCAP_CT``, and
# ``PyPCAP`` refuses to run on pcap-ct rather than mislabel itself. An extra
# whose contents changed with the interpreter would therefore change which
# ``engine=`` string works, under one unchanged extra name.
# * These are pre-releases. Folding them into ``PyPCAP`` would install a beta
# on a newer interpreter for someone who asked for the stable thing, without
# ever saying so.
#
# No compiler and no ``pcap.h`` are needed: both publish ``py3-none-any`` wheels.
# A system libpcap *is* still needed at run time, though -- the ``libpcap``
# distribution ships a vendored ``libpcap.so`` but its published ``libpcap.cfg``
# says ``LIBPCAP = None``, which sends its loader to ``find_library("pcap")``.
# That is a runtime prerequisite rather than a resolution problem, so it is not
# expressible here; the engine detects it and degrades to the default engine
# instead of dying, c.f. ``PCAP_CT.unsupported_reason``.
#
# The pins name a pre-release on purpose. Neither project has ever published a
# stable release, so pip's PEP 440 fallback ("if all versions are
# pre-releases, allow them") means a bare ``pcap-ct`` already resolves without
# ``--pre``; naming the version keeps that from being an accident, floors the
# requirement at the versions actually tested here, and still accepts a future
# stable release, since PEP 440 orders 1.3.0 above 1.3.0b3. ``pcap-ct`` itself
# depends on ``libpcap>=1.11.0b16``; ``libpcap`` is listed anyway because it is
# what supplies the ctypes bindings this engine runs on, and that should not be
# implicit in a transitive dependency.
#
# The ``>= '3.10'`` marker is the same courtesy as the ceilings above, pointing
# the other way. Taken from the wheel metadata rather than guessed: ``pcap-ct``
# 1.3.0b3 declares ``Requires-Python: <4.0.0,>=3.9.0`` and ``libpcap``
# 1.11.0b29 declares ``<4.0.0,>=3.10.0``, so 3.10 is the binding floor. The
# marker is load-bearing rather than decorative, because this project's own
# ``requires-python`` is ``>=3.8`` (see the note above it): without the
# marker, ``pip install pypcapkit[PCAP_CT]`` on a 3.8 or 3.9 interpreter would try
# to resolve two distributions that exclude it and fail the whole install, where
# with it the extra simply resolves to nothing there. CI installs it only in
# engine-tests' PCAP_CT cell, on 3.10 upwards, so the marker excludes none of those.
PCAP_CT = [
"pcap-ct>=1.3.0b3; python_version >= '3.10'",
"libpcap>=1.11.0b29; python_version >= '3.10'",
]
# pypcapfile 0.12.0's ``linklayer`` module imports :mod:`imp`, removed in Python
# 3.12, and ``savefile`` imports ``linklayer`` -- so the package installs cleanly
# and is then unusable there. It does *not* raise when the engine is selected:
# ``Extractor.run`` consults ``PyPCAPFile.unsupported_reason()`` before the import
# test and degrades to the default engine with a warning. That guard exists
# precisely because a bare ``import pcapfile`` succeeds on 3.12+, so an
# import-only check would be satisfied and let the ``ModuleNotFoundError`` escape
# from ``__init__`` instead. Upstream master has fixed it but has not released.
PyPCAPFile = [ "pypcapfile; python_version < '3.12'" ]
# for developers -- installs pcapkit.vendor's crawlers, run via
# `pcapkit-vendor` to regenerate pcapkit.const. Includes ``pycrate`` so
# pcapkit.vendor.ngap's crawlers (#880) can run, and ``requests``/
# ``beautifulsoup4`` for the crawlers that import them at module scope
# (c.f. the ``test`` extra's own comment below for which, and #507). ``all``
# carries core addons only (#910), so this extra names each of them itself
# rather than leaning on ``all`` to also carry them -- ``pycrate`` happens to be
# a core addon in its own right (see the ``all`` extra's comment below), but
# ``requests``/``beautifulsoup4`` are not, and ``dev`` carries them
# instead. Either way, this extra's own requirements are what
# it is correct against, not whatever ``all`` happens to carry.
vendor = [ "requests[socks]", "beautifulsoup4[html5lib]", "pycrate" ]
# #910: *core addons* only -- the owner's ruling scopes this to everything
# needed for the library itself to work at full functionality, rather than
# everything an end user might conceivably want, and draws the line by kind:
# ``cli``, ``crypto`` and ``pycrate`` (NGAP) are core addons, and the 3rd-party
# capture engines -- ``dpkt``, ``scapy``, ``pyshark``, ``pypcapfile`` -- are
# installed one at a time on demand, as ``PyPCAP`` and ``PCAP_CT`` are, from
# their own extras below. Install one explicitly: ``pip install pypcapkit[DPKT]`` /
# ``[Scapy]`` / ``[PyShark]`` / ``[PyPCAPFile]``.
#
# ``pypcap`` and ``pcap-ct``/``libpcap`` stay out for a reason of their own,
# apart from #910's: installability, not desirability.
# ``pypcap`` is an sdist-only C extension that needs a compiler and the libpcap
# development files, and fails where only the header is present -- as on the
# macOS runners. ``pcap-ct`` and ``libpcap`` need no compiler, but are published
# only as pre-releases, and ``all`` should not be how somebody ends up with a
# beta they did not ask for. Install either explicitly: ``pip install
# pypcapkit[PyPCAP]`` or ``pip install pypcapkit[PCAP_CT]``.
#
# The two ``cryptography`` lines are the ``crypto`` extra's, cap included (#2040).
all = [
"emoji",
"cryptography>=3.4; platform_python_implementation != 'PyPy' or python_version >= '3.11'",
"cryptography>=3.4,<46; platform_python_implementation == 'PyPy' and python_version < '3.11'",
"pycrate",
]
# Not for an end user -- for CI, which has a different need entirely: pylint,
# mypy and Sphinx's autodoc all resolve imports against whatever is installed,
# so with ``all`` limited to core addons, every one of
# ``dpkt``/``scapy``/``pyshark``/``pypcapfile`` would be unresolvable to those
# tools. This extra is what a workflow installs *alongside* ``all`` --
# ``.[all,dev]`` -- to see those engines too, for that purpose
# only. ``.github/workflows/lint.yml``'s own comment traces pylint's
# ``import-error`` messages, from ``pypcap``/``pcap-ct`` (via ``PyPCAP`` and
# ``PCAP_CT`` above, both absent on the Python it lints) and from
# ``pypcapfile`` being excluded there by the same marker this extra repeats
# below; this is the extra that keeps those from growing in number,
# and it is not a place to add ``pypcap``/``pcap-ct`` just to silence a
# finding CI has already decided to carry as advisory.
dev = [
# scapy: the same floor as the Scapy extra above, #1572
"dpkt", "scapy>=2.6.0", "pyshark",
# same marker and reasoning as the PyPCAPFile extra above: on 3.12+ the
# package installs cleanly and is then unusable, so
# the marker keeps the resolver from fetching something that could never
# run. It is not guarding against a hard error -- ``Extractor.run`` already
# degrades to the default engine with a warning, installed or not
"pypcapfile; python_version < '3.12'",
"requests[socks]", "beautifulsoup4[html5lib]",
]
docs = [
"Sphinx>=7.3", "furo",
# Pinned to the release ``docs/requirements.txt`` pins, because
# ``docs/source/conf.py`` imports that release's private modules and is
# written against it alone (#1856). tests/project/test_docs_typehints_pin_1856_unit.py
# fails when the pins differ.
"sphinx-autodoc-typehints==3.17.2", "sphinxext-opengraph", "sphinx-copybutton",
"sphinxcontrib-mermaid",
"typing-extensions", "mypy-extensions",
]
test = [
"pytest>=8",
# >=3.6.1, not >=3: the `shouldfail` forwarding tests/conftest.py's xdist fix
# depends on (`WorkerInteractor.pytest_sessionfinish` in xdist/remote.py)
# lands in 3.6.0, which PyPI has yanked, so 3.6.1 is the actual floor.
# Below it the fix silently does nothing and
# test_xdist_run_reports_the_diagnostic_and_fails goes red rather than
# skipped, since `importlib.util.find_spec('xdist')` still succeeds.
"pytest-xdist>=3.6.1",
# A per-test backstop: a hung test fails by name, with every
# thread's stack, instead of running until the job's ``timeout-minutes``
# cancels it with nothing in the log. The value and method live in
# [tool.pytest.ini_options] below. Unpinned, like ``isort`` below, rather
# than inventing a floor (verified against 2.4.0).
"pytest-timeout",
"typing-extensions",
# Enough of the ``vendor`` extra for a test to import a vendor crawler.
# Every ``unit-tests.yml`` install line builds on ``.[test]``, and only the
# whole-suite set on ``latest`` adds ``vendor`` (#1958). Without these, the
# ``ALL``-tier tests that import ``pcapkit.vendor`` behind a ``requests``
# gate would skip on every other leg rather than run: the vendor-template
# checks in ``tests/const/test_const_enum_get.py``,
# ``tests/const/test_const_enum_lookup.py`` and
# ``tests/const/test_const_enum_builtin_parity.py``, and
# ``tests/corekit/test_enum_get_exception_provenance_923_unit.py``, among
# them. ``cron-vendor.yml``'s test gate needs nothing from here: its job
# installs ``.[all,vendor]`` before ``.[test]`` (#1853).
#
# Both are needed, not just ``requests``. ``pcapkit.vendor.default`` imports
# ``requests`` at module scope, and ``pcapkit.vendor.__init__`` then imports
# every crawler unconditionally -- some of which import ``bs4`` at module
# scope. Its ``try: import bs4`` guard suppresses only the warning, not the
# ``ModuleNotFoundError`` that the crawler imports below it raise anyway.
#
# Plain, without the ``vendor`` extra's ``[socks]`` and ``[html5lib]``:
# nothing in the test suite goes through a proxy, and the unit-tier
# test that parses HTML (``tests/vendor/test_ftp_return_code_unit.py``)
# does so from an inline fixture with the ``vendor`` extra's own
# ``html5lib``, not through anything this extra provides, so neither
# parser nor proxy support is reachable from here. Their absence
# makes :mod:`pcapkit.vendor` log ``VendorWarning``s at import, which
# pytest captures and shows only on failure; they change no result. See #507.
"requests",
"beautifulsoup4",
# Same reason as the entries above, for a different test: without it
# ``tests/project/test_isort_clean.py`` skips on every CI leg, so the only
# guard on ``make isort``'s recipe lines -- and on the target-resolving
# globs behind them, wrong more than once (#757, #765, #767) -- runs
# nowhere (#766).
#
# A lint tool in the ``test`` extra rather than in a ``lint`` extra of its
# own, deliberately. ``isort`` is what *this suite* needs in order not to
# skip, which is exactly what this extra is for; a ``lint`` extra would also
# have to carry ``mypy``, ``pylint``, ``bandit`` and ``vermin`` to mean
# anything, and carrying mypy would silently close the ``HAS_MYPY`` gap that
# #779 decided to leave open -- reversing a ruling from an unrelated change.
#
# Unlike the other linters, isort has no CI check of its own to defer
# to: ``.github/workflows/lint.yml`` installs "vermin pylint mypy bandit"
# and says in its own header that isort appears only in
# ``cron-vendor.yml``, as a formatter rather than as a check. Cheap, too --
# a pure-Python wheel, and the recipe lines together measure about 1.5s.
#
# Unpinned, matching ``requests`` and ``beautifulsoup4`` above rather than
# inventing an unmeasured floor (verified against 9.0.1). A future isort
# whose verdict moves therefore turns that test red, which is the intended
# failure: it names the file and prints the diff, where a skip would say
# nothing at all.
"isort",
# The second opinion on the hand-rolled YAML scanners: the ``yaml.safe_load``
# cross-checks under ``tests/project/``, and the tests there that parse a
# workflow with it outright, skip without it.
# Test-only, as ``pcapkit`` never imports ``yaml``. Unpinned, since
# ``safe_load`` is all they use.
"PyYAML",
# What util/vendor_test_gate.py samples a test run's memory with (#1894),
# here because cron-vendor.yml's gate step installs this extra and nothing
# else. CPython only: PyPI has wheels for every CPython leg, free-threaded
# 3.14t included, and none for PyPy or GraalPy, where the gate falls back to
# ``ps``. Unpinned, like the entries above.
"psutil; platform_python_implementation == 'CPython'",
# What util/update_python_versions.py reads the runner-images README's table
# with (#1894), for the tests under ``tests/project/`` that run it on the
# saved README. A pure-Python wheel; unpinned, like the entries above.
"markdown-it-py",
# The strict XML parser util/ci_timing.py reads JUnit with and
# util/pyshark_encap_map.py reads PDML with (#1894). CPython only, like
# psutil: PyPI has no wheel for GraalPy, nor for PyPy 8.0, which
# setup-python's ``pypy3.11`` is, and the image has no libxml2 headers to
# build one (#1958). The tests that parse skip there, all of them on
# ``latest`` alone, and the scripts do not fall back to a laxer parser.
# Unpinned, like the entries above.
"lxml; platform_python_implementation == 'CPython'",
]
# setuptools specific
[tool.setuptools]
zip-safe = false # We use __file__ in pcapkit/__init__.py, therefore pcapkit isn't zip safe
[tool.setuptools.packages.find]
include = [
"pcapkit*",
]
exclude = [
"test*",
"docs*",
"sample*",
]
# Only the conda recipe creates ``pcapkit/_extern``: ``conda/pypcapkit/build.sh``
# and ``bld.bat`` install the packages ``conda/requirements.txt`` names there,
# then run ``pip install .``, which builds the wheel from the tree. Package
# discovery reaches their modules alone, so every other file -- ``emoji``'s JSON,
# ``chardet``'s models, compiled extensions, each ``dist-info`` -- stays behind
# without this entry (#1814). Elsewhere ``pcapkit._extern`` is no package at all,
# and setuptools ignores these entries without a warning; ``MANIFEST.in`` could not
# do this, since a line naming a missing directory warns in every such build. The
# bytecode ``pip install --target`` compiles stays out, as from any other wheel.
[tool.setuptools.package-data]
"pcapkit._extern" = [ "**/*" ]
[tool.setuptools.exclude-package-data]
"pcapkit._extern" = [ "*.pyc" ]
[tool.setuptools.dynamic]
version = { attr="pcapkit.__version__" }
[tool.pytest.ini_options]
testpaths = [
"tests",
]
python_files = [
"test_*.py",
]
# pytest-timeout. 900s per test is a hang backstop, not a speed limit:
# the slowest test measured locally was 21s (in test_pyshark_encap_map.py), so
# even the 10-15x slowdown seen on CI (315s) leaves it about 3x short, while a
# hang still fails by name well inside the jobs' 45-minute cap. ``thread``, not
# the POSIX default ``signal``: a pending SIGALRM fails
# TimeLimitTests.test_nothing_is_re_armed_when_nothing_was_pending, measured.
# ``thread`` keeps each test's timer for the session, pinning the pcapkit
# generation live when it started, unless tests/conftest.py's
# pytest_timeout_cancel_timer hook drops it.
timeout = 900
timeout_method = "thread"
[tool.coverage.run]
source = [
"pcapkit",
]
branch = true
[tool.coverage.report]
show_missing = true