Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/source/contributing/conventions/const-vendor-pairing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,24 @@ record-layer header citations, the Unassigned/Reserved band rationale, the
docstrings and comments, the way :mod:`pcapkit.vendor.linux.arphrd` already
does for ARPHRD; the generated ``const`` modules carry only the plain,
templated docstring every other generated module does.

Lazy Package Imports
~~~~~~~~~~~~~~~~~~~~

**A** :mod:`pcapkit.const` **package imports its enumerations on first use**, not with
itself. Ruled by the owner in session and recorded on :issue:`2729`. Its
:file:`__init__.py` names each export in an import under ``if TYPE_CHECKING:``, for
the type checkers, and binds the ``__getattr__`` and ``__dir__`` that
:func:`~pcapkit.utilities.lazy.lazy_exports` returns; :mod:`pcapkit.const` re-exports
its subpackages' ``__all__`` the same way. The one real import is of
:class:`~pcapkit.const.reg.apptype.apptype.AppType` and
:class:`~pcapkit.const.reg.apptype.apptype.TransportProtocol`, which
:mod:`pcapkit.const.reg.apptype` builds
:attr:`AppType.__registries__ <pcapkit.const.reg.apptype.apptype.AppType.__registries__>`
on. A crawler writes the enumeration module and never a package's
:file:`__init__.py`, so regenerating keeps the laziness, and a module a crawler adds
takes its export there by hand, in both places.
:file:`tests/const/test_const_lazy_exports_2729_unit.py` fails on an export imported
outside ``TYPE_CHECKING``, or one that does not resolve to what its import names, and
:file:`tests/const/test_const_apptype_lazy_1538_unit.py` on a package that loads an
enumeration with itself.
5 changes: 3 additions & 2 deletions docs/source/contributing/conventions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ House Conventions
* :ref:`reassembly-integration` -- :mod:`pcapkit.foundation.reassembly` and what a
new engine there needs from :mod:`pcapkit.toolkit` and
:mod:`pcapkit.foundation.analysis`;
* :ref:`const-vendor-pairing` -- :mod:`pcapkit.const` and the
:mod:`pcapkit.vendor` crawler each module needs.
* :ref:`const-vendor-pairing` -- :mod:`pcapkit.const`, the
:mod:`pcapkit.vendor` crawler each module needs, and how a package of it
imports its modules.

**A ruling that stays in its thread is a ruling that gets rediscovered.** So
when a question is answered in a way the code cannot express on its own -- a
Expand Down
4 changes: 3 additions & 1 deletion docs/source/pcapkit/utilities/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ Module Utilities
built with: user-refined exceptions and warnings, logging, the tunable limits
of :mod:`~pcapkit.utilities.config`, a compatibility layer, timestamp
conversion, pickle reductions, the
:mod:`context variables <pcapkit.utilities.contextvars>` its modules share, and
:mod:`context variables <pcapkit.utilities.contextvars>` its modules share,
:mod:`lazy imports <pcapkit.utilities.lazy>` for a package's exports, and
wrappers around third-party libraries. It imports nothing from :mod:`pcapkit`
outside itself; see :ref:`utilities-or-corekit`.

Expand All @@ -23,6 +24,7 @@ outside itself; see :ref:`utilities-or-corekit`.
datetime
pickle
contextvars
lazy

Version Compatibility
=====================
Expand Down
15 changes: 15 additions & 0 deletions docs/source/pcapkit/utilities/lazy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Lazy Imports
============

.. module:: pcapkit.utilities.lazy

:mod:`pcapkit.utilities.lazy` holds :func:`lazy_exports`, which gives a package the
:pep:`562` ``__getattr__`` and ``__dir__`` that import each name it exports the first
time the name is reached, rather than with the package itself. Every package under
:mod:`pcapkit.const` imports its enumerations that way (:issue:`2729`), so a caller
pays only for the enumerations it uses. This module imports nothing from
:mod:`pcapkit`; see :ref:`utilities-or-corekit`.

.. versionadded:: 1.6.0

.. autofunction:: pcapkit.utilities.lazy.lazy_exports
76 changes: 47 additions & 29 deletions pcapkit/const/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,49 @@
This module contains all constant enumerations of :mod:`pcapkit`, which are
automatically generated from the :mod:`pcapkit.vendor` module.

Each enumeration is imported the first time it is reached -- as an attribute
of this package or of the subpackage holding it -- rather than with the
package, through :func:`~pcapkit.utilities.lazy.lazy_exports`
(:issue:`2729`). The subpackages themselves are imported with it, and import
none of their enumerations.

"""
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

# IANA registration
from pcapkit.const.reg import *
if TYPE_CHECKING:
# IANA registration
from pcapkit.const.reg import *

# Miscellaneous
from pcapkit.const.pcapng import *
# Miscellaneous
from pcapkit.const.pcapng import *

# per protocol
from pcapkit.const.arp import *
from pcapkit.const.dccp import *
from pcapkit.const.esp import *
from pcapkit.const.ftp import *
from pcapkit.const.hip import *
from pcapkit.const.http import *
from pcapkit.const.icmp import *
from pcapkit.const.icmpv6 import *
from pcapkit.const.ieee802_11 import *
from pcapkit.const.igmp import *
from pcapkit.const.ipv4 import *
from pcapkit.const.ipv6 import *
from pcapkit.const.ipx import *
from pcapkit.const.l2tp import *
from pcapkit.const.linux import *
from pcapkit.const.mh import *
from pcapkit.const.ngap import *
from pcapkit.const.ospf import *
from pcapkit.const.radiotap import *
from pcapkit.const.sctp import *
from pcapkit.const.sslv2 import *
from pcapkit.const.tcp import *
from pcapkit.const.tls import *
from pcapkit.const.vlan import *
# per protocol
from pcapkit.const.arp import *
from pcapkit.const.dccp import *
from pcapkit.const.esp import *
from pcapkit.const.ftp import *
from pcapkit.const.hip import *
from pcapkit.const.http import *
from pcapkit.const.icmp import *
from pcapkit.const.icmpv6 import *
from pcapkit.const.ieee802_11 import *
from pcapkit.const.igmp import *
from pcapkit.const.ipv4 import *
from pcapkit.const.ipv6 import *
from pcapkit.const.ipx import *
from pcapkit.const.l2tp import *
from pcapkit.const.linux import *
from pcapkit.const.mh import *
from pcapkit.const.ngap import *
from pcapkit.const.ospf import *
from pcapkit.const.radiotap import *
from pcapkit.const.sctp import *
from pcapkit.const.sslv2 import *
from pcapkit.const.tcp import *
from pcapkit.const.tls import *
from pcapkit.const.vlan import *

__all__ = [
# Protocol Registration
Expand Down Expand Up @@ -123,3 +133,11 @@
'PCAPNG_VerdictType', 'PCAPNG_RecordType', 'PCAPNG_SecretsType',
'PCAPNG_FilterType', 'PCAPNG_TLSKeyLabel',
]

# NOTE: the subpackages whose ``__all__`` this package re-exports, which the
# type checkers star-import above.
__getattr__, __dir__ = lazy_exports(__name__, globals(), packages=(
'reg', 'pcapng', 'arp', 'dccp', 'esp', 'ftp', 'hip', 'http', 'icmp', 'icmpv6',
'ieee802_11', 'igmp', 'ipv4', 'ipv6', 'ipx', 'l2tp', 'linux', 'mh', 'ngap', 'ospf',
'radiotap', 'sctp', 'sslv2', 'tcp', 'tls', 'vlan',
))
14 changes: 12 additions & 2 deletions pcapkit/const/arp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,17 @@

"""

from pcapkit.const.arp.hardware import Hardware as ARP_Hardware
from pcapkit.const.arp.operation import Operation as ARP_Operation
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.arp.hardware import Hardware as ARP_Hardware
from pcapkit.const.arp.operation import Operation as ARP_Operation

__all__ = ['ARP_Hardware', 'ARP_Operation']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'ARP_Hardware': ('hardware', 'Hardware'),
'ARP_Operation': ('operation', 'Operation'),
})
26 changes: 20 additions & 6 deletions pcapkit/const/dccp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,26 @@

"""

from pcapkit.const.dccp.ack_vector_state import AckVectorState as DCCP_AckVectorState
from pcapkit.const.dccp.drop_code import DropCode as DCCP_DropCode
from pcapkit.const.dccp.feature import Feature as DCCP_Feature
from pcapkit.const.dccp.option import Option as DCCP_Option
from pcapkit.const.dccp.packet_type import PacketType as DCCP_PacketType
from pcapkit.const.dccp.reset_code import ResetCode as DCCP_ResetCode
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.dccp.ack_vector_state import AckVectorState as DCCP_AckVectorState
from pcapkit.const.dccp.drop_code import DropCode as DCCP_DropCode
from pcapkit.const.dccp.feature import Feature as DCCP_Feature
from pcapkit.const.dccp.option import Option as DCCP_Option
from pcapkit.const.dccp.packet_type import PacketType as DCCP_PacketType
from pcapkit.const.dccp.reset_code import ResetCode as DCCP_ResetCode

__all__ = ['DCCP_PacketType', 'DCCP_ResetCode', 'DCCP_Option', 'DCCP_Feature',
'DCCP_AckVectorState', 'DCCP_DropCode']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'DCCP_PacketType': ('packet_type', 'PacketType'),
'DCCP_ResetCode': ('reset_code', 'ResetCode'),
'DCCP_Option': ('option', 'Option'),
'DCCP_Feature': ('feature', 'Feature'),
'DCCP_AckVectorState': ('ack_vector_state', 'AckVectorState'),
'DCCP_DropCode': ('drop_code', 'DropCode'),
})
14 changes: 12 additions & 2 deletions pcapkit/const/esp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@

"""

from pcapkit.const.esp.cipher import Cipher as ESP_Cipher
from pcapkit.const.esp.integrity import Integrity as ESP_Integrity
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.esp.cipher import Cipher as ESP_Cipher
from pcapkit.const.esp.integrity import Integrity as ESP_Integrity

__all__ = ['ESP_Cipher', 'ESP_Integrity']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'ESP_Cipher': ('cipher', 'Cipher'),
'ESP_Integrity': ('integrity', 'Integrity'),
})
14 changes: 12 additions & 2 deletions pcapkit/const/ftp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,17 @@

"""

from pcapkit.const.ftp.command import Command as FTP_Command
from pcapkit.const.ftp.return_code import ReturnCode as FTP_ReturnCode
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.ftp.command import Command as FTP_Command
from pcapkit.const.ftp.return_code import ReturnCode as FTP_ReturnCode

__all__ = ['FTP_Command', 'FTP_ReturnCode']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'FTP_Command': ('command', 'Command'),
'FTP_ReturnCode': ('return_code', 'ReturnCode'),
})
63 changes: 45 additions & 18 deletions pcapkit/const/hip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,53 @@

"""

from pcapkit.const.hip.certificate import Certificate as HIP_Certificate
from pcapkit.const.hip.cipher import Cipher as HIP_Cipher
from pcapkit.const.hip.di import DITypes as HIP_DITypes
from pcapkit.const.hip.ecdsa_curve import ECDSACurve as HIP_ECDSACurve
from pcapkit.const.hip.ecdsa_low_curve import ECDSALowCurve as HIP_ECDSALowCurve
from pcapkit.const.hip.eddsa_curve import EdDSACurve as HIP_EdDSACurve
from pcapkit.const.hip.esp_transform_suite import ESPTransformSuite as HIP_ESPTransformSuite
from pcapkit.const.hip.group import Group as HIP_Group
from pcapkit.const.hip.hi_algorithm import HIAlgorithm as HIP_HIAlgorithm
from pcapkit.const.hip.hit_suite import HITSuite as HIP_HITSuite
from pcapkit.const.hip.nat_traversal import NATTraversal as HIP_NATTraversal
from pcapkit.const.hip.notify_message import NotifyMessage as HIP_NotifyMessage
from pcapkit.const.hip.packet import Packet as HIP_Packet
from pcapkit.const.hip.parameter import Parameter as HIP_Parameter
from pcapkit.const.hip.registration import Registration as HIP_Registration
from pcapkit.const.hip.registration_failure import RegistrationFailure as HIP_RegistrationFailure
from pcapkit.const.hip.suite import Suite as HIP_Suite
from pcapkit.const.hip.transport import Transport as HIP_Transport
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.hip.certificate import Certificate as HIP_Certificate
from pcapkit.const.hip.cipher import Cipher as HIP_Cipher
from pcapkit.const.hip.di import DITypes as HIP_DITypes
from pcapkit.const.hip.ecdsa_curve import ECDSACurve as HIP_ECDSACurve
from pcapkit.const.hip.ecdsa_low_curve import ECDSALowCurve as HIP_ECDSALowCurve
from pcapkit.const.hip.eddsa_curve import EdDSACurve as HIP_EdDSACurve
from pcapkit.const.hip.esp_transform_suite import ESPTransformSuite as HIP_ESPTransformSuite
from pcapkit.const.hip.group import Group as HIP_Group
from pcapkit.const.hip.hi_algorithm import HIAlgorithm as HIP_HIAlgorithm
from pcapkit.const.hip.hit_suite import HITSuite as HIP_HITSuite
from pcapkit.const.hip.nat_traversal import NATTraversal as HIP_NATTraversal
from pcapkit.const.hip.notify_message import NotifyMessage as HIP_NotifyMessage
from pcapkit.const.hip.packet import Packet as HIP_Packet
from pcapkit.const.hip.parameter import Parameter as HIP_Parameter
from pcapkit.const.hip.registration import Registration as HIP_Registration
from pcapkit.const.hip.registration_failure import \
RegistrationFailure as HIP_RegistrationFailure
from pcapkit.const.hip.suite import Suite as HIP_Suite
from pcapkit.const.hip.transport import Transport as HIP_Transport

__all__ = ['HIP_Certificate', 'HIP_Cipher', 'HIP_DITypes', 'HIP_ECDSACurve', 'HIP_ECDSALowCurve',
'HIP_ESPTransformSuite', 'HIP_Group', 'HIP_HIAlgorithm', 'HIP_HITSuite', 'HIP_NATTraversal',
'HIP_NotifyMessage', 'HIP_Packet', 'HIP_Parameter', 'HIP_Registration', 'HIP_RegistrationFailure',
'HIP_Suite', 'HIP_Transport', 'HIP_EdDSACurve']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'HIP_Certificate': ('certificate', 'Certificate'),
'HIP_Cipher': ('cipher', 'Cipher'),
'HIP_DITypes': ('di', 'DITypes'),
'HIP_ECDSACurve': ('ecdsa_curve', 'ECDSACurve'),
'HIP_ECDSALowCurve': ('ecdsa_low_curve', 'ECDSALowCurve'),
'HIP_ESPTransformSuite': ('esp_transform_suite', 'ESPTransformSuite'),
'HIP_Group': ('group', 'Group'),
'HIP_HIAlgorithm': ('hi_algorithm', 'HIAlgorithm'),
'HIP_HITSuite': ('hit_suite', 'HITSuite'),
'HIP_NATTraversal': ('nat_traversal', 'NATTraversal'),
'HIP_NotifyMessage': ('notify_message', 'NotifyMessage'),
'HIP_Packet': ('packet', 'Packet'),
'HIP_Parameter': ('parameter', 'Parameter'),
'HIP_Registration': ('registration', 'Registration'),
'HIP_RegistrationFailure': ('registration_failure', 'RegistrationFailure'),
'HIP_Suite': ('suite', 'Suite'),
'HIP_Transport': ('transport', 'Transport'),
'HIP_EdDSACurve': ('eddsa_curve', 'EdDSACurve'),
})
23 changes: 18 additions & 5 deletions pcapkit/const/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,23 @@

"""

from pcapkit.const.http.error_code import ErrorCode as HTTP_ErrorCode
from pcapkit.const.http.frame import Frame as HTTP_Frame
from pcapkit.const.http.method import Method as HTTP_Method
from pcapkit.const.http.setting import Setting as HTTP_Setting
from pcapkit.const.http.status_code import StatusCode as HTTP_Status
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.http.error_code import ErrorCode as HTTP_ErrorCode
from pcapkit.const.http.frame import Frame as HTTP_Frame
from pcapkit.const.http.method import Method as HTTP_Method
from pcapkit.const.http.setting import Setting as HTTP_Setting
from pcapkit.const.http.status_code import StatusCode as HTTP_Status

__all__ = ['HTTP_ErrorCode', 'HTTP_Frame', 'HTTP_Method', 'HTTP_Setting', 'HTTP_Status']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'HTTP_ErrorCode': ('error_code', 'ErrorCode'),
'HTTP_Frame': ('frame', 'Frame'),
'HTTP_Method': ('method', 'Method'),
'HTTP_Setting': ('setting', 'Setting'),
'HTTP_Status': ('status_code', 'StatusCode'),
})
24 changes: 18 additions & 6 deletions pcapkit/const/icmp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,26 @@

"""

from pcapkit.const.icmp.destination_unreachable_code import \
DestinationUnreachableCode as ICMP_DestinationUnreachableCode
from pcapkit.const.icmp.parameter_problem_code import \
ParameterProblemCode as ICMP_ParameterProblemCode
from pcapkit.const.icmp.time_exceeded_code import TimeExceededCode as ICMP_TimeExceededCode
from pcapkit.const.icmp.type import Type as ICMP_Type
from typing import TYPE_CHECKING

from pcapkit.utilities.lazy import lazy_exports

if TYPE_CHECKING:
from pcapkit.const.icmp.destination_unreachable_code import \
DestinationUnreachableCode as ICMP_DestinationUnreachableCode
from pcapkit.const.icmp.parameter_problem_code import \
ParameterProblemCode as ICMP_ParameterProblemCode
from pcapkit.const.icmp.time_exceeded_code import TimeExceededCode as ICMP_TimeExceededCode
from pcapkit.const.icmp.type import Type as ICMP_Type

__all__ = [
'ICMP_Type',
'ICMP_DestinationUnreachableCode', 'ICMP_TimeExceededCode', 'ICMP_ParameterProblemCode',
]

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
'ICMP_Type': ('type', 'Type'),
'ICMP_DestinationUnreachableCode': ('destination_unreachable_code', 'DestinationUnreachableCode'),
'ICMP_TimeExceededCode': ('time_exceeded_code', 'TimeExceededCode'),
'ICMP_ParameterProblemCode': ('parameter_problem_code', 'ParameterProblemCode'),
})
Loading
Loading