Skip to content

Commit 24e17f1

Browse files
committed
- exclude more packages on builds
- upgrades WebSockets lib - fixes automatic reloading of non-genuine profiles
1 parent 21c83bc commit 24e17f1

10 files changed

Lines changed: 39 additions & 28 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<img align="right" src="https://raw.githubusercontent.com/artisan-roaster-scope/artisan/master/wiki/screenshots/artisan.png" width="70">
22

3-
Artisan
3+
Artisan Scope
44
==========
55
Visual scope for coffee roasters
66

src/artisan-linux.spec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ hiddenimports_list=[
4747
] + collect_submodules('dbus_fast')
4848

4949
EXCLUDES = [
50+
'tkinter',
51+
'mypy',
52+
'hypothesis',
53+
'tornado',
5054
'pkg_resources',
5155
'PyQt5',
5256
'PyQt6.Multimedia',

src/artisan-win.spec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ a = Analysis(['artisan.py'],
158158
hookspath=[],
159159
runtime_hooks=[r'pyinstaller_hooks\rthooks\pyi_rth_mplconfig.py'], # overwrites default MPL runtime hook which keeps loading font cache from (new) temp directory
160160
additional_hooks_dir=[],
161-
excludes=['pkg_resources'],
161+
excludes=['tkinter', 'mypy', 'hypothesis', 'tornado', 'pkg_resources'],
162162
hiddenimports=hiddenimports_list,
163163
win_no_prefer_redirects=False,
164164
win_private_assemblies=False,

src/artisanlib/acaia.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ class ACAIA_TIMER(IntEnum):
237237
HEARTBEAT_FREQUENCY:Final[int] = 5 # send the heartbeat every 5 sec
238238

239239
RELAY_STREAMING:Final[bool] = False # if set, configure Acaia relay (and COSMO) scales to streaming mode, otherwise they work in non-streaming mode reporting only weight changes
240-
WEIGHT_ROUNDING:Final[bool] = False # if set, received weights are rounded to appropriate values based on scale max weight
240+
WEIGHT_ROUNDING:Final[bool] = False # if set, received weights are rounded to appropriate values based on scales readability
241+
# rounding for scales with readability>1 (to 4g), no rounding otherwise
241242

242243

243244
# ISP versions -> device model (CSMO series)
@@ -269,7 +270,7 @@ def __init__(self,
269270
weight_changed_handler:Callable[[float,bool], None],
270271
battery_changed_handler: Callable[[int], None],
271272
tare_pressed_handler: Callable[[], None],
272-
stable_only:bool=True, # if True only stable weight readings are reported by weight_changed_signal
273+
stable_only:bool=False, # if True only stable weight readings are reported by weight_changed_signal
273274
decimals:int=1) -> None: # number of significant decimals (0, 1, ..) of the weight signal
274275
super().__init__()
275276

@@ -554,9 +555,9 @@ def update_weight(self, value:float|None, stable:bool|None = False) -> None:
554555
if self._logging:
555556
_log.debug('update_weight(%s,%s)', value, stable)
556557
if value is not None and (not self.stable_only or stable):
557-
if WEIGHT_ROUNDING and self.repeatability > 1:
558-
# round to full 5g
559-
value = round_base(value, 5)
558+
if WEIGHT_ROUNDING and self.repeatability >= 1:
559+
# round to full 4g
560+
value = round_base(value, 4)
560561
## round to full 10g
561562
##value = round(value, -1)
562563
# convert the weight in g delivered with one decimal to an int

src/artisanlib/main.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,7 @@ def __init__(self, parent:QWidget|None = None, *, locale:str, artisanviewerFirst
22642264
# self.exportMenu.addAction(fileExportRoastLoggerAction)
22652265

22662266
self.convMenu:QMenu = QMenu(QApplication.translate('Menu', 'Convert To'))
2267+
22672268
fileConvertFahrenheitAction = QAction(QApplication.translate('Menu', 'Fahrenheit...'), self)
22682269
fileConvertFahrenheitAction.triggered.connect(self.fileConvertToFahrenheit)
22692270
self.convMenu.addAction(fileConvertFahrenheitAction)
@@ -12424,7 +12425,7 @@ def keyPressEvent(self, a0: 'QKeyEvent|None') -> None: # pyright: ignore [report
1242412425
#meta_modifier = modifiers == Qt.KeyboardModifier.MetaModifier # Control on macOS, Meta on Windows
1242512426
#uncomment next line to find the integer value of a k
1242612427
#print(k,a0.text())
12427-
#_log.debug("PRINT key: %s",k)
12428+
# _log.debug("PRINT key: %s",k)
1242812429

1242912430
# numberkeys = [48,49,50,51,52,53,54,55,56,57] # keycodes for number keys 0,1,...,9
1243012431
numberkeys = [
@@ -13714,7 +13715,9 @@ def loadFile(self, filename:str, quiet:bool = False) -> None:
1371413715
org_obj_extra_devs = []
1371513716
if res:
1371613717
# we avoid the reset within setProfile as we just did a reset and do not want to confuse the ExtraDeviceSettingsBackup
13717-
res = self.setProfileDict(filename,obj_dict,quiet=quiet,reset=False, validate_signature=True)
13718+
# if quite=True (eg on reloading profile after conversions) we don't validate the signature to allow the
13719+
# reloading of non-valid profiles that have been loaded before the conversion
13720+
res = self.setProfileDict(filename,obj_dict,quiet=quiet,reset=False, validate_signature=not quiet)
1371813721
if res:
1371913722
#order custom events
1372013723
self.orderEvents()
@@ -15659,7 +15662,7 @@ def validateProfileDict(self, profile_dict:dict[str,Any], quiet:bool=True, valid
1565915662
profile:ProfileData = ta.validate_python(profile_dict)
1566015663
if self.official_build and validate_signature and ('version' not in profile or QVersionNumber.fromString(profile['version'])[0] >= QVersionNumber(4,2,0)):
1566115664
# # testing:
15662-
# if self.official_build and validate_signature and 'version' in profile and 'signature' in profile:
15665+
# if validate_signature and 'version' in profile and 'signature' in profile:
1566315666
# official builds validate all profile signatures for files generated by Artisan versions >= v4.2
1566415667
# we validate the signature
1566515668
try:

src/artisanlib/util.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
from artisanlib.atypes import ProfileData # pylint: disable=unused-import
5252
from proto import artisan_roast_pb2 # pylint: disable=unused-import
5353

54-
from artisanlib.atypes import ProfileData
5554

5655
##
5756

@@ -1379,7 +1378,7 @@ def deserialize(filename:str) -> dict[str, Any]:
13791378

13801379
def csv_load(csvFile:io.TextIOWrapper) -> 'ProfileData':
13811380
import csv
1382-
profile = ProfileData()
1381+
profile:ProfileData = {}
13831382

13841383
data = csv.reader(csvFile,delimiter='\t')
13851384
#read file header

src/artisanlib/weblcds.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,17 @@
4545

4646
class WebView:
4747

48-
__slots__ = [ '_loop', '_thread', '_app', '_port', '_last_send', '_last_message', '_min_send_interval', '_resource_path', '_index_path', '_websocket_path', '_runner' ]
48+
__slots__ = [ '_loop', '_thread', '_app', 'websockets_appkey', '_port', '_last_send', '_last_message',
49+
'_min_send_interval', '_resource_path', '_index_path', '_websocket_path', '_runner' ]
4950

5051
def __init__(self, port:int, resource_path:str, index_path:str, websocket_path:str) -> None:
5152

5253
self._loop: asyncio.AbstractEventLoop|None = None # the asyncio loop
5354
self._thread: Thread|None = None # the thread running the asyncio loop
5455
self._app = web.Application(debug=True)
55-
self._app['websockets'] = weakref.WeakSet()
56+
self.websockets_appkey = web.AppKey('websockets', weakref.WeakSet[web.WebSocketResponse])
57+
self._app[self.websockets_appkey] = weakref.WeakSet()
58+
5659
self._app.on_shutdown.append(self.on_shutdown)
5760

5861
self._last_send:float = time.time() # timestamp of the last message send to the clients
@@ -88,13 +91,13 @@ async def send_msg_to_ws(self, ws:web.WebSocketResponse, message:str) -> None:
8891
except Exception as e: # pylint: disable=broad-except
8992
_log.exception(e)
9093
try:
91-
self._app['websockets'].discard(ws)
94+
self._app[self.websockets_appkey].discard(ws)
9295
except Exception as ex: # pylint: disable=broad-except
9396
_log.exception(ex)
9497

9598
async def send_msg_to_all(self, message:str) -> None:
96-
if 'websockets' in self._app and self._app['websockets'] is not None:
97-
ws_set = set(self._app['websockets'])
99+
if self.websockets_appkey in self._app:
100+
ws_set = self._app[self.websockets_appkey]
98101
for ws in ws_set:
99102
await self.send_msg_to_ws(ws, message)
100103

@@ -116,7 +119,7 @@ def send_msg(self, message:str, timeout:float|None = 0.2) -> None:
116119
async def websocket_handler(self, request: 'Request') -> web.WebSocketResponse:
117120
ws:web.WebSocketResponse = web.WebSocketResponse()
118121
await ws.prepare(request)
119-
request.app['websockets'].add(ws)
122+
request.app[self.websockets_appkey].add(ws)
120123
try:
121124
async for msg in ws:
122125
if msg.type == WSMsgType.TEXT:
@@ -126,14 +129,14 @@ async def websocket_handler(self, request: 'Request') -> web.WebSocketResponse:
126129
elif msg.type == WSMsgType.ERROR:
127130
_log.error('ws connection closed with exception %s', ws.exception())
128131
finally:
129-
request.app['websockets'].discard(ws)
132+
request.app[self.websockets_appkey].discard(ws)
130133
return ws
131134

132-
@staticmethod
133-
async def on_shutdown(app:web.Application) -> None:
134-
for ws in set(app['websockets']):
135+
# @staticmethod
136+
async def on_shutdown(self, app:web.Application) -> None:
137+
for ws in app[self.websockets_appkey]:
135138
await ws.close(code=WSCloseCode.GOING_AWAY,
136-
message='Server shutdown')
139+
message=b'Server shutdown')
137140

138141
async def startup(self) -> None:
139142
self._runner = web.AppRunner(self._app)

src/plus/controller.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,10 @@ def connect(clear_on_failure: bool =False, interactive: bool = True) -> None:
284284
message = QApplication.translate(
285285
'Plus', 'Authentication failed'
286286
)
287-
message = (
288-
f'{aw.plus_account} {message}'
289-
) # @UndefinedVariable
287+
if aw.plus_account is not None: # pyright:ignore[reportUnnecessaryComparison] # pyright infers type str here, which is wrong!
288+
message = (
289+
f'{aw.plus_account} {message}'
290+
) # @UndefinedVariable
290291
aw.sendmessageSignal.emit(
291292
message, True, None
292293
) # @UndefinedVariable

src/requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pytest-datadir==1.8.0
2929
#PyVirtualDisplay==3.0
3030
#pytest-bdd==6.1.1
3131
#pytest-benchmark==4.0.0
32-
hypothesis>=6.161.6
32+
hypothesis>=6.163.0
3333
coverage>=7.15.2
3434
coverage-badge==1.1.2
3535
codespell==2.4.3

src/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pyusb==1.3.1
4040
persist-queue==1.1.0
4141
portalocker==3.2.0
4242
xlrd==2.0.2
43-
websockets==16.1
43+
websockets==17.0
4444
PyYAML==6.0.3
4545
psutil==7.2.2
4646
protobuf==7.35.1

0 commit comments

Comments
 (0)