Skip to content

Commit 407b003

Browse files
edrasEdras Pacola
andauthored
Version 0.5.1 (#103)
* removing eventlet from webinterface this package is deprecated and should not be used for new projects. socketio use only threading from python * fix installer dependencies pyinstaller needs to add the hidden dependencies of web interface * automate artifacts generation this script: - builds the exe - copy the .bat file to start web interface - zip the contents - download the wheel file from pypi - place everything under dist folder to upload to release page on github * enhance development documentation * bug fix on multidimensional array Only the first indeces of multidimensional matrices were being addressed. Added matrix example on example folder * version 0.5.1 --------- Co-authored-by: Edras Pacola <[email protected]>
1 parent 2b70107 commit 407b003

File tree

13 files changed

+274
-85
lines changed

13 files changed

+274
-85
lines changed

doc/development.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,15 @@ sphinx-build -M html doc build --keep-going
6060
```bash
6161
pyinstaller --noconfirm .\pyx2cscope_win.spec
6262
```
63+
64+
## Creating artifacts to upload to github release page
65+
This script will execute the pyinstaller command listed above,
66+
include the script file to start the web interface, zip
67+
the contents of the dist folder and add the whell file
68+
available on pypi in the dist folder.
69+
70+
```bash
71+
python -m scripts/build.py
72+
```
73+
74+
## Creating artifacts to upload to GitHu

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "pyx2cscope"
7-
version = "0.5.0"
7+
version = "0.5.1"
88
description = "python implementation of X2Cscope"
99
authors = [
1010
"Yash Agarwal",
@@ -32,11 +32,10 @@ pyyaml ="^6.0.1"
3232
numpy = "^1.26.0"
3333
matplotlib = "^3.7.2"
3434
PyQt5 = "^5.15.9"
35-
pyqtgraph= "^0.13.7"
35+
pyqtgraph = "^0.13.7"
3636
mchplnet = "0.3.0"
3737
flask = "^3.0.3"
3838

39-
4039
[tool.ruff]
4140
line-length = 120
4241
# only allow the specified pydocstyle convention

pyx2cscope/__init__.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
"""This module contains the pyx2cscope package.
22
3-
Version: 0.5.0
3+
Version: 0.5.1
44
"""
55

6-
# Apply eventlet monkey patch before any other imports if web interface is requested
7-
import sys
8-
9-
if "-w" in sys.argv or "--web" in sys.argv:
10-
import eventlet
11-
eventlet.monkey_patch()
12-
136
import logging
147

15-
__version__ = "0.5.0"
16-
8+
__version__ = "0.5.1"
179

1810
def set_logger(
1911
level: int = logging.ERROR,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""PyX2CScope array example reference.
2+
3+
This example shows different use cases for single and multidimensional arrays.
4+
5+
We define 3 different arrays:
6+
7+
static uint8_t my_array1D[3] = {3, 2, 1};
8+
static uint8_t my_array2D[2][3] = { {6, 5, 4}, {3, 2, 1} };
9+
static uint8_t my_array3D[2][2][3] = {
10+
{
11+
{12, 11, 10}, {9, 8, 7},
12+
},
13+
{
14+
{6, 5, 4}, {3, 2, 1},
15+
}
16+
};
17+
"""
18+
19+
import logging
20+
21+
from pyx2cscope.utils import get_com_port, get_elf_file_path
22+
from pyx2cscope.x2cscope import X2CScope
23+
24+
# Set up logging
25+
logging.basicConfig(
26+
level=logging.INFO,
27+
filename=__file__ + ".log",
28+
)
29+
30+
# X2C Scope Set up
31+
elf_file = get_elf_file_path()
32+
com_port = get_com_port()
33+
x2c_scope = X2CScope(port=com_port, elf_file=elf_file)
34+
35+
my_array_1d = x2c_scope.get_variable("my_array1D")
36+
my_array_2d = x2c_scope.get_variable("my_array2D")
37+
my_array_3d = x2c_scope.get_variable("my_array3D")
38+
39+
print(my_array_1d.get_value())
40+
# [3, 2, 1]
41+
print(my_array_2d.get_value())
42+
# [6, 5, 4, 3, 2, 1]
43+
print(my_array_3d.get_value())
44+
# [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
45+
46+
my_array_2d_10 = x2c_scope.get_variable("my_array2D[1][0]")
47+
my_array_2d_10.set_value(10)
48+
print(my_array_2d.get_value())
49+
# [6, 5, 4, 10, 2, 1]
50+
51+
my_array_2d[4] = 11
52+
print(my_array_2d.get_value())
53+
# [6, 5, 4, 10, 11, 1]
54+
55+
print(my_array_2d[5])
56+
# 1
57+
58+
my_array_3d_102 = x2c_scope.get_variable("my_array3D[1][0][2]")
59+
my_array_3d_102.set_value(10)
60+
print(my_array_3d.get_value())
61+
# [12, 11, 10, 9, 8, 7, 6, 5, 10, 3, 2, 1]
62+
63+

pyx2cscope/examples/testingArray.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

pyx2cscope/gui/web/app.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
This module holds and handles the main url and forward the relative urls to the specific
44
pages (blueprints).
55
"""
6-
import eventlet
7-
8-
eventlet.monkey_patch()
9-
106
import logging
117
import os
128
import webbrowser
@@ -176,7 +172,8 @@ def main(host="localhost", web_port=5000, new=True, *args, **kwargs):
176172
print("Server is open for external requests!")
177173

178174
if os.environ.get('DEBUG') != 'true':
179-
socketio.run(app, debug=False, host=host, port=web_port)
175+
socketio.run(app, debug=False, host=host, port=web_port,
176+
allow_unsafe_werkzeug=True)
180177
else:
181178
socketio.run(app, debug=True, host=host, port=web_port,
182179
allow_unsafe_werkzeug=True, use_reloader=False)

pyx2cscope/gui/web/extensions.py

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,16 @@
33
This module provides SocketIO configuration and lock creation functions
44
that adapt to the current environment (production or debug mode).
55
"""
6-
import os
7-
86
from flask_socketio import SocketIO
97

10-
# Only enable eventlet in production, not during debugging
11-
if os.environ.get('DEBUG', None) is None: # None means production
12-
import eventlet
13-
eventlet.monkey_patch()
14-
socketio = SocketIO(cors_allowed_origins="*", async_mode='eventlet')
15-
16-
def create_lock():
17-
"""Create an eventlet-based semaphore lock.
8+
socketio = SocketIO(cors_allowed_origins="*", async_mode='threading')
9+
import threading
1810

19-
Returns:
20-
eventlet.semaphore.Semaphore: A semaphore lock for thread synchronization.
21-
"""
22-
return eventlet.semaphore.Semaphore()
23-
else:
24-
socketio = SocketIO(cors_allowed_origins="*", async_mode='threading')
25-
import threading
2611

27-
def create_lock():
28-
"""Create a threading-based lock.
12+
def create_lock():
13+
"""Create a threading-based lock.
2914
30-
Returns:
31-
threading.Lock: A lock for thread synchronization.
32-
"""
33-
return threading.Lock()
15+
Returns:
16+
threading.Lock: A lock for thread synchronization.
17+
"""
18+
return threading.Lock()

pyx2cscope/gui/web/scope.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
This module provides the WebScope class for managing watch and scope variables
44
through the web interface.
55
"""
6+
import numbers
67
import time
78

8-
from pandas.core.dtypes.inference import is_number
9-
109
from pyx2cscope.gui.web import extensions
1110
from pyx2cscope.x2cscope import TriggerConfig, X2CScope
1211

@@ -127,7 +126,7 @@ def set_watch_rate(self, rate):
127126
Args:
128127
rate (float): Polling rate in seconds (must be between 0 and MAX_WATCH_RATE).
129128
"""
130-
if is_number(rate) and 0 < rate < self.MAX_WATCH_RATE:
129+
if isinstance(rate, numbers.Number) and 0 < rate < self.MAX_WATCH_RATE:
131130
self.watch_rate = rate
132131

133132
def clear_watch_var(self):

pyx2cscope/parser/generic_parser.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"""
55

66
import logging
7+
import math
8+
from itertools import product
79

810
from elftools.construct.lib import ListContainer
911
from elftools.dwarf.dwarf_expr import DWARFExprParser
@@ -106,6 +108,7 @@ def _get_base_type_die(self, current_die):
106108
if type_attr:
107109
ref_addr = type_attr.value + current_die.cu.cu_offset
108110
return self.dwarf_info.get_DIE_from_refaddr(ref_addr)
111+
return None
109112

110113
def _get_end_die(self, current_die):
111114
"""Find the end DIE of a type iteratively."""
@@ -224,7 +227,8 @@ def _process_array_type(self, end_die, member_name, offset):
224227
"""
225228
members = {}
226229
array_members = {}
227-
array_size = self._get_array_length(end_die)
230+
array_dimensions = self._get_array_dimensions(end_die)
231+
array_size = math.prod(array_dimensions)
228232
base_type_die = self._get_base_type_die(end_die)
229233
self._process_end_die(members, base_type_die, member_name, offset)
230234
if members:
@@ -241,11 +245,13 @@ def _process_array_type(self, end_die, member_name, offset):
241245
}
242246

243247
# Generate array members, e.g.: array[0], array[1], ..., array[i]
244-
for i in range(array_size):
248+
ranges = [range(d) for d in array_dimensions]
249+
for idx, idx_tuple in enumerate(product(*ranges)):
250+
idx_str = ''.join(f'[{i}]' for i in idx_tuple)
245251
for name, values in members.items():
246-
element_name = name.replace(member_name, f"{member_name}[{i}]")
252+
element_name = name + idx_str
247253
array_members[element_name] = values.copy()
248-
array_members[element_name]["address_offset"] += i * idx_size
254+
array_members[element_name]["address_offset"] += idx * idx_size
249255

250256
return array_members
251257

@@ -344,16 +350,18 @@ def _process_structure_type(self, die, parent_name: str, offset=0):
344350
return members
345351

346352
@staticmethod
347-
def _get_array_length(type_die):
348-
"""Gets the length of an array type."""
349-
array_length = 0
353+
def _get_array_dimensions(type_die):
354+
"""Gets the length of an array type.
355+
356+
Multidimensional arrays have multiple children with the tag DW_TAG_subrange_type.
357+
"""
358+
dimensions = []
350359
for child in type_die.iter_children():
351360
if child.tag == "DW_TAG_subrange_type":
352361
array_length_attr = child.attributes.get("DW_AT_upper_bound")
353362
if array_length_attr:
354-
array_length = array_length_attr.value + 1
355-
break
356-
return array_length
363+
dimensions.append(array_length_attr.value + 1)
364+
return dimensions
357365

358366
@staticmethod
359367
def _process_base_type(end_die, parent_name, offset):

pyx2cscope_win.spec

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@ a = Analysis(
66
['pyx2cscope\\__main__.py'],
77
pathex=[],
88
binaries=[],
9-
datas=[('pyx2cscope\\gui\\web\\static', 'pyx2cscope\\gui\\web\\static'), ('pyx2cscope\\gui\\web\\templates', 'pyx2cscope\\gui\\web\\templates'), ('pyx2cscope\\gui\\img', 'pyx2cscope\\gui\\img')],
10-
hiddenimports=[],
9+
datas=[
10+
('pyx2cscope\\gui\\web\\static', 'pyx2cscope\\gui\\web\\static'),
11+
('pyx2cscope\\gui\\web\\templates', 'pyx2cscope\\gui\\web\\templates'),
12+
('pyx2cscope\\gui\\img', 'pyx2cscope\\gui\\img'),
13+
],
14+
hiddenimports=[
15+
'engineio.async_threading',
16+
'engineio.async_drivers.threading'
17+
],
1118
hookspath=[],
1219
hooksconfig={},
1320
runtime_hooks=[],
@@ -35,6 +42,7 @@ exe = EXE(
3542
entitlements_file=None,
3643
icon=['pyx2cscope\\gui\\img\\pyx2cscope.ico'],
3744
)
45+
3846
coll = COLLECT(
3947
exe,
4048
a.binaries,

0 commit comments

Comments
 (0)