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

dynobo / normcap / 18970553291

31 Oct 2025 11:01AM UTC coverage: 79.741% (-1.8%) from 81.509%
18970553291

Pull #798

github

web-flow
Merge e8a2929bb into 50be529a6
Pull Request #798: Refactoring

844 of 1175 new or added lines in 51 files covered. (71.83%)

23 existing lines in 5 files now uncovered.

2960 of 3712 relevant lines covered (79.74%)

4.55 hits per line

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

69.23
/normcap/argparser.py
1
import argparse
6✔
2
import sys
6✔
3
from pathlib import Path
6✔
4
from typing import Any
6✔
5

6
from normcap import __version__
6✔
7
from normcap.clipboard import Handler as ClipboardHandler
6✔
8
from normcap.gui.settings import DEFAULT_SETTINGS
6✔
9
from normcap.notification import Handler as NotificationHandler
6✔
10
from normcap.screenshot import Handler as ScreenshotHandler
6✔
11

12

13
def _patch_print_help(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
6✔
14
    """Patch print_help to write directly to console handle on Windows.
15

16
    This is a workaround for the quirk of briefcase packaged GUI apps on Windows,
17
    where sys.stdout and sys.stderr are not available. Therefore, we use windll api
18
    to directly write the help text to the console.
19
    """
NEW
20
    if sys.platform != "win32":
×
NEW
21
        raise RuntimeError(
×
22
            f"Windows specific _patch_print_help() got called on {sys.platform} system!"
23
        )
24

NEW
25
    print_help = parser.print_help
×
26

NEW
27
    def patched_print_help(file: Any = None) -> None:  # noqa: ANN401
×
NEW
28
        try:
×
NEW
29
            with Path("CON").open("w", encoding="utf-8") as console:
×
NEW
30
                console.write("\r\033[K")
×
NEW
31
                print_help(file=console)
×
NEW
32
                console.write("\r\n\r\nPress Enter to continue ...")
×
NEW
33
                console.flush()
×
NEW
34
        except Exception:  # noqa:S110  # except with pass
×
35
            # Avoid crash/error.
NEW
36
            pass
×
37

NEW
38
    parser.print_help = patched_print_help  # type: ignore
×
NEW
39
    return parser
×
40

41

42
def _create_argparser() -> argparse.ArgumentParser:
6✔
43
    """Create and configure the argument parser.
44

45
    Returns:
46
        The configured argument parser.
47
    """
48
    parser = argparse.ArgumentParser(
6✔
49
        prog="normcap",
50
        description=(
51
            "OCR-powered screen-capture tool to capture information instead of images."
52
        ),
53
    )
54

55
    for setting in DEFAULT_SETTINGS:
6✔
56
        if not setting.cli_arg:
6✔
57
            continue
6✔
58
        flags = (
6✔
59
            [f"-{setting.flag}", f"--{setting.key}"]
60
            if setting.flag
61
            else [f"--{setting.key}"]
62
        )
63
        parser.add_argument(
6✔
64
            *flags,
65
            type=setting.type_,
66
            help=setting.help_ + f" (default: {setting.value})",
67
            choices=setting.choices,
68
            nargs=setting.nargs,
69
        )
70
    parser.add_argument(
6✔
71
        "--reset",
72
        action="store_true",
73
        help="Reset all settings to default values",
74
        default=False,
75
    )
76
    parser.add_argument(
6✔
77
        "-v",
78
        "--verbosity",
79
        default="warning",
80
        action="store",
81
        choices=["error", "warning", "info", "debug"],
82
        help="Set level of detail for console output (default: %(default)s)",
83
    )
84
    parser.add_argument(
6✔
85
        "--log-file",
86
        type=Path,
87
        action="store",
88
        help="Save console output to a file",
89
    )
90
    parser.add_argument(
6✔
91
        "--version",
92
        action="store_true",
93
        help="Print NormCap version and exit",
94
    )
95
    parser.add_argument(
6✔
96
        "--cli-mode",
97
        action="store_true",
98
        help="Print text after detection to stdout and exits immediately",
99
    )
100
    parser.add_argument(
6✔
101
        "--background-mode",
102
        action="store_true",
103
        help="Start minimized to tray, without capturing",
104
    )
105
    parser.add_argument(
6✔
106
        "--screenshot-handler",
107
        action="store",
108
        choices=[h.name.lower() for h in ScreenshotHandler],
109
        help=(
110
            "Only relevant on Linux! Force using specific screenshot handler instead "
111
            "of auto-selecting"
112
        ),
113
    )
114
    parser.add_argument(
6✔
115
        "--clipboard-handler",
116
        action="store",
117
        choices=[h.name.lower() for h in ClipboardHandler],
118
        help="Force using specific clipboard handler instead of auto-selecting",
119
    )
120
    parser.add_argument(
6✔
121
        "--notification-handler",
122
        action="store",
123
        choices=[h.name.lower() for h in NotificationHandler],
124
        help=(
125
            "Only relevant on Linux! Force using specific notification handler instead "
126
            "of auto-selecting"
127
        ),
128
    )
129
    parser.add_argument(
6✔
130
        "--dbus-activation",
131
        action="store_true",
132
        help=argparse.SUPPRESS,
133
    )
134

135
    if sys.platform == "win32" and sys.stdout is None:
6✔
136
        # ONHOLD: After briefcase update: Check if patch still necessary
NEW
137
        parser = _patch_print_help(parser)
×
138

139
    return parser
6✔
140

141

142
def get_args() -> argparse.Namespace:
6✔
143
    """Parse command line arguments.
144

145
    Exit if NormCap was started with --version flag.
146

147
    Auto-enable tray for "background mode", which starts NormCap in tray without
148
    immediately opening the select-region window.
149
    """
150
    args = _create_argparser().parse_args()
6✔
151

152
    if args.version:
6✔
153
        print(f"NormCap {__version__}")  # noqa: T201
6✔
154
        sys.exit(0)
6✔
155

156
    if args.background_mode:
6✔
157
        # Background mode requires tray icon
NEW
158
        args.tray = True
×
159

160
    return args
6✔
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

© 2026 Coveralls, Inc