Skip to content

Commit

Permalink
Fix compatibility problems with python 3.12
Browse files Browse the repository at this point in the history
  • Loading branch information
dknowles2 committed Feb 10, 2024
1 parent 42acd6a commit 35a0317
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 52 deletions.
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ build-backend = "setuptools.build_meta"
[project]
name = "pytboss"
# version = "2023.4.0"
description = "Python library for interacting with Pitboss grills and smokers."
description = "Python library for interacting with PitBoss grills and smokers."
authors = [
{name = "David Knowles", email = "dknowles2@gmail.com"},
]
dependencies = ["bleak", "bleak_retry_connector", "js2py"]
dependencies = ["bleak", "bleak_retry_connector", "dukpy"]
requires-python = ">=3.10"
dynamic = ["readme", "version"]
license = {text = "Apache License 2.0"}
Expand All @@ -20,9 +20,9 @@ classifiers = [
]

[project.urls]
"Homepage" = "https://github.com/dknowles2/pyschlage"
"Source Code" = "https://github.com/dknowles2/pyschlage"
"Bug Reports" = "https://github.com/dknowles2/pyschlage/issues"
"Homepage" = "https://github.com/dknowles2/pytboss"
"Source Code" = "https://github.com/dknowles2/pytboss"
"Bug Reports" = "https://github.com/dknowles2/pytboss/issues"

[tool.setuptools]
platforms = ["any"]
Expand Down
2 changes: 1 addition & 1 deletion pytboss/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ async def _on_state_received(self, payload: str):
return

async with self._lock:
self._state.update(state.to_dict())
self._state.update(state)
# TODO: Run callbacks concurrently
# TODO: Send copies of state so subscribers can't modify it
for callback in self._state_callbacks:
Expand Down
51 changes: 28 additions & 23 deletions pytboss/grills.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,45 @@
import json
from typing import Any

import js2py
import dukpy

from .exceptions import InvalidGrill

_COMMAND_JS_TMPL = """\
function() {
let formatHex = function(n) {
let t = '0' + parseInt(n).toString(16);
function command() {
var formatHex = function(n) {
var t = '0' + parseInt(n).toString(16);
return t.substring(t.length - 2)
};
let formatDecimal = function(n) {
let t = '000' + parseInt(n).toString(10);
var formatDecimal = function(n) {
var t = '000' + parseInt(n).toString(10);
return t.substring(t.length - 3);
};
%s
}
command.apply(null, dukpy['args']);
"""

_CONTROLLER_JS_TMPL = """\
// Basic polyfill for String.startsWith.
String.prototype.startsWith = function(search, pos){
return this.slice(pos || 0, search.length) === search;
};
function(message) {
let convertTemperature = function(parts, startIndex) {
let temp = (
function parse(message) {
var convertTemperature = function(parts, startIndex) {
var temp = (
parts[startIndex] * 100 +
parts[startIndex + 1] * 10 +
parts[startIndex + 2]
);
return temp === 960 ? null : temp;
};
let parseHexMessage = function(_data) {
const parsed = [];
for (let i = 0; i < _data.length; i+=2) {
parsed.push(parseInt(_data.substring(i, i+2), 16));
var parseHexMessage = function(data) {
var parsed = [];
for (var i = 0; i < data.length; i+=2) {
parsed.push(parseInt(data.substring(i, i+2), 16));
}
return parsed;
};
%s
}
parse(dukpy['message']);
"""


Expand All @@ -70,11 +68,14 @@ class Command:
@classmethod
def from_dict(cls, cmd_dict) -> "Command":
"""Creates a Command from a JSON dict."""
js_func = cmd_dict["function"]
if js_func:
js_func = js_func.replace("let ", "var ")
return cls(
name=cmd_dict["name"],
slug=cmd_dict["slug"],
_hex=cmd_dict["hexadecimal"],
_js_func=cmd_dict["function"],
_js_func=js_func,
)

def __call__(self, *args) -> str:
Expand All @@ -85,7 +86,7 @@ def __call__(self, *args) -> str:
if self._js_func is None:
raise NotImplementedError

return js2py.eval_js(_COMMAND_JS_TMPL % self._js_func)(*args)
return dukpy.evaljs(_COMMAND_JS_TMPL % self._js_func, args=args)


@dataclass
Expand All @@ -107,27 +108,31 @@ class ControlBoard:
@classmethod
def from_dict(cls, ctrl_dict) -> "ControlBoard":
"""Creates a ControlBoard from a JSON dict."""
status_js_func = ctrl_dict["status_function"]
temperatures_js_func = ctrl_dict["temperature_function"]
return cls(
name=ctrl_dict["name"],
commands={
c["slug"]: Command.from_dict(c)
for c in ctrl_dict["control_board_commands"]
},
_status_js_func=ctrl_dict["status_function"],
_temperatures_js_func=ctrl_dict["temperature_function"],
_status_js_func=status_js_func.replace("let ", "var "),
_temperatures_js_func=temperatures_js_func.replace("let ", "var "),
)

def parse_status(self, message) -> dict | None:
"""Parses a status message."""
if not self._status_js_func:
raise NotImplementedError
return js2py.eval_js(_CONTROLLER_JS_TMPL % self._status_js_func)(message)
return dukpy.evaljs(_CONTROLLER_JS_TMPL % self._status_js_func, message=message)

def parse_temperatures(self, message) -> dict | None:
"""Parses a temperatures message."""
if not self._temperatures_js_func:
raise NotImplementedError
return js2py.eval_js(_CONTROLLER_JS_TMPL % self._temperatures_js_func)(message)
return dukpy.evaljs(
_CONTROLLER_JS_TMPL % self._temperatures_js_func, message=message
)


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
bleak==0.21.1
bleak_retry_connector==3.4.0
js2py==0.74
dukpy==0.3.0
33 changes: 11 additions & 22 deletions tests/test_ble.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
from unittest import mock

import bleak
from bleak_retry_connector import BleakClientWithServiceCache

from pytboss import ble
Expand Down Expand Up @@ -29,19 +30,13 @@ async def test_connect_disconnect(


@mock.patch("bleak_retry_connector.establish_connection")
@mock.patch("bleak.BleakClient", spec=True)
@mock.patch("bleak.BleakClient", spec=True)
@mock.patch("bleak.BLEDevice", spec=True)
@mock.patch("bleak.BLEDevice", spec=True)
async def test_reset_device(
mock_old_device,
mock_new_device,
mock_old_bleak_client,
mock_new_bleak_client,
mock_establish_connection,
):
async def test_reset_device(mock_establish_connection):
mock_old_device = mock.create_autospec(bleak.BLEDevice)
mock_new_device = mock.create_autospec(bleak.BLEDevice)
mock_old_device.name = "OLD DEVICE NAME"
mock_new_device.name = "NEW DEVICE NAME"
mock_old_bleak_client = mock.create_autospec(bleak.BleakClient)
mock_new_bleak_client = mock.create_autospec(bleak.BleakClient)
mock_establish_connection.return_value = mock_old_bleak_client

conn = ble.BleConnection(mock_old_device)
Expand Down Expand Up @@ -75,19 +70,13 @@ async def test_reset_device(


@mock.patch("bleak_retry_connector.establish_connection")
@mock.patch("bleak.BleakClient", spec=True)
@mock.patch("bleak.BleakClient", spec=True)
@mock.patch("bleak.BLEDevice", spec=True)
@mock.patch("bleak.BLEDevice", spec=True)
async def test_reset_device_with_debug_log_subscription(
mock_old_device,
mock_new_device,
mock_old_bleak_client,
mock_new_bleak_client,
mock_establish_connection,
):
async def test_reset_device_with_debug_log_subscription(mock_establish_connection):
mock_old_device = mock.create_autospec(bleak.BLEDevice)
mock_new_device = mock.create_autospec(bleak.BLEDevice)
mock_old_device.name = "OLD DEVICE NAME"
mock_new_device.name = "NEW DEVICE NAME"
mock_old_bleak_client = mock.create_autospec(bleak.BleakClient)
mock_new_bleak_client = mock.create_autospec(bleak.BleakClient)
mock_establish_connection.return_value = mock_old_bleak_client

conn = ble.BleConnection(mock_old_device)
Expand Down

0 comments on commit 35a0317

Please sign in to comment.