Skip to content

Commit

Permalink
Remove remaining legacy Python 2 code (#599)
Browse files Browse the repository at this point in the history
* Replace OrderedDict with plain dict()

<https://docs.python.org/3/library/collections.html#ordereddict-objects>:
> Ordered dictionaries are just like regular dictionaries but have some
> extra capabilities relating to ordering operations. They have become
> less important now that the built-in dict class gained the ability to
> remember insertion order (this new behavior became guaranteed in
> Python 3.7).

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

* construct/lib/container: Remove unneeded methods

`collections.abc.MutableMapping` already implements `keys()`,
`update()`, `__eq__()`, `__ne__()` and `__contains__()` – most
importantly correctly, e.g. `update()` has many variants which the
current implementation does not handle.

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

* construct: Remove Python 2 compatibility layer

Remove the compatibility layer `py3compat`.

PS: There is #548 to migrate
from the interned version of `construct` back to "Construct 2.10+" now
that it is maintained again. When that happens, this change will become
moot. Until then restore some sanity back into our copy as handling
Python type annotations for both Python 2 and 3 is a major pain.

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

* Drop remaining Python 2 compatibility code

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

* Drop from __future__ import print_function

The project is Python 3 only, so remove the legacy Python 2
compatibility.

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

* Replace `bytelist2string` with `bytes`

The function was used in only one place. Just use the much more
efficient `bytes(list[int])` to convert from `list[int]` to `bytes`.

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

---------

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
  • Loading branch information
pmhahn authored Feb 25, 2025
1 parent aad8631 commit f92bb71
Show file tree
Hide file tree
Showing 32 changed files with 32 additions and 184 deletions.
6 changes: 0 additions & 6 deletions elftools/common/construct_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ def _sizeof(self, context):

class ULEB128(Construct):
"""A construct based parser for ULEB128 encoding.
Incompatible with Python 2 - assumes that the return of read()
is an indexed collection of numbers.
"""
def _parse(self, stream, context):
value = 0
Expand All @@ -68,9 +65,6 @@ def _parse(self, stream, context):

class SLEB128(Construct):
"""A construct based parser for SLEB128 encoding.
Incompatible with Python 2 - assumes that the return of read()
is an indexed collection of numbers.
"""
def _parse(self, stream, context):
value = 0
Expand Down
7 changes: 0 additions & 7 deletions elftools/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@ def bytes2str(b):
"""Decode a bytes object into a string."""
return b.decode('latin-1')

def bytelist2string(bytelist):
""" Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a bytes object
(e.g. b'\x10\x20\x00').
"""
return b''.join(bytes((b,)) for b in bytelist)


def struct_parse(struct, stream, stream_pos=None):
""" Convenience function for using the given struct to parse a stream.
If stream_pos is provided, the stream is seeked to this position before
Expand Down
2 changes: 1 addition & 1 deletion elftools/construct/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
... )
>>> s.parse("\\x01\\x02\\x03")
Container(a = 1, b = 515)
>>> print s.parse("\\x01\\x02\\x03")
>>> print(s.parse("\\x01\\x02\\x03"))
Container:
a = 1
b = 515
Expand Down
3 changes: 2 additions & 1 deletion elftools/construct/adapters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from io import BytesIO

from .core import Adapter, AdaptationError, Pass
from .lib import int_to_bin, bin_to_int, swap_bytes
from .lib import FlagsContainer, HexString
from .lib.py3compat import BytesIO, decodebytes


#===============================================================================
Expand Down
14 changes: 7 additions & 7 deletions elftools/construct/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from io import BytesIO
from struct import Struct as Packer

from .lib.py3compat import BytesIO, advance_iterator, bchr
from .lib import Container, ListContainer, LazyContainer


Expand Down Expand Up @@ -520,13 +520,13 @@ def _build(self, obj, stream, context):
if self.subcon.conflags & self.FLAG_COPY_CONTEXT:
for subobj in obj:
if isinstance(obj, bytes):
subobj = bchr(subobj)
subobj = bytes((subobj,))
self.subcon._build(subobj, stream, context.__copy__())
cnt += 1
else:
for subobj in obj:
if isinstance(obj, bytes):
subobj = bchr(subobj)
subobj = bytes((subobj,))
self.subcon._build(subobj, stream, context)
cnt += 1
except ConstructError as ex:
Expand Down Expand Up @@ -587,7 +587,7 @@ def _build(self, obj, stream, context):
break
else:
for subobj in obj:
subobj = bchr(subobj)
subobj = bytes((subobj,))
self.subcon._build(subobj, stream, context.__copy__())
if self.predicate(subobj, context):
terminated = True
Expand Down Expand Up @@ -722,7 +722,7 @@ def _build(self, obj, stream, context):
elif sc.name is None:
subobj = None
else:
subobj = advance_iterator(objiter)
subobj = next(objiter)
context[sc.name] = subobj
sc._build(subobj, stream, context)

Expand Down Expand Up @@ -881,7 +881,7 @@ def _parse(self, stream, context):
except ConstructError:
stream.seek(pos)
else:
context.__update__(context2)
context.update(context2)
if self.include_name:
return sc.name, obj
else:
Expand All @@ -903,7 +903,7 @@ def _build(self, obj, stream, context):
except Exception:
pass
else:
context.__update__(context2)
context.update(context2)
stream.write(stream2.getvalue())
return
raise SelectError("no subconstruct matched", obj)
Expand Down
3 changes: 1 addition & 2 deletions elftools/construct/debug.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""
Debugging utilities for constructs
"""
from __future__ import print_function
import sys
import traceback
import pdb
Expand Down Expand Up @@ -81,7 +80,7 @@ def printout(self, stream, context):
frames.reverse()
for f in frames:
a = Container()
a.__update__(f.f_locals)
a.update(f.f_locals)
obj.stack.append(a)

print("=" * 80)
Expand Down
18 changes: 3 additions & 15 deletions elftools/construct/lib/binary.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from .py3compat import int2byte


def int_to_bin(number, width=32):
r"""
Convert an integer into its binary representation in a bytes object.
Expand Down Expand Up @@ -32,13 +29,6 @@ def int_to_bin(number, width=32):
1: 1,
48: 0, # '0'
49: 1, # '1'

# The following are for Python 2, in which iteration over a bytes object
# yields single-character bytes and not integers.
'\x00': 0,
'\x01': 1,
'0': 0,
'1': 1,
}

def bin_to_int(bits, signed=False):
Expand Down Expand Up @@ -81,10 +71,8 @@ def swap_bytes(bits, bytesize=8):
_char_to_bin = {}
_bin_to_char = {}
for i in range(256):
ch = int2byte(i)
ch = bytes((i,))
bin = int_to_bin(i, 8)
# Populate with for both keys i and ch, to support Python 2 & 3
_char_to_bin[ch] = bin
_char_to_bin[i] = bin
_bin_to_char[bin] = ch

Expand All @@ -94,15 +82,15 @@ def encode_bin(data):
Create a binary representation of the given b'' object. Assume 8-bit
ASCII. Example:
>>> encode_bin('ab')
>>> encode_bin(b'ab')
b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00"
"""
return b"".join(_char_to_bin[ch] for ch in data)


def decode_bin(data):
"""
Locical opposite of decode_bin.
Logical opposite of decode_bin.
"""
if len(data) & 7:
raise ValueError("Data length must be a multiple of 8")
Expand Down
33 changes: 4 additions & 29 deletions elftools/construct/lib/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
Various containers.
"""

from collections.abc import MutableMapping
from pprint import pformat
from .py3compat import MutableMapping


def recursion_lock(retval, lock_name = "__recursion_lock__"):
def decorator(func):
Expand Down Expand Up @@ -40,45 +41,19 @@ def __delitem__(self, name):
def __setitem__(self, name, value):
self.__dict__[name] = value

def keys(self):
return self.__dict__.keys()
def __iter__(self):
return iter(self.__dict__)

def __len__(self):
return len(self.__dict__.keys())

# Extended dictionary interface.

def update(self, other):
self.__dict__.update(other)

__update__ = update

def __contains__(self, value):
return value in self.__dict__

# Rich comparisons.

def __eq__(self, other):
try:
return self.__dict__ == other.__dict__
except AttributeError:
return False

def __ne__(self, other):
return not self == other

# Copy interface.

def copy(self):
return self.__class__(**self.__dict__)

__copy__ = copy

# Iterator interface.

def __iter__(self):
return iter(self.__dict__)

def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__))

Expand Down
9 changes: 3 additions & 6 deletions elftools/construct/lib/hex.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from .py3compat import byte2int, int2byte, bytes2str


# Map an integer in the inclusive range 0-255 to its string byte representation
_printable = dict((i, ".") for i in range(256))
_printable.update((i, bytes2str(int2byte(i))) for i in range(32, 128))
_printable.update((i, chr(i)) for i in range(32, 128))


def hexdump(data, linesize):
Expand All @@ -18,8 +15,8 @@ def hexdump(data, linesize):
fmt = fmt % (3 * linesize - 1,)
for i in range(0, len(data), linesize):
line = data[i : i + linesize]
hextext = " ".join('%02x' % byte2int(b) for b in line)
rawtext = "".join(_printable[byte2int(b)] for b in line)
hextext = " ".join('%02x' % b for b in line)
rawtext = "".join(_printable[b] for b in line)
prettylines.append(fmt % (i, str(hextext), str(rawtext)))
return prettylines

Expand Down
74 changes: 0 additions & 74 deletions elftools/construct/lib/py3compat.py

This file was deleted.

3 changes: 1 addition & 2 deletions elftools/construct/macros.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .lib.py3compat import int2byte
from .lib import (BitStreamReader, BitStreamWriter, encode_bin,
decode_bin)
from .core import (Struct, MetaField, StaticField, FormatField,
Expand Down Expand Up @@ -103,7 +102,7 @@ def Flag(name, truth = 1, falsehood = 0, default = False):
"""

return SymmetricMapping(Field(name, 1),
{True : int2byte(truth), False : int2byte(falsehood)},
{True : bytes((truth,)), False : bytes((falsehood,))},
default = default,
)

Expand Down
1 change: 0 additions & 1 deletion elftools/dwarf/descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,6 @@ def _import_extra(attr, die, section_offset):
# stream.
with preserve_stream_pos(die.stream):
ref_die = DIE(cu, die.stream, ref_die_offset)
#print '&&& ref_die', ref_die
return '[Abbrev Number: %s (%s)]' % (
ref_die.abbrev_code, ref_die.tag)

Expand Down
4 changes: 2 additions & 2 deletions elftools/dwarf/die.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
from collections import namedtuple, OrderedDict
from collections import namedtuple
import os

from ..common.exceptions import DWARFError, ELFParseError
Expand Down Expand Up @@ -86,7 +86,7 @@ def __init__(self, cu, stream, offset):
self.stream = stream
self.offset = offset

self.attributes = OrderedDict()
self.attributes = {}
self.tag = None
self.has_children = None
self.abbrev_code = None
Expand Down
4 changes: 2 additions & 2 deletions elftools/dwarf/dwarf_expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from collections import namedtuple
from io import BytesIO

from ..common.utils import struct_parse, bytelist2string, read_blob
from ..common.utils import struct_parse, read_blob
from ..common.exceptions import DWARFError


Expand Down Expand Up @@ -135,7 +135,7 @@ def parse_expr(self, expr):
The list can potentially be nested.
"""
stream = BytesIO(bytelist2string(expr))
stream = BytesIO(bytes(expr))
parsed = []

while True:
Expand Down
Loading

0 comments on commit f92bb71

Please sign in to comment.