Skip to content

Commit 9c6e1cf

Browse files
committed
Use observe from enaml and improve speedups
1 parent a568c50 commit 9c6e1cf

File tree

8 files changed

+49
-57
lines changed

8 files changed

+49
-57
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 0.12.2
2+
- Use @observe from enaml to avoid unecessary notifications during init_widget
3+
- Improve speedup code
4+
15
# 0.12.1
26
- Support python 3.13
37
- Cleanup type errors and lint errors

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
setup(
1717
name='enaml-web',
18-
version='0.12.1',
18+
version='0.12.2',
1919
author='CodeLV',
2020
author_email='[email protected]',
2121
url='https://github.com/codelv/enaml-web',
@@ -25,7 +25,7 @@
2525
long_description_content_type="text/markdown",
2626
requires=['enaml'],
2727
python_requires='>=3.9',
28-
install_requires=['enaml >= 0.9.8', 'lxml>=3.4.0'],
28+
install_requires=['enaml >= 0.15.0', 'lxml>=3.4.0'],
2929
optional_requires=[
3030
'Pygments', 'Markdown', 'nbconvert', # extra components
3131
],

src/speedups.c

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,78 +12,74 @@ Created on Feb 10, 2022
1212
#define PY_SSIZE_T_CLEAN
1313
#include <Python.h>
1414

15-
const char * alphabet = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
15+
const char alphabet[] = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
16+
// C adds a null at the end so it needs -1
17+
const uint64_t alphabet_size = sizeof(alphabet) / sizeof(alphabet[0]) - 1;
18+
const uint8_t id_size = 8;
19+
20+
static PyObject* Tag = 0;
21+
static PyObject* children_str = 0;
1622

1723
/**
1824
* Generate a short ID (8 characters)
1925
*/
20-
static PyObject * gen_id(PyObject *self, PyObject *obj)
26+
static PyObject* gen_id(PyObject* mod, PyObject* obj)
2127
{
22-
// Builtin ID
23-
PyObject *id = PyLong_FromVoidPtr(obj);
24-
if (id && PySys_Audit("builtins.id", "O", id) < 0) {
25-
Py_DECREF(id);
26-
return NULL;
27-
}
28-
// TODO: Should there be some randomness?
29-
uint64_t number = PyLong_AsUnsignedLong(id);
30-
uint8_t index = 0;
31-
char buf[8];
32-
while (index < 8)
28+
uint64_t number = (uint64_t) obj;
29+
char buf[id_size];
30+
for (uint8_t index = 0; index < id_size; index++)
3331
{
34-
// Mod must match sizeof alphabet
35-
lldiv_t r = lldiv(number, 59);
32+
lldiv_t r = lldiv(number, alphabet_size);
3633
number = r.quot;
3734
buf[index] = alphabet[r.rem];
38-
index += 1;
3935
}
40-
Py_DECREF(id);
41-
return PyUnicode_FromStringAndSize(buf, 8);
36+
return PyUnicode_FromStringAndSize(buf, id_size);
4237
}
4338

4439
/**
4540
* Lookup the index of the child tag from the parent's children list ignoring
4641
* any pattern nodes. This provides about a 30% speedup.
4742
*/
48-
static PyObject * lookup_child_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
43+
static PyObject* lookup_child_index(PyObject* mod, PyObject *const *args, Py_ssize_t nargs)
4944
{
5045
if (nargs != 2) {
5146
PyErr_SetString( PyExc_ValueError, "must take exactly 2 arguments" );
5247
return 0;
5348
}
5449

55-
PyObject* module = PyImport_ImportModule("web.components.html");
56-
if (!module) {
57-
PyErr_SetString( PyExc_ImportError, "Could not import web.components.html" );
58-
return 0;
59-
}
50+
// Deferred import of web.components.html.Tag
51+
if ( !Tag ) {
52+
PyObject* module = PyImport_ImportModule("web.components.html");
53+
if (!module) {
54+
PyErr_SetString( PyExc_ImportError, "Could not import web.components.html" );
55+
return 0;
56+
}
6057

61-
PyObject* Tag = PyObject_GetAttrString(module, "Tag");
62-
Py_DECREF(module);
63-
if (!Tag) {
64-
PyErr_SetString( PyExc_ImportError, "Could not import web.components.html.Tag" );
65-
return 0;
58+
Tag = PyObject_GetAttrString(module, "Tag");
59+
Py_DECREF(module);
60+
if ( !Tag ) {
61+
PyErr_SetString( PyExc_ImportError, "Could not import web.components.html.Tag" );
62+
return 0;
63+
}
6664
}
6765

6866
PyObject* parent = args[0];
6967
PyObject* child = args[1];
7068
if (!PyObject_IsInstance(parent, Tag) || !PyObject_IsInstance(child, Tag)) {
7169
PyErr_SetString( PyExc_TypeError, "Both arguments must be Tags" );
72-
Py_DECREF(Tag);
7370
return 0;
7471
}
7572

76-
PyObject* children = PyObject_GetAttrString(parent, "_children");
73+
PyObject* children = PyObject_GetAttr(parent, children_str);
7774
if (!children || !PyList_Check(children)) {
7875
PyErr_SetString( PyExc_TypeError, "Tag's children must be a list" );
79-
Py_DECREF(children);
80-
Py_DECREF(Tag);
76+
Py_XDECREF(children);
8177
return 0;
8278
}
8379

8480
uint32_t index = 0;
8581
uint8_t found = 0;
86-
for (uint32_t i = 0; i < PyList_Size(children); i++) {
82+
for (uint32_t i = 0; i < PyList_GET_SIZE(children); i++) {
8783
PyObject* c = PyList_GET_ITEM(children, i);
8884
if (c == child)
8985
{
@@ -95,7 +91,6 @@ static PyObject * lookup_child_index(PyObject *self, PyObject *const *args, Py_s
9591
index += 1;
9692
}
9793
Py_DECREF(children);
98-
Py_DECREF(Tag);
9994

10095
if (!found) {
10196
PyErr_SetString( PyExc_KeyError, "Child not found" );
@@ -121,5 +116,9 @@ static PyModuleDef speedups_module = {
121116
PyMODINIT_FUNC
122117
PyInit_speedups(void)
123118
{
119+
children_str = PyUnicode_InternFromString("_children");
120+
if ( !children_str )
121+
return 0;
122+
124123
return PyModule_Create( &speedups_module );
125124
}

web/components/code.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
@author: jrm
1111
"""
1212

13-
from atom.api import Str, Typed, ForwardTyped, ChangeDict, observe
14-
from enaml.core.declarative import d_
13+
from atom.api import Str, Typed, ForwardTyped, ChangeDict
14+
from enaml.core.declarative import d_, observe
1515
from .raw import Raw, ProxyRawNode
1616

1717

web/components/html.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323
ForwardTyped,
2424
Typed,
2525
Coerced,
26-
observe,
2726
set_default,
2827
ChangeDict,
2928
)
30-
from enaml.core.declarative import d_, Declarative
29+
from enaml.core.declarative import d_, Declarative, observe
3130
from enaml.widgets.toolkit_object import ToolkitObject, ProxyToolkitObject
3231

3332
try:

web/components/ipynb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
from __future__ import annotations
1414

15-
from atom.api import Int, Typed, ForwardTyped, ChangeDict, observe
16-
from enaml.core.declarative import d_
15+
from atom.api import Int, Typed, ForwardTyped, ChangeDict
16+
from enaml.core.declarative import d_, observe
1717
from .raw import Raw, ProxyRawNode
1818

1919

web/components/md.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,8 @@
1111
"""
1212

1313
from typing import Any, Optional
14-
from atom.api import (
15-
Typed,
16-
ForwardTyped,
17-
Enum,
18-
Int,
19-
Bool,
20-
List,
21-
Dict,
22-
ChangeDict,
23-
observe,
24-
)
25-
from enaml.core.declarative import d_
14+
from atom.api import Typed, ForwardTyped, Enum, Int, Bool, List, Dict, ChangeDict
15+
from enaml.core.declarative import d_, observe
2616
from .html import Tag
2717
from .raw import Raw, ProxyRawNode
2818

web/components/raw.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
from __future__ import annotations
1414

1515
from typing import Union, Optional
16-
from atom.api import ForwardTyped, Instance, Typed, ChangeDict, set_default, observe
16+
from atom.api import ForwardTyped, Instance, Typed, ChangeDict, set_default
1717
from lxml.etree import _Element as Element
18-
from enaml.core.declarative import d_
18+
from enaml.core.declarative import d_, observe
1919
from .html import Tag, ProxyTag
2020

2121
SourceType = Optional[Union[str, list[Element], Element]]

0 commit comments

Comments
 (0)