• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dynobo / normcap / 5660667262

pending completion
5660667262

Pull #489

github

web-flow
Merge 1fcbc48df into 2bf49ed75
Pull Request #489: Feature/improve coverage

59 of 80 new or added lines in 7 files covered. (73.75%)

40 existing lines in 2 files now uncovered.

2151 of 2390 relevant lines covered (90.0%)

2.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.61
/normcap/gui/notification.py
1
import logging
3✔
2
import os
3✔
3
import shutil
3✔
4
import subprocess
3✔
5
import sys
3✔
6
import textwrap
3✔
7

8
from PySide6 import QtCore, QtGui, QtWidgets
3✔
9

10
from normcap.gui import system_info
3✔
11
from normcap.gui.models import Capture, CaptureMode
3✔
12

13
logger = logging.getLogger(__name__)
3✔
14

15

16
class Communicate(QtCore.QObject):
3✔
17
    """Notifier's communication bus."""
3✔
18

19
    send_notification = QtCore.Signal(Capture)
3✔
20
    on_notification_sent = QtCore.Signal()
3✔
21

22

23
class Notifier(QtCore.QObject):
3✔
24
    """Send notifications."""
3✔
25

26
    def __init__(self, parent: QtCore.QObject) -> None:
3✔
27
        super().__init__(parent=parent)
3✔
28
        self.com = Communicate(parent=self)
3✔
29
        self.com.send_notification.connect(self._send_notification)
3✔
30

31
    @staticmethod
3✔
32
    def _compose_notification(capture: Capture) -> tuple[str, str]:
3✔
33
        """Extract message text out of captures object and include icon."""
34
        # Compose message text
35
        if not capture.ocr_text or len(capture.ocr_text.strip()) < 1:
3✔
36
            title = "Nothing captured!"
3✔
37
            text = "Please try again."
3✔
38
            return title, text
3✔
39

40
        text = capture.ocr_text.strip().replace(os.linesep, " ")
3✔
41
        text = textwrap.shorten(text, width=45)
3✔
42

43
        # Compose message title
44
        if capture.ocr_applied_magic == "ParagraphMagic":
3✔
45
            count = capture.ocr_text.count(os.linesep * 2) + 1
3✔
46
            title = f"{count} paragraph"
3✔
47
        elif capture.ocr_applied_magic == "EmailMagic":
3✔
48
            count = capture.ocr_text.count("@")
3✔
49
            title = f"{count} email"
3✔
50
        elif capture.ocr_applied_magic == "SingleLineMagic":
3✔
51
            count = capture.ocr_text.count(" ") + 1
3✔
52
            title = f"{count} word"
3✔
53
        elif capture.ocr_applied_magic == "MultiLineMagic":
3✔
54
            count = capture.ocr_text.count(os.linesep) + 1
3✔
55
            title = f"{count} line"
3✔
56
        elif capture.ocr_applied_magic == "UrlMagic":
3✔
57
            count = capture.ocr_text.count(os.linesep) + 1
3✔
58
            title = f"{count} URL"
3✔
59
        elif capture.mode == CaptureMode.RAW:
3✔
60
            count = len(capture.ocr_text)
3✔
61
            # Count linesep only as single char:
62
            count -= (len(os.linesep) - 1) * capture.ocr_text.count(os.linesep)
3✔
63
            title = f"{count} char"
3✔
64
        else:
65
            count = 0
3✔
66
            title = ""
3✔
67

68
        title += f"{'s' if count > 1 else ''} captured"
3✔
69

70
        return title, text
3✔
71

72
    @QtCore.Slot(Capture)
3✔
73
    def _send_notification(self, capture: Capture) -> None:
3✔
74
        """Show tray icon then send notification."""
75
        title, message = self._compose_notification(capture)
3✔
76
        if sys.platform == "linux" and shutil.which("notify-send"):
3✔
77
            self._send_via_libnotify(title, message)
3✔
78
        else:
79
            self._send_via_qt_tray(title, message)
3✔
80
        self.com.on_notification_sent.emit()
3✔
81

82
    def _send_via_libnotify(self, title: str, message: str) -> None:
3✔
83
        """Send via notify-send.
84

85
        Seems to work more reliable on Linux + Gnome, but requires libnotify.
86
        Running in detached mode to avoid freezing KDE bar in some distributions.
87
        """
88
        logger.debug("Send notification via notify-send")
3✔
89
        icon_path = system_info.get_resources_path() / "icons" / "notification.png"
3✔
90

91
        # Escape chars interpreted by notify-send
92
        message = message.replace("\\", "\\\\")
3✔
93
        message = message.replace("-", "\\-")
3✔
94

95
        cmds = [
3✔
96
            "notify-send",
97
            f"--icon={icon_path.resolve()}",
98
            "--app-name=NormCap",
99
            f"{title}",
100
            f"{message}",
101
        ]
102

103
        # Left detached on purpose!
104
        subprocess.Popen(cmds, start_new_session=True)  # noqa: S603
3✔
105

106
    def _send_via_qt_tray(self, title: str, message: str) -> None:
3✔
107
        """Send via QSystemTrayIcon.
108

109
        Used for:
110
            - Windows
111
            - macOS
112
            - Linux (Fallback in case no notify-send)
113
        """
114
        logger.debug("Send notification via QT")
3✔
115

116
        # Need to load icon from path, as icon from resources.py won't show up:
117
        parent = self.parent()
3✔
118

119
        if not isinstance(parent, QtWidgets.QSystemTrayIcon):
3✔
UNCOV
120
            raise TypeError("Parent is expected to be of type QSystemTrayIcon.")
×
121

122
        parent.show()
3✔
123
        parent.showMessage(title, message, QtGui.QIcon(":notification"))
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2024 Coveralls, Inc