diff --git a/apps/console.py b/apps/console.py index a1d4d3a2..b7c30c77 100644 --- a/apps/console.py +++ b/apps/console.py @@ -27,7 +27,6 @@ import re from collections import OrderedDict import click -import colors from prompt_toolkit import Application from prompt_toolkit.history import FileHistory @@ -53,6 +52,7 @@ from prompt_toolkit.layout import ( from bumble import __version__ import bumble.core +from bumble import colors from bumble.core import UUID, AdvertisingData, BT_LE_TRANSPORT from bumble.device import ConnectionParametersPreferences, Device, Connection, Peer from bumble.utils import AsyncRunner diff --git a/apps/controller_info.py b/apps/controller_info.py index 22a1ce58..9c9345ee 100644 --- a/apps/controller_info.py +++ b/apps/controller_info.py @@ -19,9 +19,9 @@ import asyncio import os import logging import click -from colors import color from bumble.company_ids import COMPANY_IDENTIFIERS +from bumble.colors import color from bumble.core import name_or_number from bumble.hci import ( map_null_terminated_utf8_string, diff --git a/apps/gatt_dump.py b/apps/gatt_dump.py index 6a9cf727..a3205c00 100644 --- a/apps/gatt_dump.py +++ b/apps/gatt_dump.py @@ -19,9 +19,9 @@ import asyncio import os import logging import click -from colors import color import bumble.core +from bumble.colors import color from bumble.device import Device, Peer from bumble.gatt import show_services from bumble.transport import open_transport_or_link diff --git a/apps/gg_bridge.py b/apps/gg_bridge.py index a3f9f526..17c16628 100644 --- a/apps/gg_bridge.py +++ b/apps/gg_bridge.py @@ -20,8 +20,8 @@ import os import struct import logging import click -from colors import color +from bumble.colors import color from bumble.device import Device, Peer from bumble.core import AdvertisingData from bumble.gatt import Service, Characteristic, CharacteristicValue diff --git a/apps/l2cap_bridge.py b/apps/l2cap_bridge.py index 91462a0c..17623e4c 100644 --- a/apps/l2cap_bridge.py +++ b/apps/l2cap_bridge.py @@ -19,8 +19,8 @@ import asyncio import logging import os import click -from colors import color +from bumble.colors import color from bumble.transport import open_transport_or_link from bumble.device import Device from bumble.utils import FlowControlAsyncPipe diff --git a/apps/link_relay/link_relay.py b/apps/link_relay/link_relay.py index e8bdcebb..6036fa0f 100644 --- a/apps/link_relay/link_relay.py +++ b/apps/link_relay/link_relay.py @@ -23,9 +23,10 @@ import argparse import uuid import os from urllib.parse import urlparse -from colors import color import websockets +from bumble.colors import color + # ----------------------------------------------------------------------------- # Logging # ----------------------------------------------------------------------------- diff --git a/apps/pair.py b/apps/pair.py index 0a1b8f9e..3729143d 100644 --- a/apps/pair.py +++ b/apps/pair.py @@ -19,9 +19,9 @@ import asyncio import os import logging import click -from colors import color from prompt_toolkit.shortcuts import PromptSession +from bumble.colors import color from bumble.device import Device, Peer from bumble.transport import open_transport_or_link from bumble.smp import PairingDelegate, PairingConfig diff --git a/apps/scan.py b/apps/scan.py index 672877fa..dac7a2c0 100644 --- a/apps/scan.py +++ b/apps/scan.py @@ -19,8 +19,8 @@ import asyncio import os import logging import click -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link from bumble.keys import JsonKeyStore diff --git a/apps/show.py b/apps/show.py index 86b5fb1d..bf01eada 100644 --- a/apps/show.py +++ b/apps/show.py @@ -17,8 +17,8 @@ # ----------------------------------------------------------------------------- import struct import click -from colors import color +from bumble.colors import color from bumble import hci from bumble.transport.common import PacketReader from bumble.helpers import PacketTracer diff --git a/apps/usb_probe.py b/apps/usb_probe.py index 16ea4db3..785b0dd3 100644 --- a/apps/usb_probe.py +++ b/apps/usb_probe.py @@ -30,8 +30,8 @@ import os import logging import click import usb1 -from colors import color +from bumble.colors import color from bumble.transport.usb import load_libusb diff --git a/bumble/att.py b/bumble/att.py index b97aef1f..e5cdadf2 100644 --- a/bumble/att.py +++ b/bumble/att.py @@ -24,12 +24,12 @@ # ----------------------------------------------------------------------------- from __future__ import annotations import struct -from colors import color from pyee import EventEmitter from typing import Dict, Type from bumble.core import UUID, name_or_number from bumble.hci import HCI_Object, key_with_value +from bumble.colors import color # ----------------------------------------------------------------------------- diff --git a/bumble/avdtp.py b/bumble/avdtp.py index 62e7b490..238036dc 100644 --- a/bumble/avdtp.py +++ b/bumble/avdtp.py @@ -20,7 +20,6 @@ import asyncio import struct import time import logging -from colors import color from pyee import EventEmitter from typing import Dict, Type @@ -40,6 +39,7 @@ from .a2dp import ( VendorSpecificMediaCodecInformation, ) from . import sdp +from .colors import color # ----------------------------------------------------------------------------- # Logging diff --git a/bumble/colors.py b/bumble/colors.py new file mode 100644 index 00000000..2813cfe5 --- /dev/null +++ b/bumble/colors.py @@ -0,0 +1,103 @@ +# Copyright (c) 2012 Giorgos Verigakis +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from functools import partial +from typing import List, Optional, Union + + +# ANSI color names. There is also a "default" +COLORS = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white') + +# ANSI style names +STYLES = ( + 'none', + 'bold', + 'faint', + 'italic', + 'underline', + 'blink', + 'blink2', + 'negative', + 'concealed', + 'crossed', +) + + +ColorSpec = Union[str, int] + + +def _join(*values: ColorSpec) -> str: + return ';'.join(str(v) for v in values) + + +def _color_code(spec: ColorSpec, base: int) -> str: + if isinstance(spec, str): + spec = spec.strip().lower() + + if spec == 'default': + return _join(base + 9) + elif spec in COLORS: + return _join(base + COLORS.index(spec)) + elif isinstance(spec, int) and 0 <= spec <= 255: + return _join(base + 8, 5, spec) + else: + raise ValueError('Invalid color spec "%s"' % spec) + + +def color( + s: str, + fg: Optional[ColorSpec] = None, + bg: Optional[ColorSpec] = None, + style: Optional[str] = None, +) -> str: + codes: List[ColorSpec] = [] + + if fg: + codes.append(_color_code(fg, 30)) + if bg: + codes.append(_color_code(bg, 40)) + if style: + for style_part in style.split('+'): + if style_part in STYLES: + codes.append(STYLES.index(style_part)) + else: + raise ValueError('Invalid style "%s"' % style_part) + + if codes: + return '\x1b[{0}m{1}\x1b[0m'.format(_join(*codes), s) + else: + return s + + +# Foreground color shortcuts +black = partial(color, fg='black') +red = partial(color, fg='red') +green = partial(color, fg='green') +yellow = partial(color, fg='yellow') +blue = partial(color, fg='blue') +magenta = partial(color, fg='magenta') +cyan = partial(color, fg='cyan') +white = partial(color, fg='white') + +# Style shortcuts +bold = partial(color, style='bold') +none = partial(color, style='none') +faint = partial(color, style='faint') +italic = partial(color, style='italic') +underline = partial(color, style='underline') +blink = partial(color, style='blink') +blink2 = partial(color, style='blink2') +negative = partial(color, style='negative') +concealed = partial(color, style='concealed') +crossed = partial(color, style='crossed') diff --git a/bumble/controller.py b/bumble/controller.py index bc59fe41..da5d4cf1 100644 --- a/bumble/controller.py +++ b/bumble/controller.py @@ -20,7 +20,7 @@ import asyncio import itertools import random import struct -from colors import color +from bumble.colors import color from bumble.core import BT_CENTRAL_ROLE, BT_PERIPHERAL_ROLE from bumble.hci import ( diff --git a/bumble/device.py b/bumble/device.py index a9713912..d97df496 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -25,8 +25,7 @@ from contextlib import asynccontextmanager, AsyncExitStack from dataclasses import dataclass from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union -from colors import color - +from .colors import color from .att import ATT_CID, ATT_DEFAULT_MTU, ATT_PDU from .gatt import Characteristic, Descriptor, Service from .hci import ( diff --git a/bumble/gatt.py b/bumble/gatt.py index 180941b1..7aa065c5 100644 --- a/bumble/gatt.py +++ b/bumble/gatt.py @@ -29,8 +29,8 @@ import functools import logging import struct from typing import Optional, Sequence -from colors import color +from .colors import color from .core import UUID, get_dict_key_by_value from .att import Attribute diff --git a/bumble/gatt_client.py b/bumble/gatt_client.py index 9d0ce5c0..2fd75736 100644 --- a/bumble/gatt_client.py +++ b/bumble/gatt_client.py @@ -27,9 +27,9 @@ import asyncio import logging import struct -from colors import color from pyee import EventEmitter +from .colors import color from .hci import HCI_Constant from .att import ( ATT_ATTRIBUTE_NOT_FOUND_ERROR, diff --git a/bumble/gatt_server.py b/bumble/gatt_server.py index 9efc9002..86786cdb 100644 --- a/bumble/gatt_server.py +++ b/bumble/gatt_server.py @@ -29,8 +29,8 @@ from collections import defaultdict import struct from typing import List, Tuple, Optional from pyee import EventEmitter -from colors import color +from .colors import color from .core import UUID from .att import ( ATT_ATTRIBUTE_NOT_FOUND_ERROR, diff --git a/bumble/hci.py b/bumble/hci.py index 951e81cb..d8517c21 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -20,9 +20,9 @@ import struct import collections import logging import functools -from colors import color from typing import Dict, Type, Union +from .colors import color from .core import ( BT_BR_EDR_TRANSPORT, AdvertisingData, diff --git a/bumble/helpers.py b/bumble/helpers.py index 55fe065e..83c7c6df 100644 --- a/bumble/helpers.py +++ b/bumble/helpers.py @@ -16,8 +16,8 @@ # Imports # ----------------------------------------------------------------------------- import logging -from colors import color +from .colors import color from .att import ATT_CID, ATT_PDU from .smp import SMP_CID, SMP_Command from .core import name_or_number diff --git a/bumble/hfp.py b/bumble/hfp.py index 749570ae..7bb9f084 100644 --- a/bumble/hfp.py +++ b/bumble/hfp.py @@ -18,7 +18,8 @@ import logging import asyncio import collections -from colors import color + +from .colors import color # ----------------------------------------------------------------------------- diff --git a/bumble/host.py b/bumble/host.py index bb29eb05..65c7741a 100644 --- a/bumble/host.py +++ b/bumble/host.py @@ -20,8 +20,7 @@ import collections import logging import struct -from colors import color - +from bumble.colors import color from bumble.l2cap import L2CAP_PDU from .hci import ( diff --git a/bumble/keys.py b/bumble/keys.py index 47be8754..7fed6602 100644 --- a/bumble/keys.py +++ b/bumble/keys.py @@ -25,8 +25,8 @@ import logging import os import json from typing import Optional -from colors import color +from .colors import color from .hci import Address diff --git a/bumble/l2cap.py b/bumble/l2cap.py index aaea46f5..2610adce 100644 --- a/bumble/l2cap.py +++ b/bumble/l2cap.py @@ -21,10 +21,10 @@ import logging import struct from collections import deque -from colors import color from pyee import EventEmitter from typing import Dict, Type +from .colors import color from .core import BT_CENTRAL_ROLE, InvalidStateError, ProtocolError from .hci import ( HCI_LE_Connection_Update_Command, diff --git a/bumble/link.py b/bumble/link.py index 09d249f4..84ff47e0 100644 --- a/bumble/link.py +++ b/bumble/link.py @@ -19,9 +19,9 @@ import logging import asyncio from functools import partial -from colors import color import websockets +from bumble.colors import color from bumble.hci import ( Address, HCI_SUCCESS, diff --git a/bumble/rfcomm.py b/bumble/rfcomm.py index 66a681bc..a6b02ba6 100644 --- a/bumble/rfcomm.py +++ b/bumble/rfcomm.py @@ -18,10 +18,10 @@ import logging import asyncio -from colors import color from pyee import EventEmitter from . import core +from .colors import color from .core import BT_BR_EDR_TRANSPORT, InvalidStateError, ProtocolError # ----------------------------------------------------------------------------- diff --git a/bumble/sdp.py b/bumble/sdp.py index 896a47a2..019b8e6f 100644 --- a/bumble/sdp.py +++ b/bumble/sdp.py @@ -18,11 +18,10 @@ from __future__ import annotations import logging import struct -from colors import color -import colors from typing import Dict, List, Type from . import core +from .colors import color from .core import InvalidStateError from .hci import HCI_Object, name_or_number, key_with_value @@ -506,7 +505,7 @@ class ServiceAttribute: def to_string(self, with_colors=False): if with_colors: return ( - f'Attribute(id={colors.color(self.id_name(self.id),"magenta")},' + f'Attribute(id={color(self.id_name(self.id),"magenta")},' f'value={self.value})' ) diff --git a/bumble/smp.py b/bumble/smp.py index 416fb2b9..9a72cb0d 100644 --- a/bumble/smp.py +++ b/bumble/smp.py @@ -29,8 +29,8 @@ import secrets from typing import Dict, Optional, Type from pyee import EventEmitter -from colors import color +from .colors import color from .hci import Address, HCI_LE_Enable_Encryption_Command, HCI_Object, key_with_value from .core import ( BT_BR_EDR_TRANSPORT, diff --git a/bumble/transport/common.py b/bumble/transport/common.py index a2964075..945ba4b4 100644 --- a/bumble/transport/common.py +++ b/bumble/transport/common.py @@ -18,9 +18,9 @@ import struct import asyncio import logging -from colors import color from .. import hci +from ..colors import color # ----------------------------------------------------------------------------- diff --git a/bumble/transport/pyusb.py b/bumble/transport/pyusb.py index 6b3152aa..8ad85983 100644 --- a/bumble/transport/pyusb.py +++ b/bumble/transport/pyusb.py @@ -22,10 +22,10 @@ import time import usb.core import usb.util -from colors import color from .common import Transport, ParserSource from .. import hci +from ..colors import color # ----------------------------------------------------------------------------- diff --git a/bumble/transport/usb.py b/bumble/transport/usb.py index f0efa32e..68c5a6f2 100644 --- a/bumble/transport/usb.py +++ b/bumble/transport/usb.py @@ -23,10 +23,10 @@ import ctypes import platform import usb1 -from colors import color from .common import Transport, ParserSource from .. import hci +from ..colors import color # ----------------------------------------------------------------------------- diff --git a/bumble/utils.py b/bumble/utils.py index 111f0556..474fff2f 100644 --- a/bumble/utils.py +++ b/bumble/utils.py @@ -22,9 +22,9 @@ import collections import sys from typing import Awaitable, TypeVar from functools import wraps -from colors import color from pyee import EventEmitter +from .colors import color # ----------------------------------------------------------------------------- # Logging diff --git a/examples/battery_client.py b/examples/battery_client.py index a7854ce7..3cf11b46 100644 --- a/examples/battery_client.py +++ b/examples/battery_client.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport from bumble.profiles.battery_service import BatteryServiceProxy diff --git a/examples/device_information_client.py b/examples/device_information_client.py index 9fa6c15f..416aa2f1 100644 --- a/examples/device_information_client.py +++ b/examples/device_information_client.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device, Peer from bumble.profiles.device_information_service import DeviceInformationServiceProxy from bumble.transport import open_transport diff --git a/examples/heart_rate_client.py b/examples/heart_rate_client.py index 99ed359d..ecfcffbc 100644 --- a/examples/heart_rate_client.py +++ b/examples/heart_rate_client.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport from bumble.profiles.heart_rate_service import HeartRateServiceProxy diff --git a/examples/keyboard.py b/examples/keyboard.py index b8729c0a..16dbeb6f 100644 --- a/examples/keyboard.py +++ b/examples/keyboard.py @@ -22,7 +22,7 @@ import logging import struct import json import websockets -from colors import color +from bumble.colors import color from bumble.core import AdvertisingData from bumble.device import Device, Connection, Peer diff --git a/examples/run_a2dp_info.py b/examples/run_a2dp_info.py index 48d85003..2f21cfa7 100644 --- a/examples/run_a2dp_info.py +++ b/examples/run_a2dp_info.py @@ -20,7 +20,7 @@ import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link from bumble.core import ( diff --git a/examples/run_a2dp_source.py b/examples/run_a2dp_source.py index 68aa435d..24435181 100644 --- a/examples/run_a2dp_source.py +++ b/examples/run_a2dp_source.py @@ -20,7 +20,7 @@ import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link from bumble.core import BT_BR_EDR_TRANSPORT diff --git a/examples/run_classic_connect.py b/examples/run_classic_connect.py index 70575a5e..bb46bf75 100644 --- a/examples/run_classic_connect.py +++ b/examples/run_classic_connect.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link diff --git a/examples/run_classic_discovery.py b/examples/run_classic_discovery.py index 00f88148..569c8b38 100644 --- a/examples/run_classic_discovery.py +++ b/examples/run_classic_discovery.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link diff --git a/examples/run_controller_with_scanner.py b/examples/run_controller_with_scanner.py index bdf53a70..9603cff8 100644 --- a/examples/run_controller_with_scanner.py +++ b/examples/run_controller_with_scanner.py @@ -19,7 +19,7 @@ import logging import asyncio import sys import os -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.controller import Controller diff --git a/examples/run_gatt_client.py b/examples/run_gatt_client.py index 09d0edc1..dcf8a1b9 100644 --- a/examples/run_gatt_client.py +++ b/examples/run_gatt_client.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.core import ProtocolError from bumble.device import Device, Peer diff --git a/examples/run_gatt_client_and_server.py b/examples/run_gatt_client_and_server.py index 6586ca4d..f3df733a 100644 --- a/examples/run_gatt_client_and_server.py +++ b/examples/run_gatt_client_and_server.py @@ -18,7 +18,7 @@ import asyncio import os import logging -from colors import color +from bumble.colors import color from bumble.core import ProtocolError from bumble.controller import Controller diff --git a/examples/run_hfp_gateway.py b/examples/run_hfp_gateway.py index 09942c41..63a2a7c3 100644 --- a/examples/run_hfp_gateway.py +++ b/examples/run_hfp_gateway.py @@ -20,7 +20,7 @@ import sys import os import logging -from colors import color +from bumble.colors import color import bumble.core from bumble.device import Device diff --git a/examples/run_rfcomm_client.py b/examples/run_rfcomm_client.py index f6cf24e1..9a942787 100644 --- a/examples/run_rfcomm_client.py +++ b/examples/run_rfcomm_client.py @@ -20,7 +20,7 @@ import sys import os import logging -from colors import color +from bumble.colors import color import bumble.core from bumble.device import Device diff --git a/examples/run_scanner.py b/examples/run_scanner.py index b04b0e8e..bdd7fba4 100644 --- a/examples/run_scanner.py +++ b/examples/run_scanner.py @@ -19,7 +19,7 @@ import asyncio import sys import os import logging -from colors import color +from bumble.colors import color from bumble.device import Device from bumble.transport import open_transport_or_link diff --git a/setup.cfg b/setup.cfg index 781c3671..3be6bcc6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,7 +30,6 @@ package_dir = bumble.apps = apps include-package-data = True install_requires = - ansicolors >= 1.1 appdirs >= 1.4 click >= 7.1.2; platform_system!='Emscripten' construct >= 2.10