Skip to content

Commit

Permalink
Replace py dependency with termcolor.
Browse files Browse the repository at this point in the history
Only the colored terminal printing feature of the borderline deprecated py
library is used so swap it out for termcolor which is slimmer. Doing so also
fixes the pains that py's submodule deprecations sculdugery have been causing
PyInstaller users (e.g. #245, #447, plus a new regression specific to pyshark
0.5.2 leading to a `ModuleNotFoundError: No module named 'py._io'`).
  • Loading branch information
bwoodsend committed Jul 14, 2022
1 parent 8e0d543 commit 7ab5b43
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 37 deletions.
23 changes: 15 additions & 8 deletions src/pyshark/packet/common.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import sys
import functools

import termcolor


class Pickleable(object):
"""
Base class that implements getstate/setstate, since most of the classes are overriding getattr.
Expand All @@ -24,11 +30,12 @@ def __setstate__(self, data):
setattr(self, key, val)


class StrWriter:
"""A class which mocks the py.io.TerminalWriter to write to an internal buffer"""

def __init__(self):
self.buffer = ""

def write(self, text, *_, **__):
self.buffer += text
@functools.wraps(termcolor.colored)
def colored(text, *args, **kwargs):
try:
enable_color = sys.stdout.isatty()
except:
enable_color = False
if enable_color:
return termcolor.colored(text, *args, **kwargs)
return text
15 changes: 8 additions & 7 deletions src/pyshark/packet/layers/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import typing

import py
import io
import sys

from pyshark.packet import common

Expand Down Expand Up @@ -50,21 +50,22 @@ def __getattr__(self, item):

def pretty_print(self, writer=None):
if not writer:
writer = py.io.TerminalWriter()
writer = sys.stdout
if self.layer_name == DATA_LAYER_NAME:
writer.write('DATA')
return

writer.write('Layer %s:' % self.layer_name.upper() + os.linesep, yellow=True, bold=True)
text = 'Layer %s:' % self.layer_name.upper() + os.linesep
writer.write(common.colored(text, color="yellow", attrs=["bold"]))
self._pretty_print_layer_fields(writer)

def _pretty_print_layer_fields(self, terminal_writer: py.io.TerminalWriter):
def _pretty_print_layer_fields(self, terminal_writer: io.IOBase):
raise NotImplementedError()

def __repr__(self):
return '<%s Layer>' % self.layer_name.upper()

def __str__(self):
writer = common.StrWriter()
writer = io.StringIO()
self.pretty_print(writer=writer)
return writer.buffer
return writer.getvalue()
21 changes: 11 additions & 10 deletions src/pyshark/packet/layers/ek_layer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import abc
import os
import io

import py
import typing

from pyshark.packet.common import colored
from pyshark import ek_field_mapping
from pyshark.packet.layers.base import BaseLayer

Expand Down Expand Up @@ -106,24 +107,24 @@ def _field_has_subfields(self, field_ek_name):
return True
return False

def _pretty_print_layer_fields(self, terminal_writer: py.io.TerminalWriter):
def _pretty_print_layer_fields(self, file: io.IOBase):
for field_name in self.field_names:
field = self.get_field(field_name)
self._pretty_print_field(field_name, field, terminal_writer, indent=1)
self._pretty_print_field(field_name, field, file, indent=1)

def _pretty_print_field(self, field_name, field, terminal_writer, indent=0):
def _pretty_print_field(self, field_name, field, file, indent=0):
prefix = "\t" * indent
if isinstance(field, EkMultiField):
terminal_writer.write(f"{prefix}{field_name}: ", green=True, bold=True)
file.write(colored(f"{prefix}{field_name}: ", "green", attrs=["bold"]))
if field.value is not None:
terminal_writer.write(str(field.value))
terminal_writer.write(os.linesep)
file.write(str(field.value))
file.write(os.linesep)
for subfield in field.subfields:
self._pretty_print_field(subfield, field.get_field(subfield), terminal_writer,
self._pretty_print_field(subfield, field.get_field(subfield), file,
indent=indent + 1)
else:
terminal_writer.write(f"{prefix}{field_name}: ", green=True, bold=True)
terminal_writer.write(f"{field}{os.linesep}")
file.write(colored(f"{prefix}{field_name}: ", "green", attrs=["bold"]))
file.write(f"{field}{os.linesep}")

def _get_possible_layer_prefixes(self):
"""Gets the possible prefixes for a field under this layer.
Expand Down
10 changes: 5 additions & 5 deletions src/pyshark/packet/layers/json_layer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import io

import py

from pyshark.packet.common import colored
from pyshark.packet.fields import LayerField
from pyshark.packet.fields import LayerFieldsContainer
from pyshark.packet.layers.base import BaseLayer
Expand Down Expand Up @@ -79,12 +79,12 @@ def has_field(self, dotted_name) -> bool:
return False
return True

def _pretty_print_layer_fields(self, terminal_writer: py.io.TerminalWriter):
def _pretty_print_layer_fields(self, file: io.IOBase):
for field_line in self._get_all_field_lines():
if ':' in field_line:
field_name, field_line = field_line.split(':', 1)
terminal_writer.write(field_name + ':', green=True, bold=True)
terminal_writer.write(field_line, bold=True)
file.write(colored(field_name + ':', "green", ["bold"]))
file.write(colored(field_line, attrs=["bold"]))

def _get_all_field_lines(self):
"""Returns all lines that represent the fields of the layer (both their names and values)."""
Expand Down
10 changes: 5 additions & 5 deletions src/pyshark/packet/layers/xml_layer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
import typing
import io

import py

from pyshark.packet.common import colored
from pyshark.packet.fields import LayerField, LayerFieldsContainer
from pyshark.packet.layers import base

Expand Down Expand Up @@ -96,12 +96,12 @@ def _sanitize_field_name(self, field_name):
field_name = field_name.replace(self._field_prefix, '')
return field_name.replace('.', '_').replace('-', '_').lower()

def _pretty_print_layer_fields(self, terminal_writer: py.io.TerminalWriter):
def _pretty_print_layer_fields(self, file: io.IOBase):
for field_line in self._get_all_field_lines():
if ':' in field_line:
field_name, field_line = field_line.split(':', 1)
terminal_writer.write(field_name + ':', green=True, bold=True)
terminal_writer.write(field_line, bold=True)
file.write(colored(field_name + ':', "green", attrs=["bold"]))
file.write(colored(field_line, attrs=["bold"]))

def _get_all_fields_with_alternates(self):
all_fields = list(self._all_fields.values())
Expand Down
2 changes: 1 addition & 1 deletion src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
version="0.5.2",
packages=find_packages(),
package_data={'': ['*.ini', '*.pcapng']},
install_requires=['lxml', 'py', 'packaging', 'appdirs'],
install_requires=['lxml', 'termcolor', 'packaging', 'appdirs'],
tests_require=['pytest'],
url="https://github.com/KimiNewt/pyshark",
license="MIT",
Expand Down
2 changes: 1 addition & 1 deletion src/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ envlist = py{35,36,37,38,39,310}
[testenv]
deps =
appdirs
py
termcolor
pytest
mock
lxml
Expand Down

0 comments on commit 7ab5b43

Please sign in to comment.