-
Notifications
You must be signed in to change notification settings - Fork 0
Refresh PR #881 against upstream master #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
58d114d
443d438
2354994
df3c3fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,9 @@ | |
|
|
||
| @author: synkarius | ||
| ''' | ||
| import os, sys, time, pkg_resources | ||
| from pkg_resources import VersionConflict, DistributionNotFound | ||
| import os, sys, time | ||
| from importlib.metadata import version, PackageNotFoundError | ||
| from packaging.version import Version | ||
| from castervoice.lib import printer | ||
|
|
||
| DARWIN = sys.platform == "darwin" | ||
|
|
@@ -13,10 +14,8 @@ | |
| def install_type(): | ||
| # Checks if Caster install is Classic or PIP. | ||
| try: | ||
| pkg_resources.require("castervoice") | ||
| except VersionConflict: | ||
| pass | ||
| except DistributionNotFound: | ||
| version("castervoice") | ||
| except PackageNotFoundError: | ||
| return "classic" | ||
| return "pip" | ||
|
|
||
|
|
@@ -39,11 +38,9 @@ def dep_missing(): | |
| for dep in requirements: | ||
| dep = dep.split(">=", 1)[0] | ||
| try: | ||
| pkg_resources.require("{}".format(dep)) | ||
| except VersionConflict: | ||
| pass | ||
| except DistributionNotFound: | ||
| missing_list.append('{0}'.format(dep)) | ||
| version(dep) | ||
| except PackageNotFoundError: | ||
| missing_list.append(dep) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Version specifier not stripped from package name lookupHigh Severity The |
||
| if missing_list: | ||
| pippackages = (' '.join(map(str, missing_list))) | ||
| printer.out("\nCaster: dependencys are missing. Use 'python -m pip install {0}'".format(pippackages)) | ||
|
|
@@ -60,18 +57,20 @@ def dep_min_version(): | |
| for dep in listdependency: | ||
| package = dep[0] | ||
| operator = dep[1] | ||
| version = dep[2] | ||
| req_version = dep[2] | ||
| issue_url = dep[3] | ||
| try: | ||
| pkg_resources.require('{0} {1} {2}'.format(package, operator, version)) | ||
| except VersionConflict as e: | ||
| if operator == ">=": | ||
| installed = Version(version(package)) | ||
| required = Version(req_version) | ||
| if operator == ">=" and installed < required: | ||
| if issue_url is not None: | ||
| printer.out("\nCaster: Requires {0} v{1} or greater.\nIssue reference: {2}".format(package, version, issue_url)) | ||
| printer.out("\nCaster: Requires {0} v{1} or greater.\nIssue reference: {2}".format(package, req_version, issue_url)) | ||
| printer.out("Update with: 'python -m pip install {} --upgrade' \n".format(package)) | ||
| if operator == "==": | ||
| elif operator == "==" and installed != required: | ||
| printer.out("\nCaster: Requires an exact version of {0}.\nIssue reference: {1}".format(package, issue_url)) | ||
| print("Install with: 'python -m pip install {}' \n".format(e.req)) | ||
| printer.out("Install with: 'python -m pip install {0}=={1}' \n".format(package, req_version)) | ||
| except PackageNotFoundError: | ||
| pass | ||
|
|
||
|
|
||
| class DependencyMan: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,9 +28,12 @@ def __init__(self): | |
| def get_pronunciation(self): | ||
| return "formatting" | ||
|
|
||
| def run(self, event_content): | ||
| pronunciation = event_content["pronunciation"] | ||
| _apply_format(pronunciation) | ||
| def run(self, event): | ||
| if event.active: | ||
| _apply_format(event.rule_class_name) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Format hook uses class name instead of pronunciationHigh Severity
|
||
| else: | ||
| textformat.format.clear_text_format() | ||
| textformat.secondary_format.clear_text_format() | ||
|
|
||
|
|
||
| def get_hook(): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| # All credit goes to caspark | ||
| # This is adapted from caspark's grammar at https://gist.github.com/caspark/9c2c5e2853a14b6e28e9aa4f121164a6 | ||
|
|
||
| from __future__ import print_function | ||
|
|
||
| import re | ||
| import time | ||
|
|
||
| import six | ||
| from dragonfly import DictList, Window, get_current_engine, get_engine | ||
|
|
||
| from castervoice.lib.util import recognition_history | ||
|
|
||
| _history = recognition_history.get_and_register_history(1) | ||
|
|
||
| open_windows_dictlist = DictList("open_windows") | ||
|
|
||
| WORD_SPLITTER = re.compile('[^a-zA-Z0-9]+') | ||
|
|
||
|
|
||
| def get_caster_messaging_window(): | ||
| if get_current_engine().name == 'natlink': | ||
| from natlinkcore import natlinkstatus # pylint: disable=import-error | ||
| status = natlinkstatus.NatlinkStatus() | ||
| if status.NatlinkIsEnabled() == 1: | ||
| return "Messages from Natlink" | ||
| return "Caster: Status Window" | ||
|
|
||
|
|
||
| def lower_if_not_abbreviation(s): | ||
| if len(s) <= 4 and s.upper() == s: | ||
| return s | ||
| else: | ||
| return s.lower() | ||
|
|
||
|
|
||
| def find_window(window_matcher_func, timeout_ms=3000): | ||
| """ | ||
| Returns a Window matching the given matcher function, or raises an error otherwise | ||
| """ | ||
| steps = int(timeout_ms / 100) | ||
| for i in range(steps): | ||
| for win in Window.get_all_windows(): | ||
| if window_matcher_func(win): | ||
| return win | ||
| time.sleep(0.1) | ||
| raise ValueError( | ||
| "no matching window found within {} ms".format(timeout_ms)) | ||
|
|
||
|
|
||
| def refresh_open_windows_dictlist(): | ||
| """ | ||
| Refreshes `open_windows_dictlist` | ||
| """ | ||
| window_options = {} | ||
| for window in (x for x in Window.get_all_windows() if | ||
| x.is_valid and | ||
| x.is_enabled and | ||
| x.is_visible and | ||
| not x.executable.startswith("C:\\Windows") and | ||
| x.classname != "DgnResultsBoxWindow"): | ||
| for word in {lower_if_not_abbreviation(word) | ||
| for word | ||
| in WORD_SPLITTER.split(window.title) | ||
| if len(word)}: | ||
| if word in window_options: | ||
| window_options[word] += [window] | ||
| else: | ||
| window_options[word] = [window] | ||
|
|
||
| window_options = {k: v for k, | ||
| v in six.iteritems(window_options) if v is not None} | ||
| open_windows_dictlist.set(window_options) | ||
|
|
||
|
|
||
| def debug_window_switching(): | ||
| """ | ||
| Prints out contents of `open_windows_dictlist` | ||
| """ | ||
| options = open_windows_dictlist.copy() | ||
| print("*** Windows known:\n", | ||
| "\n".join(sorted({w.title for list_of_windows in six.itervalues(options) | ||
| for w in list_of_windows}))) | ||
|
|
||
| print("*** Single word switching options:\n", "\n".join( | ||
| "{}: '{}'".format( | ||
| k.ljust(20), "', '".join(window.title for window in options[k]) | ||
| ) for k in sorted(six.iterkeys(options)) if len(options[k]) == 1)) | ||
| print("*** Ambiguous switching options:\n", "\n".join( | ||
| "{}: '{}'".format( | ||
| k.ljust(20), "', '".join(window.title for window in options[k]) | ||
| ) for k in sorted(six.iterkeys(options)) if len(options[k]) > 1)) | ||
|
|
||
|
|
||
| def switch_window(windows): | ||
| """ | ||
| Matches keywords to window titles stored in `open_windows_dictlist` | ||
| """ | ||
| matched_window_handles = {w.handle: w for w in windows[0]} | ||
| for window_options in windows[1:]: | ||
| matched_window_handles = { | ||
| w.handle: w for w in window_options if w.handle in matched_window_handles} | ||
| if six.PY2: | ||
| matched_windows = matched_window_handles.values() | ||
| else: | ||
| matched_windows = list(matched_window_handles.values()) | ||
| if len(matched_windows) == 1: | ||
| window = matched_windows[0] | ||
| print("Window Management: Switching to", window.title) | ||
| window.set_foreground() | ||
| else: | ||
| try: | ||
| messaging_title = get_caster_messaging_window() | ||
| messaging_window = find_window( | ||
| lambda w: messaging_title in w.title, timeout_ms=100) | ||
| if messaging_window.is_minimized: | ||
| messaging_window.restore() | ||
| else: | ||
| messaging_window.set_foreground() | ||
| except ValueError: | ||
| pass | ||
| if len(matched_windows) >= 2: | ||
| print("Ambiguous window switch command:\n", "\n".join( | ||
| "'{}' from {} (handle: {})".format(w.title, w.executable, w.handle) | ||
| for w in matched_windows)) | ||
| else: | ||
| spec_n_word = 2 | ||
| words = list(map(str, _history[0])) | ||
| del words[:spec_n_word] | ||
| print("Window Management: No matching window title containing keywords: `{}`". | ||
| format(' '.join(map(str, words)))) | ||
|
|
||
|
|
||
| class Timer: | ||
| """ | ||
| Dragonfly timer runs every 2 seconds updating open_windows_dictlist | ||
| """ | ||
| timer = None | ||
|
|
||
| def __init__(self): | ||
| pass | ||
|
|
||
| def set(self): | ||
| if self.timer is None: | ||
| self.timer = get_engine().create_timer(refresh_open_windows_dictlist, 2) | ||
| self.timer.start() | ||
|
|
||
|
|
||
| timerinstance = Timer() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| from dragonfly import get_engine | ||
|
|
||
| get_engine("text") |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dep_missing()now passes raw requirement strings toimportlib.metadata.version(), but only strips">="first. Entries likepillow==9.5.0inrequirements.txtanddragonfly2[kaldi]inrequirements-mac-linux.txtare not valid distribution names forversion(), so they are always treated as missing even when installed. In classic installs this causes persistent false missing-dependency warnings (and the 10-second sleep) on every startup.Useful? React with 👍 / 👎.