tkinterweb 4.17.2__py3-none-any.whl → 4.17.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tkinterweb/bindings.py +11 -9
- tkinterweb/handlers.py +32 -45
- tkinterweb/htmlwidgets.py +4 -2
- tkinterweb/utilities.py +9 -8
- {tkinterweb-4.17.2.dist-info → tkinterweb-4.17.3.dist-info}/METADATA +1 -1
- {tkinterweb-4.17.2.dist-info → tkinterweb-4.17.3.dist-info}/RECORD +9 -9
- {tkinterweb-4.17.2.dist-info → tkinterweb-4.17.3.dist-info}/LICENSE.md +0 -0
- {tkinterweb-4.17.2.dist-info → tkinterweb-4.17.3.dist-info}/WHEEL +0 -0
- {tkinterweb-4.17.2.dist-info → tkinterweb-4.17.3.dist-info}/top_level.txt +0 -0
tkinterweb/bindings.py
CHANGED
|
@@ -532,13 +532,13 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
532
532
|
self.queue_after = None
|
|
533
533
|
self.queue = None
|
|
534
534
|
|
|
535
|
-
def post_to_queue(self, callback):
|
|
535
|
+
def post_to_queue(self, callback, thread_safe=True):
|
|
536
536
|
"""Use this method to send a callback to TkinterWeb's thread-safety queue. The callback will be evaluated on the main thread.
|
|
537
537
|
Use this when running Tkinter commands from within a thread.
|
|
538
538
|
If the queue is not running (i.e. threading is disabled), the callback will be evaluated immediately.
|
|
539
539
|
|
|
540
540
|
New in version 4.9."""
|
|
541
|
-
if self.queue:
|
|
541
|
+
if thread_safe and self.queue:
|
|
542
542
|
self.queue.put(callback)
|
|
543
543
|
else:
|
|
544
544
|
callback()
|
|
@@ -546,6 +546,7 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
546
546
|
def post_event(self, event, thread_safe=False):
|
|
547
547
|
"Generate a virtual event."
|
|
548
548
|
# NOTE: when thread_safe=True, this method is thread-safe
|
|
549
|
+
# Would you believe that?
|
|
549
550
|
if not self.events_enabled:
|
|
550
551
|
return
|
|
551
552
|
|
|
@@ -565,6 +566,7 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
565
566
|
def post_message(self, message, thread_safe=False):
|
|
566
567
|
"Post a message."
|
|
567
568
|
# NOTE: when thread_safe=True, this method is thread-safe
|
|
569
|
+
# Amazing stuff, eh?
|
|
568
570
|
if not self.messages_enabled:
|
|
569
571
|
return
|
|
570
572
|
|
|
@@ -722,16 +724,16 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
722
724
|
else:
|
|
723
725
|
return utilities.cache_download(url, *args, insecure=self.insecure_https, cafile=self.ssl_cafile, headers=tuple(self.headers.items()), timeout=self.request_timeout)
|
|
724
726
|
|
|
725
|
-
def _thread_check(self, callback, *args, **kwargs):
|
|
727
|
+
def _thread_check(self, callback, url, *args, **kwargs):
|
|
726
728
|
if not self.downloads_have_occured:
|
|
727
729
|
self.downloads_have_occured = True
|
|
728
730
|
|
|
729
|
-
if not self.threading_enabled:
|
|
730
|
-
callback(*args, **kwargs)
|
|
731
|
+
if not self.threading_enabled or url.startswith("file://"):
|
|
732
|
+
callback(url, *args, **kwargs)
|
|
731
733
|
elif len(self.active_threads) >= self.maximum_thread_count:
|
|
732
|
-
self.after(500, lambda callback=callback, args=args: self._thread_check(callback, *args, **kwargs))
|
|
734
|
+
self.after(500, lambda callback=callback, url=url, args=args: self._thread_check(callback, url, *args, **kwargs))
|
|
733
735
|
else:
|
|
734
|
-
thread = utilities.StoppableThread(target=callback, args=args, kwargs=kwargs)
|
|
736
|
+
thread = utilities.StoppableThread(target=callback, args=(url, *args,), kwargs=kwargs)
|
|
735
737
|
thread.start()
|
|
736
738
|
|
|
737
739
|
def _begin_download(self):
|
|
@@ -747,9 +749,9 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
747
749
|
|
|
748
750
|
self.active_threads.remove(thread)
|
|
749
751
|
if len(self.active_threads) == 0:
|
|
750
|
-
self.post_to_queue(self._handle_load_finish)
|
|
752
|
+
self.post_to_queue(self._handle_load_finish, thread.is_subthread)
|
|
751
753
|
else:
|
|
752
|
-
self.post_to_queue(lambda: self._handle_load_finish(False))
|
|
754
|
+
self.post_to_queue(lambda: self._handle_load_finish(False), thread.is_subthread)
|
|
753
755
|
|
|
754
756
|
def _finish_resource_load(self, message, url, resource, success):
|
|
755
757
|
# NOTE: this must run in the main thread
|
tkinterweb/handlers.py
CHANGED
|
@@ -471,7 +471,7 @@ class ScriptManager(utilities.BaseManager):
|
|
|
471
471
|
attributes = dict(zip(attributes[::2], attributes[1::2])) # Make attributes a dict
|
|
472
472
|
|
|
473
473
|
if "src" in attributes:
|
|
474
|
-
self.html._thread_check(self.fetch_scripts,
|
|
474
|
+
self.html._thread_check(self.fetch_scripts, self.html.resolve_url(attributes["src"]), attributes)
|
|
475
475
|
elif "defer" in attributes:
|
|
476
476
|
self.pending_scripts.append((attributes, tag_contents))
|
|
477
477
|
else:
|
|
@@ -484,22 +484,22 @@ class ScriptManager(utilities.BaseManager):
|
|
|
484
484
|
thread = self.html._begin_download()
|
|
485
485
|
|
|
486
486
|
if url and thread.isrunning():
|
|
487
|
-
self.html.post_message(f"Fetching script from {utilities.shorten(url)}",
|
|
487
|
+
self.html.post_message(f"Fetching script from {utilities.shorten(url)}", thread.is_subthread)
|
|
488
488
|
try:
|
|
489
489
|
data = self.html.download_url(url)[1]
|
|
490
490
|
except Exception as error:
|
|
491
491
|
self.html.post_to_queue(lambda message=f"ERROR: could not load script {url}: {error}",
|
|
492
|
-
url=url: self.html._finish_resource_load(message, url, "script", False))
|
|
492
|
+
url=url: self.html._finish_resource_load(message, url, "script", False), thread.is_subthread)
|
|
493
493
|
|
|
494
494
|
if data and thread.isrunning():
|
|
495
495
|
if "defer" in attributes:
|
|
496
496
|
self.pending_scripts.append((attributes, data))
|
|
497
497
|
else:
|
|
498
|
-
self.html.post_to_queue(lambda attributes=attributes, data=data: self.html.on_script(attributes, data))
|
|
498
|
+
self.html.post_to_queue(lambda attributes=attributes, data=data: self.html.on_script(attributes, data), thread.is_subthread)
|
|
499
499
|
|
|
500
500
|
if url:
|
|
501
501
|
self.html.post_to_queue(lambda message=f"Successfully loaded {utilities.shorten(url)}",
|
|
502
|
-
url=url: self.html._finish_resource_load(message, url, "script", True))
|
|
502
|
+
url=url: self.html._finish_resource_load(message, url, "script", True), thread.is_subthread)
|
|
503
503
|
|
|
504
504
|
self.html._finish_download(thread)
|
|
505
505
|
|
|
@@ -532,14 +532,9 @@ class StyleManager(utilities.BaseManager):
|
|
|
532
532
|
except tk.TclError:
|
|
533
533
|
return
|
|
534
534
|
|
|
535
|
-
if (
|
|
536
|
-
("
|
|
537
|
-
|
|
538
|
-
):
|
|
539
|
-
if url.startswith("file://"):
|
|
540
|
-
self.fetch_styles(node, url)
|
|
541
|
-
else:
|
|
542
|
-
self.html._thread_check(self.fetch_styles, node, url)
|
|
535
|
+
if (("stylesheet" in rel)
|
|
536
|
+
and ("all" in media or "screen" in media)):
|
|
537
|
+
self.html._thread_check(self.fetch_styles, url, node)
|
|
543
538
|
# Onload is fired if and when the stylesheet is parsed
|
|
544
539
|
elif "icon" in rel:
|
|
545
540
|
self.html.icon = url
|
|
@@ -553,8 +548,7 @@ class StyleManager(utilities.BaseManager):
|
|
|
553
548
|
try:
|
|
554
549
|
new_url = self.html.resolve_url(new_url, parent_url)
|
|
555
550
|
self.html.post_message(f"Loading stylesheet from {utilities.shorten(new_url)}")
|
|
556
|
-
|
|
557
|
-
self.html._thread_check(self.fetch_styles, url=new_url)
|
|
551
|
+
self.html._thread_check(self.fetch_styles, new_url)
|
|
558
552
|
|
|
559
553
|
except Exception as error:
|
|
560
554
|
self.html.post_message(f"ERROR: could not load stylesheet {new_url}: {error}")
|
|
@@ -567,21 +561,21 @@ class StyleManager(utilities.BaseManager):
|
|
|
567
561
|
newurl = f"url('{newurl}')"
|
|
568
562
|
return newurl
|
|
569
563
|
|
|
570
|
-
def fetch_styles(self,
|
|
564
|
+
def fetch_styles(self, url=None, node=None):
|
|
571
565
|
"Fetch stylesheets and parse the CSS code they contain"
|
|
572
566
|
# NOTE: this runs in a thread
|
|
573
567
|
|
|
574
568
|
thread = self.html._begin_download()
|
|
575
569
|
if url and thread.isrunning():
|
|
576
|
-
self.html.post_message(f"Fetching stylesheet from {utilities.shorten(url)}",
|
|
570
|
+
self.html.post_message(f"Fetching stylesheet from {utilities.shorten(url)}", thread.is_subthread)
|
|
577
571
|
try:
|
|
578
572
|
data = self.html.download_url(url)[1]
|
|
579
573
|
if data and thread.isrunning():
|
|
580
|
-
self.html.post_to_queue(lambda node=node, url=url, data=data: self._finish_fetching_styles(node, url, data))
|
|
574
|
+
self.html.post_to_queue(lambda node=node, url=url, data=data: self._finish_fetching_styles(node, url, data), thread.is_subthread)
|
|
581
575
|
|
|
582
576
|
except Exception as error:
|
|
583
577
|
self.html.post_to_queue(lambda message=f"ERROR: could not load stylesheet {url}: {error}",
|
|
584
|
-
url=url: self.html._finish_resource_load(message, url, "stylesheet", False))
|
|
578
|
+
url=url: self.html._finish_resource_load(message, url, "stylesheet", False), thread.is_subthread)
|
|
585
579
|
|
|
586
580
|
self.html._finish_download(thread)
|
|
587
581
|
|
|
@@ -651,7 +645,7 @@ class ImageManager(utilities.BaseManager):
|
|
|
651
645
|
self.bad_paths.add(url)
|
|
652
646
|
|
|
653
647
|
if not self.html.ignore_invalid_images:
|
|
654
|
-
image, data_is_image = self.check_images(utilities.BROKEN_IMAGE, name, url, "image/png")
|
|
648
|
+
image, data_is_image = self.check_images(utilities.BROKEN_IMAGE, name, url, "image/png", False)
|
|
655
649
|
image = imageutils.data_to_image(image, name, "image/png", data_is_image)
|
|
656
650
|
|
|
657
651
|
self.loaded_images.setdefault(name, set()).add(image)
|
|
@@ -692,10 +686,7 @@ class ImageManager(utilities.BaseManager):
|
|
|
692
686
|
else:
|
|
693
687
|
url = url.split("), url(", 1)[0].replace("'", "").replace('"', "")
|
|
694
688
|
url = self.html.resolve_url(url)
|
|
695
|
-
|
|
696
|
-
self.fetch_images(url, name)
|
|
697
|
-
else:
|
|
698
|
-
self.html._thread_check(self.fetch_images, url, name)
|
|
689
|
+
self.html._thread_check(self.fetch_images, url, name)
|
|
699
690
|
|
|
700
691
|
return list((name, self.html.register(self._on_image_delete)))
|
|
701
692
|
|
|
@@ -705,23 +696,26 @@ class ImageManager(utilities.BaseManager):
|
|
|
705
696
|
|
|
706
697
|
thread = self.html._begin_download()
|
|
707
698
|
if thread.isrunning():
|
|
708
|
-
self.html.post_message(f"Fetching image from {utilities.shorten(url)}",
|
|
699
|
+
self.html.post_message(f"Fetching image from {utilities.shorten(url)}", thread.is_subthread)
|
|
709
700
|
|
|
710
701
|
if url == self.html.base_url:
|
|
711
|
-
self.html.post_to_queue(lambda url=url, name=name, error="ERROR: image url not specified":
|
|
702
|
+
self.html.post_to_queue(lambda url=url, name=name, error="ERROR: image url not specified":
|
|
703
|
+
self._on_image_error(url, name, error), thread.is_subthread)
|
|
712
704
|
else:
|
|
713
705
|
try:
|
|
714
706
|
url, data, filetype, code = self.html.download_url(url)
|
|
715
|
-
data, data_is_image = self.check_images(data, name, url, filetype)
|
|
707
|
+
data, data_is_image = self.check_images(data, name, url, filetype, thread.is_subthread)
|
|
716
708
|
|
|
717
709
|
if thread.isrunning():
|
|
718
|
-
self.html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
710
|
+
self.html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
711
|
+
self.finish_fetching_images(data, name, url, filetype, data_is_image), thread.is_subthread)
|
|
719
712
|
except Exception as error:
|
|
720
|
-
self.html.post_to_queue(lambda url=url, name=name, error=f"ERROR: could not load image {url}: {error}":
|
|
713
|
+
self.html.post_to_queue(lambda url=url, name=name, error=f"ERROR: could not load image {url}: {error}":
|
|
714
|
+
self._on_image_error(url, name, error), thread.is_subthread)
|
|
721
715
|
|
|
722
716
|
self.html._finish_download(thread)
|
|
723
717
|
|
|
724
|
-
def check_images(self, data, name, url, filetype):
|
|
718
|
+
def check_images(self, data, name, url, filetype, thread_safe):
|
|
725
719
|
"Invert images if needed and convert SVG images to PNGs."
|
|
726
720
|
# NOTE: this runs in a thread
|
|
727
721
|
|
|
@@ -738,7 +732,7 @@ class ImageManager(utilities.BaseManager):
|
|
|
738
732
|
data_is_image = True
|
|
739
733
|
except (ImportError, ModuleNotFoundError,):
|
|
740
734
|
error = f"ERROR: could not invert the image {url}: PIL and PIL.ImageTk must be installed."
|
|
741
|
-
self.html.post_to_queue(lambda url=url, name=name, error=error: self._on_image_error(url, name, error))
|
|
735
|
+
self.html.post_to_queue(lambda url=url, name=name, error=error: self._on_image_error(url, name, error), thread_safe)
|
|
742
736
|
|
|
743
737
|
return data, data_is_image
|
|
744
738
|
|
|
@@ -893,10 +887,7 @@ class ObjectManager(utilities.BaseManager):
|
|
|
893
887
|
return
|
|
894
888
|
|
|
895
889
|
self.html.post_message(f"Creating object from {utilities.shorten(data)}")
|
|
896
|
-
|
|
897
|
-
self.fetch_objects(node, data, straight=True)
|
|
898
|
-
else:
|
|
899
|
-
self.html._thread_check(self.fetch_objects, node, data)
|
|
890
|
+
self.html._thread_check(self.fetch_objects, data, node)
|
|
900
891
|
|
|
901
892
|
def _on_object_value_change(self, node, attribute, value):
|
|
902
893
|
if attribute == "data":
|
|
@@ -907,7 +898,7 @@ class ObjectManager(utilities.BaseManager):
|
|
|
907
898
|
# Force reset because it might contain widgets that are added internally
|
|
908
899
|
self.html.widget_manager.map_node(node, True)
|
|
909
900
|
|
|
910
|
-
def fetch_objects(self,
|
|
901
|
+
def fetch_objects(self, url, node):
|
|
911
902
|
# NOTE: this runs in a thread
|
|
912
903
|
|
|
913
904
|
thread = self.html._begin_download()
|
|
@@ -919,16 +910,12 @@ class ObjectManager(utilities.BaseManager):
|
|
|
919
910
|
if data and thread.isrunning():
|
|
920
911
|
if filetype.startswith("image"):
|
|
921
912
|
name = self.html.image_manager.allocate_image_name()
|
|
922
|
-
data, data_is_image = self.html.image_manager.check_images(data, name, url, filetype)
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
else:
|
|
926
|
-
self.html.post_to_queue(lambda node=node, data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image: self._finish_fetching_image_objects(node, data, name, url, filetype, data_is_image))
|
|
913
|
+
data, data_is_image = self.html.image_manager.check_images(data, name, url, filetype, thread.is_subthread)
|
|
914
|
+
self.html.post_to_queue(lambda node=node, data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
915
|
+
self._finish_fetching_image_objects(node, data, name, url, filetype, data_is_image), thread.is_subthread)
|
|
927
916
|
elif filetype == "text/html":
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
else:
|
|
931
|
-
self.html.post_to_queue(lambda node=node, data=data, url=url, filetype=filetype: self._finish_fetching_HTML_objects(node, data, url, filetype))
|
|
917
|
+
self.html.post_to_queue(lambda node=node, data=data, url=url, filetype=filetype:
|
|
918
|
+
self._finish_fetching_HTML_objects(node, data, url, filetype), thread.is_subthread)
|
|
932
919
|
|
|
933
920
|
except Exception as error:
|
|
934
921
|
self.html.post_message(f"ERROR: could not load object element with data {url}: {error}", True)
|
tkinterweb/htmlwidgets.py
CHANGED
|
@@ -1223,6 +1223,8 @@ class HtmlFrame(Frame):
|
|
|
1223
1223
|
url = url.replace("view-source:", "")
|
|
1224
1224
|
parsed = urlparse(url)
|
|
1225
1225
|
|
|
1226
|
+
thread = utilities.get_current_thread()
|
|
1227
|
+
|
|
1226
1228
|
location = parsed.netloc if parsed.netloc else parsed.path
|
|
1227
1229
|
self._html.post_message(f"Connecting to {location}", True)
|
|
1228
1230
|
if self._html.insecure_https: self._html.post_message("WARNING: Using insecure HTTPS session", True)
|
|
@@ -1230,7 +1232,7 @@ class HtmlFrame(Frame):
|
|
|
1230
1232
|
newurl, data, filetype, code = self._html.download_url(url, data, method, decode)
|
|
1231
1233
|
self._html.post_message(f"Successfully connected to {location}", True)
|
|
1232
1234
|
|
|
1233
|
-
if
|
|
1235
|
+
if thread.isrunning():
|
|
1234
1236
|
if view_source:
|
|
1235
1237
|
newurl = "view-source:"+newurl
|
|
1236
1238
|
if self._current_url != newurl:
|
|
@@ -1250,7 +1252,7 @@ class HtmlFrame(Frame):
|
|
|
1250
1252
|
elif "image" in filetype:
|
|
1251
1253
|
name = self._html.image_manager.allocate_image_name()
|
|
1252
1254
|
if name:
|
|
1253
|
-
data, data_is_image = self._html.image_manager.check_images(data, name, url, filetype)
|
|
1255
|
+
data, data_is_image = self._html.image_manager.check_images(data, name, url, filetype, thread.is_subthread)
|
|
1254
1256
|
self._html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image: self._finish_loading_image(data, name, url, filetype, data_is_image))
|
|
1255
1257
|
else:
|
|
1256
1258
|
self.load_html(self._get_about_page("about:image", name), newurl, _thread_safe=thread_safe)
|
tkinterweb/utilities.py
CHANGED
|
@@ -31,7 +31,7 @@ __title__ = "TkinterWeb"
|
|
|
31
31
|
__author__ = "Andrew Clarke"
|
|
32
32
|
__copyright__ = "(c) 2021-2025 Andrew Clarke"
|
|
33
33
|
__license__ = "MIT"
|
|
34
|
-
__version__ = "4.17.
|
|
34
|
+
__version__ = "4.17.3"
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
ROOT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "resources")
|
|
@@ -686,6 +686,8 @@ class StoppableThread(threading.Thread):
|
|
|
686
686
|
self.daemon = True
|
|
687
687
|
self.running = True
|
|
688
688
|
|
|
689
|
+
self.is_subthread = True
|
|
690
|
+
|
|
689
691
|
def stop(self):
|
|
690
692
|
self.running = False
|
|
691
693
|
|
|
@@ -697,6 +699,9 @@ class PlaceholderThread:
|
|
|
697
699
|
"""Fake StoppableThread. The only purpose of this is to provide fake methods that mirror the StoppableThread class.
|
|
698
700
|
This means that if a download is running in the MainThread, the stop flags can still be set without raising errors, though they won't do anything."""
|
|
699
701
|
|
|
702
|
+
def __init__(self, *args, **kwargs):
|
|
703
|
+
self.is_subthread = False
|
|
704
|
+
|
|
700
705
|
def stop(self):
|
|
701
706
|
return
|
|
702
707
|
|
|
@@ -855,14 +860,11 @@ def download(url, data=None, method="GET", decode=None, insecure=False, cafile=N
|
|
|
855
860
|
parsed = urlparse(url)
|
|
856
861
|
url = urlunparse(parsed._replace(query=""))
|
|
857
862
|
|
|
858
|
-
thread = get_current_thread()
|
|
859
863
|
url = url.replace(" ", "%20")
|
|
860
864
|
if data and (method == "POST"):
|
|
861
865
|
req = Request(url, data, headers=dict(headers))
|
|
862
866
|
else:
|
|
863
867
|
req = Request(url, headers=dict(headers))
|
|
864
|
-
if not thread.isrunning():
|
|
865
|
-
return None, url, "", ""
|
|
866
868
|
|
|
867
869
|
with urlopen(req, context=context, timeout=timeout) as res:
|
|
868
870
|
data = res.read()
|
|
@@ -893,10 +895,8 @@ def download(url, data=None, method="GET", decode=None, insecure=False, cafile=N
|
|
|
893
895
|
data = data.decode(decode, errors="ignore")
|
|
894
896
|
else:
|
|
895
897
|
data = data.decode(errors="ignore")
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
else:
|
|
899
|
-
return url, data, filetype, code
|
|
898
|
+
|
|
899
|
+
return url, data, filetype, code
|
|
900
900
|
|
|
901
901
|
|
|
902
902
|
@lru_cache()
|
|
@@ -915,6 +915,7 @@ def shorten(string):
|
|
|
915
915
|
def get_current_thread():
|
|
916
916
|
"Return the currently running thread"
|
|
917
917
|
thread = threading.current_thread()
|
|
918
|
+
# Py 3.4+: Use is threading.main_thread()
|
|
918
919
|
if thread.name == "MainThread":
|
|
919
920
|
thread = PlaceholderThread()
|
|
920
921
|
return thread
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
tkinterweb/__init__.py,sha256=mKnt2RjNd0zMntvkmT4dn5iyytsko7fJJb-rnx4H82E,4690
|
|
2
|
-
tkinterweb/bindings.py,sha256=
|
|
2
|
+
tkinterweb/bindings.py,sha256=XE0CPX28YtwBW9g9l0nsVVSHe3O3pX19w6POxorX8_k,73563
|
|
3
3
|
tkinterweb/dom.py,sha256=6zEZUGMSdWuwu1-MQOpt1XJN-w_Aku1HGY5P2iM2ksE,43546
|
|
4
4
|
tkinterweb/extensions.py,sha256=QfV13omkMoeXe17JPbeJjykwXtWTcZ24mKuB7NoBgVI,46555
|
|
5
|
-
tkinterweb/handlers.py,sha256=
|
|
6
|
-
tkinterweb/htmlwidgets.py,sha256=
|
|
5
|
+
tkinterweb/handlers.py,sha256=3ptECxVAiSarldfi4_C_mqd7A9xyTzpqvgwOKcBCX_I,42583
|
|
6
|
+
tkinterweb/htmlwidgets.py,sha256=OSgLFlT4TpMRWFAwLdGcnX9Mc8FBtx-yFCUlxdKBivs,104373
|
|
7
7
|
tkinterweb/imageutils.py,sha256=Du6vX00Isx7z1Q6sVV4po9ycYrP_iDG22ScG04U_huQ,5368
|
|
8
8
|
tkinterweb/js.py,sha256=Wlameh5KGK3GKzBCczaWYWT1L6-5uOWHt1HCZmzrjLk,3597
|
|
9
9
|
tkinterweb/subwidgets.py,sha256=wT4gtUnUE5j9UA8lrKCjLaysWqHav-_46NF97uMswDo,28200
|
|
10
|
-
tkinterweb/utilities.py,sha256=
|
|
10
|
+
tkinterweb/utilities.py,sha256=LFjs3MlfiIleVZMjFh5mTMk_6H3LXqxfXo_dQ02scTE,43431
|
|
11
11
|
tkinterweb/resources/combobox-2.3.tm,sha256=flofzRxHJMeEj0I--4iLT9SWIo9G1MSIwY0h940tG-U,65083
|
|
12
12
|
tkinterweb/resources/pkgIndex.tcl,sha256=Zp99aTL170d0TbVrWS-6uzaIaykUQbRO0krvmJhcduA,77
|
|
13
|
-
tkinterweb-4.17.
|
|
14
|
-
tkinterweb-4.17.
|
|
15
|
-
tkinterweb-4.17.
|
|
16
|
-
tkinterweb-4.17.
|
|
17
|
-
tkinterweb-4.17.
|
|
13
|
+
tkinterweb-4.17.3.dist-info/LICENSE.md,sha256=Jf8BR3uTR9RLMAA2osul_ZRkvoYRgmlqq1Pd-xt0uMY,1074
|
|
14
|
+
tkinterweb-4.17.3.dist-info/METADATA,sha256=KdU710Bje-ndhFi-Oq1vVdfRiz6cuqczy2ve8NJKVNg,3133
|
|
15
|
+
tkinterweb-4.17.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
16
|
+
tkinterweb-4.17.3.dist-info/top_level.txt,sha256=QVZQjAzSgzBGwOl41qcOyvkYAwy1FXLlnvwtYvE9Ur4,11
|
|
17
|
+
tkinterweb-4.17.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|