fields: preserve containers when copying fields#5009
Conversation
AI-Assisted: yes (Codex)
eac2ff2 to
159afb7
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5009 +/- ##
==========================================
- Coverage 80.31% 80.04% -0.28%
==========================================
Files 381 384 +3
Lines 93630 95658 +2028
==========================================
+ Hits 75202 76565 +1363
- Misses 18428 19093 +665
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a longstanding copy bug for _FieldContainer wrappers (e.g., Emph) so that copying preserves the container type rather than collapsing to the wrapped field—particularly impacting Packet_metaclass default-replacement when fields_desc references another packet (issue #4657).
Changes:
- Add
_FieldContainer.copy()to return a copied container instance (including copying its stored attributes/slots). - Add
_FieldContainer.__setattr__()to delegate unsupported attribute assignment to the wrapped field (mirroring existing read delegation). - Add regression tests covering
Emph(...).copy()and the packet-metaclass copy/default override path.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
scapy/fields.py |
Implements _FieldContainer.copy() and adds write-delegation via __setattr__ to preserve wrappers during copy/default replacement. |
test/fields.uts |
Adds regression coverage for direct container .copy() and packet metaclass field-copy behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def __setattr__(self, attr, value): | ||
| # type: (str, Any) -> None | ||
| try: | ||
| object.__setattr__(self, attr, value) | ||
| except AttributeError as ex: | ||
| try: | ||
| fld = object.__getattribute__(self, "fld") | ||
| except AttributeError: | ||
| raise ex | ||
| setattr(fld, attr, value) |
| """ | ||
| __slots__ = ["fld"] | ||
|
|
||
| def copy(self): |
There was a problem hiding this comment.
What this function does looks very funky to me. Couldn't we just call the copy() of the sub field?
Summary
Fix copying of
_FieldContainerinstances so wrappers such asEmphremain wrappers instead of being replaced by their contained field.The root cause was that
_FieldContainerdelegated missing attributes tofld, socontainer.copy()resolved tocontainer.fld.copy()when the container class did not define its owncopy()method. This also affected packet field copying whenfields_descreferences another packet class and overrides a copied field default.Fixes #4657.
Changes
_FieldContainer.copy()to copy the container instance and its stored attributes.Emph(...).copy()and the packet-metaclass copy path from the issue.Validation
python3 -m scapy.tools.UTscapy -t test/fields.uts -N -qq -f xUnit -o /tmp/scapy-fields.xml/tmp/scapy-flake8-venv/bin/flake8 scapy/Note:
toxis not installed in this local environment, so flake8 was run through a temporary venv using the repository-pinnedflake8<6.0.0version.