Skip to content
Closed
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
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
`Unreleased`_
=============

Changed
-------
- Changed internal backend detection to use a single common function.

`1.1.1`_ (2025-09-07)
=====================

Expand Down
10 changes: 4 additions & 6 deletions bleak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@
from bleak.args.bluez import BlueZScannerArgs
from bleak.args.corebluetooth import CBScannerArgs, CBStartNotifyArgs
from bleak.args.winrt import WinRTClientArgs
from bleak.backends import get_backend
from bleak.backends.characteristic import BleakGATTCharacteristic
from bleak.backends.client import BaseBleakClient, get_platform_client_backend_type
from bleak.backends.client import BaseBleakClient
from bleak.backends.descriptor import BleakGATTDescriptor
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import (
AdvertisementData,
AdvertisementDataCallback,
AdvertisementDataFilter,
BaseBleakScanner,
get_platform_scanner_backend_type,
)
from bleak.backends.service import BleakGATTServiceCollection
from bleak.exc import BleakCharacteristicNotFoundError, BleakError
Expand Down Expand Up @@ -124,7 +124,7 @@ def __init__(
**kwargs: Any,
) -> None:
PlatformBleakScanner = (
get_platform_scanner_backend_type() if backend is None else backend
get_backend().scanner_type if backend is None else backend
)

self._backend = PlatformBleakScanner(
Expand Down Expand Up @@ -490,9 +490,7 @@ def __init__(
backend: Optional[type[BaseBleakClient]] = None,
**kwargs: Any,
) -> None:
PlatformBleakClient = (
get_platform_client_backend_type() if backend is None else backend
)
PlatformBleakClient = get_backend().client_type if backend is None else backend

self._backend = PlatformBleakClient(
address_or_ble_device,
Expand Down
81 changes: 76 additions & 5 deletions bleak/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,76 @@
# -*- coding: utf-8 -*-
# Created on 2017-11-19 by hbldh <[email protected]>
"""
__init__.py
"""
import os
import platform
import sys
from dataclasses import dataclass

from bleak.backends.client import BaseBleakClient
from bleak.backends.scanner import BaseBleakScanner
from bleak.exc import BleakError


@dataclass(frozen=True)
class BleakBackendProvider:
client_type: type[BaseBleakClient]
scanner_type: type[BaseBleakScanner]


def get_backend() -> BleakBackendProvider:
"""
Gets the platform-specific backend provider.
"""
if sys.platform == "android" and os.environ.get("P4A_BOOTSTRAP") is not None:
from bleak.backends.p4android.client import BleakClientP4Android
from bleak.backends.p4android.scanner import BleakScannerP4Android

return BleakBackendProvider(
client_type=BleakClientP4Android,
scanner_type=BleakScannerP4Android,
)

if sys.platform == "linux":
from bleak.backends.bluezdbus.client import BleakClientBlueZDBus
from bleak.backends.bluezdbus.scanner import BleakScannerBlueZDBus

return BleakBackendProvider(
client_type=BleakClientBlueZDBus,
scanner_type=BleakScannerBlueZDBus,
)

if sys.platform == "ios" and "Pythonista3.app" in sys.executable:
# Must be resolved before checking for "Darwin" (macOS),
# as both the Pythonista app for iOS and macOS
# return "Darwin" from platform.system()
try:
from bleak_pythonista import (
BleakClientPythonistaCB,
BleakScannerPythonistaCB,
)

return BleakBackendProvider(
client_type=BleakClientPythonistaCB,
scanner_type=BleakScannerPythonistaCB,
)
except ImportError as e:
raise ImportError(
"Ensure you have `bleak-pythonista` package installed."
) from e

if sys.platform == "darwin":
from bleak.backends.corebluetooth.client import BleakClientCoreBluetooth
from bleak.backends.corebluetooth.scanner import BleakScannerCoreBluetooth

return BleakBackendProvider(
client_type=BleakClientCoreBluetooth,
scanner_type=BleakScannerCoreBluetooth,
)

if sys.platform == "win32":
from bleak.backends.winrt.client import BleakClientWinRT
from bleak.backends.winrt.scanner import BleakScannerWinRT

return BleakBackendProvider(
client_type=BleakClientWinRT,
scanner_type=BleakScannerWinRT,
)

raise BleakError(f"Unsupported platform: {platform.system()}")
42 changes: 0 additions & 42 deletions bleak/backends/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
Base class for backend clients.
"""
import abc
import os
import platform
import sys
from collections.abc import Callable
from typing import Any, Optional, Union
Expand Down Expand Up @@ -207,43 +205,3 @@ async def stop_notify(self, characteristic: BleakGATTCharacteristic) -> None:

"""
raise NotImplementedError()


def get_platform_client_backend_type() -> type[BaseBleakClient]:
"""
Gets the platform-specific :class:`BaseBleakClient` type.
"""
if os.environ.get("P4A_BOOTSTRAP") is not None:
from bleak.backends.p4android.client import BleakClientP4Android

return BleakClientP4Android

if platform.system() == "Linux":
from bleak.backends.bluezdbus.client import BleakClientBlueZDBus

return BleakClientBlueZDBus

if sys.platform == "ios" and "Pythonista3.app" in sys.executable:
# Must be resolved before checking for "Darwin" (macOS),
# as both the Pythonista app for iOS and macOS
# return "Darwin" from platform.system()
try:
from bleak_pythonista import BleakClientPythonistaCB

return BleakClientPythonistaCB
except ImportError as e:
raise ImportError(
"Ensure you have `bleak-pythonista` package installed."
) from e

if platform.system() == "Darwin":
from bleak.backends.corebluetooth.client import BleakClientCoreBluetooth

return BleakClientCoreBluetooth

if platform.system() == "Windows":
from bleak.backends.winrt.client import BleakClientWinRT

return BleakClientWinRT

raise BleakError(f"Unsupported platform: {platform.system()}")
44 changes: 0 additions & 44 deletions bleak/backends/scanner.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import abc
import asyncio
import inspect
import os
import platform
import sys
from collections.abc import Callable, Coroutine, Hashable
from typing import Any, NamedTuple, Optional

from bleak.backends.device import BLEDevice
from bleak.exc import BleakError

# prevent tasks from being garbage collected
_background_tasks: set[asyncio.Task[None]] = set()
Expand Down Expand Up @@ -280,43 +276,3 @@ async def start(self) -> None:
async def stop(self) -> None:
"""Stop scanning for devices"""
raise NotImplementedError()


def get_platform_scanner_backend_type() -> type[BaseBleakScanner]:
"""
Gets the platform-specific :class:`BaseBleakScanner` type.
"""
if os.environ.get("P4A_BOOTSTRAP") is not None:
from bleak.backends.p4android.scanner import BleakScannerP4Android

return BleakScannerP4Android

if platform.system() == "Linux":
from bleak.backends.bluezdbus.scanner import BleakScannerBlueZDBus

return BleakScannerBlueZDBus

if sys.platform == "ios" and "Pythonista3.app" in sys.executable:
# Must be resolved before checking for "Darwin" (macOS),
# as both the Pythonista app for iOS and macOS
# return "Darwin" from platform.system()
try:
from bleak_pythonista import BleakScannerPythonistaCB

return BleakScannerPythonistaCB
except ImportError as e:
raise ImportError(
"Ensure you have `bleak-pythonista` package installed."
) from e

if platform.system() == "Darwin":
from bleak.backends.corebluetooth.scanner import BleakScannerCoreBluetooth

return BleakScannerCoreBluetooth

if platform.system() == "Windows":
from bleak.backends.winrt.scanner import BleakScannerWinRT

return BleakScannerWinRT

raise BleakError(f"Unsupported platform: {platform.system()}")
7 changes: 3 additions & 4 deletions tests/test_platform_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@

import platform

from bleak.backends.client import get_platform_client_backend_type
from bleak.backends.scanner import get_platform_scanner_backend_type
from bleak.backends import get_backend


def test_platform_detection():
"""Test by importing the client and assert correct client by OS."""

client_backend_type = get_platform_client_backend_type()
scanner_backend_type = get_platform_scanner_backend_type()
client_backend_type = get_backend().client_type
scanner_backend_type = get_backend().scanner_type

if platform.system() == "Linux":
assert client_backend_type.__name__ == "BleakClientBlueZDBus"
Expand Down
Loading