def test_str_and_repr(): """ `__str__` and `__repr__` should give formatted strings that represent nested components nicely. """ @component class Child: a: int b: str c: List[float] @component class Parent: b: str = "bar" child: Child = Child() p = Parent() configure(p, {"a": 10, "b": "foo", "c": [1.5, -1.2]}, name="parent") assert (unstyle(repr(p)) == """Parent(b="foo", child=Child(a=10, b="foo", c=[1.5, -1.2]))""") assert (unstyle(str(p)) == """Parent( b="foo", child=Child( a=10, b="foo", c=[1.5, -1.2] ) )""")
def parse_doc(ctx, command, stack) -> CommandInfo: name = " ".join(stack) formatter = ctx.make_formatter() command.format_usage(ctx, formatter) usage = click.unstyle(formatter.getvalue()) usage = re.split(r"usage\s*:", usage, maxsplit=2, flags=re.IGNORECASE)[1].strip() short = click.unstyle(command.get_short_help_str(80)) is_group = isinstance(command, click.MultiCommand) info = CommandInfo(name=name, usage=usage, short=short, is_group=is_group) formatter = ctx.make_formatter() command.format_help_text(ctx, formatter) help = click.unstyle(formatter.getvalue()) parts = re.split(r"examples:", help, flags=re.IGNORECASE) info.description = dedent(parts[0]) if len(parts) > 1: assert len(parts) == 2 info.examples = dedent(parts[1]) for param in command.get_params(ctx): ret = param.get_help_record(ctx) if ret: info.options.append( Option(click.unstyle(ret[0]), click.unstyle(ret[1]))) return info
def test_colors(): headers = ["alpha", "beta", click.style("gamma", bg="green")] rows = [ ["delta", "omega", "psi"], ["echo", click.style("charlie", fg="red"), "bingo"], [click.style("nebukadnezar", bold=True), "otto", "kilo"], ] align = ["r", "c", "l"] s = format_table(headers, rows, align, width=None) print() print(s) assert (unstyle(s) == """ alpha beta gamma ------------ ------- ----- delta omega psi echo charlie bingo nebukadnezar otto kilo """[1:-1]) align = ["r+", "c", "l"] s = format_table(headers, rows, align, width=100) print() print(s) assert (unstyle(s) == """ alpha beta gamma -------------------------------------------------------------------------------------- ------- ----- delta omega psi echo charlie bingo nebukadnezar otto kilo """[1:-1])
def format_table( headers: Tuple[str, ...], rows: List[Tuple[str, ...]], align: Tuple[str, ...], width: Optional[int] = None, ) -> str: assert len(headers) == len(align), "Number of aligns must match columns" if width is None and any("+" in a for a in align): width, _ = shutil.get_terminal_size((80, 40)) col_widths = [len(click.unstyle(h)) for h in headers] for row in rows: for idx, col in enumerate(row): col_widths[idx] = max(col_widths[idx], len(click.unstyle(col))) output = "" output += _format_row(headers, col_widths, align, max_width=width) + "\n" output += (_format_row( tuple(["" for _ in col_widths]), col_widths, align, max_width=width, padstr="-", ) + "\n") for row in rows: output += _format_row(row, col_widths, align, max_width=width) + "\n" return output[:-1]
def shorten(string: str, length: int) -> str: ANSIRE = "\x1b\\[(?:K|.*?m)" if length <= 4: raise ValueError("Shortening to <= 4 does not make sense") if length >= len(click.unstyle(string)): return string m = re.match("^(" + ANSIRE + ").*(" + ANSIRE + "$)", string) if m is None: # Not a single style, unstyle all start = "" end = "" else: start = m.group(1) end = m.group(2) string = click.unstyle(string) leftover = length - 3 left_length = max(1, math.floor(leftover / 2)) left = string[:left_length] right = string[-(length - left_length - 3) :] return f"{start}{left}...{right}{end}"
def test_repr(hyper): output = """Hyper( bar=0.5, barx2=1.0, baz=string, foo=[1, 2, 3] )""" assert click.unstyle(str(hyper)) == output assert click.unstyle(repr(hyper)) == output
def test_create_new_app(self): print '* Generating application' application = TemporaryApplication() print '* Testing build/run' result = application.execute('run manage.py help --quiet') self.assertTrue('for help on a specific subcommand' in result, result) print '* Testing migration flow' result = application.execute('run manage.py migrate --quiet') self.assertTrue('Applying auth.0001_initial' in result, result) result = application.execute('run manage.py migrate --quiet') self.assertTrue('No migrations to apply' in result, result) print '* Testing model generation' application.execute('generate model foo --not-interactive') try: result = application.execute('test --ds=tests.settings') except Exception as e: e = click.unstyle(str(e)) self.assertTrue('no such table: %s_%s' % ('dummy', 'foo') in e, e) print '* Testing new migration flow' application.execute('run manage.py makemigrations --quiet') application.execute('test --ds=tests.settings') result = application.execute('run manage.py migrate --quiet') self.assertTrue('Applying dummy.0001_initial' in result, result) result = application.execute('run manage.py migrate --quiet') self.assertFalse('Applying dummy.0001_initial' in result, result) print '* Testing command generation' application.execute('generate command foobar') result = application.execute('run manage.py help --quiet') self.assertTrue('foobar' in result, result) result = application.execute('run manage.py foobar --quiet') self.assertTrue('foobar called' in result, result) result = click.unstyle(application.execute('info')) self.assertTrue('Django == 1.10' in result, result) print '* Testing server' server = application.execute('serve 9123', async=True) time.sleep(2) response = requests.get('http://localhost:9123') content = response.content self.assertTrue('It worked' in content, content) server.terminate()
def test_display_section_name(capsys, title, separator, printed, expected): # When section name is displayed default.display_section_name(title, separator=separator) out = capsys.readouterr().out.strip() terminal_width = default.get_terminal_width() # It should fit into the terminal width assert len(click.unstyle(out)) == terminal_width # And the section name should be bold assert strip_style_win32(click.style(click.unstyle(out), bold=True)) == out assert expected in out
def test_str_and_repr(): """`__str__` and `__repr__` should give formatted strings that represent nested components nicely.""" @component class Child1: a: int = Field() @component class Child2: a: int = Field() b: str = Field() c: List[float] = Field() d: int = Field(allow_missing=True) child_1: Child1 = ComponentField() @component class Parent: b: str = Field("bar") child_1: Child1 = ComponentField(Child1) child_2: Child2 = ComponentField(Child2) p = Parent() configure( p, {"child_1.a": 5, "child_2.a": 10, "b": "foo", "child_2.c": [1.5, -1.2]}, name="parent", ) assert ( click.unstyle(repr(p)) == """Parent(b="foo", child_1=Child1(a=5), child_2=Child2(a=10, b=<inherited value>, c=[1.5, -1.2], d=<missing>, child_1=<inherited component instance>))""" ) assert ( click.unstyle(str(p)) == """Parent( b="foo", child_1=Child1( a=5 ), child_2=Child2( a=10, b=<inherited value>, c=[1.5, -1.2], d=<missing>, child_1=<inherited component instance> ) )""" )
def report(self) -> None: # progress wasn't disabled, so we need to cleanup a bit. clear_line_width = len(click.unstyle(self._progress_msg)) if self._crawler.terminated: # we adding additional 10 spaces to clear ^C we got on the # terminal if ^C pressed. clear_line_width += 10 if not self._opts['no_progress']: click.echo(BEFORE_BAR, nl=False) click.echo(' ' * clear_line_width, nl=False) click.echo(BEFORE_BAR, nl=False) info = self.info() # type: str stat = self._get_progress() # type: str split_line_len = max(len(click.unstyle(info)), len(click.unstyle(stat))) if self._crawler.terminated: term_msg = "Results can be inconsistent, as execution was terminated." pref_len = (split_line_len - len(term_msg)) // 2 click.echo((" " * split_line_len)) click.echo((" "*pref_len) + term_msg) click.echo((" "*pref_len) + ("^" * len(term_msg))) click.echo("=" * split_line_len) click.echo(info, color=self.is_colored()) click.echo("=" * split_line_len) click.echo(stat, color=self.is_colored()) click.echo(("-"*split_line_len) + "\033[?25h") # show some url report(s) show = list(self._opts.get('show', [])) # type: Sequence[str] if 'none' in show: return if 'all' in show: show = ['ok', 'failed', 'ignored'] for report in show: OUTPUT_REPORT = self._generate(report) if len(OUTPUT_REPORT): click.echo(OUTPUT_REPORT, color=self.is_colored())
def after_method(self, bench, method): click.echo('\r', nl=False) # Clear the line results = bench.results[method] mean = results.total / bench.times ref = self.ref(bench, method) duration = self.duration(total=results.total, mean=mean, ref=ref) if results.has_success and results.has_errors: status = ' '.join((yellow(WARNING), duration)) elif results.has_success: status = ' '.join((green(OK), duration)) else: status = ' '.join((red(KO), duration)) width, _ = click.get_terminal_size() size = width - len(click.unstyle(status)) label = bench.label_for(method) click.echo('{label:.<{size}} {status}'.format(label=cyan(label), size=size, status=status)) if self.debug and results.error: exc = results.error click.echo(yellow('Error: {0}'.format(type(exc)))) click.echo('\t{0}'.format(exc.message if hasattr(exc, 'message') else exc))
def parse_tweets(raw_tweets, source, now=None): """ Parses a list of raw tweet lines from a twtxt file and returns a list of :class:`Tweet` objects. :param list raw_tweets: list of raw tweet lines :param Source source: the source of the given tweets :param Datetime now: the current datetime :returns: a list of parsed tweets :class:`Tweet` objects :rtype: list """ if now is None: now = datetime.now(timezone.utc) dom = parse_feed('\n'.join(raw_tweets)) if dom.bozo: tweets = [] for line in raw_tweets: try: tweet = parse_tweet(line, source, now) except (ValueError, OverflowError) as e: logger.debug("{0} - {1}".format(source.url, e)) else: tweets.append(tweet) else: tweets = [ Tweet( click.unstyle(m.title.strip()) + ' ' + m.links[0].href, parse_iso8601(m.updated), source ) for m in dom.entries ] return tweets
def __call__(self, files: Sequence[FileStatus]) -> Iterator[str]: if not files: return items = [self.painter.paint(file.name, file.type) for file in files] widths = [len(unstyle(item)) for item in items] # let`s check how many columns we can use test_count = 1 while True: test_columns = chunks(widths, ceil(len(items) / test_count)) test_columns_widths = [max(column) for column in test_columns] test_total_width = sum( test_columns_widths) + 2 * (len(test_columns) - 1) if test_count == 1 or test_total_width <= self.width: count = test_count columns_widths = test_columns_widths if test_total_width == self.width: break if test_total_width >= self.width or len(test_columns) == len( items): break test_count = test_count + 1 rows = transpose(chunks(items, ceil(len(items) / count))) for row in rows: formatted_row = [] for i in range(len(row)): formatted = row[i] if i < len(row) - 1: formatted = formatted.ljust(columns_widths[i]) formatted_row.append(formatted) yield " ".join(formatted_row)
def _format_row( cols: Tuple[str, ...], widths: List[int], aligns: Tuple[str, ...], max_width: Optional[int] = None, padstr: str = " ", ) -> str: assert len(cols) == len(aligns), "Number of aligns must match columns" colstrs = ["" for _ in cols] stretch_col = None for idx, (col, width, align) in enumerate(zip(cols, widths, aligns)): if align.endswith("+"): stretch_col = idx colstr = _do_align(col, align[:-1], width, padstr) else: colstr = _do_align(col, align, width, padstr) colstrs[idx] = colstr if stretch_col is not None and max_width is not None: total_len = sum( len(click.unstyle(c)) for i, c in enumerate(colstrs) if i != stretch_col) + (len(cols) - 1) * len(padstr) align = aligns[stretch_col][:-1] width = max_width - total_len col = cols[stretch_col] colstr = _do_align(col, align, width, padstr) colstrs[stretch_col] = colstr return " ".join(colstrs)
def test_styling(): examples = [ ('x', dict(fg='black'), '\x1b[30mx\x1b[0m'), ('x', dict(fg='red'), '\x1b[31mx\x1b[0m'), ('x', dict(fg='green'), '\x1b[32mx\x1b[0m'), ('x', dict(fg='yellow'), '\x1b[33mx\x1b[0m'), ('x', dict(fg='blue'), '\x1b[34mx\x1b[0m'), ('x', dict(fg='magenta'), '\x1b[35mx\x1b[0m'), ('x', dict(fg='cyan'), '\x1b[36mx\x1b[0m'), ('x', dict(fg='white'), '\x1b[37mx\x1b[0m'), ('x', dict(bg='black'), '\x1b[40mx\x1b[0m'), ('x', dict(bg='red'), '\x1b[41mx\x1b[0m'), ('x', dict(bg='green'), '\x1b[42mx\x1b[0m'), ('x', dict(bg='yellow'), '\x1b[43mx\x1b[0m'), ('x', dict(bg='blue'), '\x1b[44mx\x1b[0m'), ('x', dict(bg='magenta'), '\x1b[45mx\x1b[0m'), ('x', dict(bg='cyan'), '\x1b[46mx\x1b[0m'), ('x', dict(bg='white'), '\x1b[47mx\x1b[0m'), ('foo bar', dict(blink=True), '\x1b[5mfoo bar\x1b[0m'), ('foo bar', dict(underline=True), '\x1b[4mfoo bar\x1b[0m'), ('foo bar', dict(bold=True), '\x1b[1mfoo bar\x1b[0m'), ('foo bar', dict(dim=True), '\x1b[2mfoo bar\x1b[0m'), ] for text, styles, ref in examples: assert click.style(text, **styles) == ref assert click.unstyle(ref) == text
def test_description(): v = Vulnerability.parse(load('CVE-2010-0748')) assert unstyle(fmt_vuln(v, show_description=True)) == ( 'https://nvd.nist.gov/vuln/detail/CVE-2010-0748 ' 'Transmission before 1.92 allows an attacker to cause a denial of ' 'service (crash) or possibly have other unspecified impact via a ' 'large number of tr arguments in a magnet link.')
def test_get_tkn_bad(capsys): with pytest.raises(SystemExit): secret = web_support.get_secret(invoker.configs() + invoker.bad_config()) out, err = capsys.readouterr() assert click.unstyle( err.strip()) == 'No webhook secret has been provided'
def format_license(license, only_text=False, columns=get_terminal_size().columns): to_print = [ { 'words': [{ 'style': { 'bold': True }, 'value': license['package'] }, { 'value': ' version {0} found using license '.format(license['version']) }, { 'style': { 'bold': True }, 'value': license['license'] }] }, ] content = style_lines(to_print, columns, '-> ', start_line='', end_line='') return click.unstyle(content) if only_text else content
def step(self, job: JobDescription) -> None: new_time = self.time_factory() dt = new_time - self._time msg = "Status: " + format_job_status(job.status) reason = self._get_status_reason_message(job) if reason: msg += " " + style(reason, bold=True) description = self._get_status_description_message(job) if description: msg += " " + description if job.status == JobStatus.PENDING: msg = style("- ", fg="yellow") + msg elif job.status == JobStatus.FAILED: msg = style("× ", fg="red") + msg else: # RUNNING or SUCCEDED msg = style("√ ", fg="green") + msg if not self._color: msg = unstyle(msg) if msg != self._prev: if self._prev: self._printer.print(self._prev, lineno=self._lineno) self._prev = msg self._lineno = self._printer.total_lines self._printer.print(msg) else: self._printer.print(f"{msg} {next(self._spinner)} [{dt:.1f} sec]", lineno=self._lineno)
def test_validate_with_basic_policy_file(self): dirname = os.path.dirname(__file__) path = os.path.join(dirname, "test_policy_file", "default_policy_file.yml") result = self.runner.invoke( cli.cli, ['validate', 'policy_file', '--path', path]) cleaned_stdout = click.unstyle(result.stdout) msg = 'The Safety policy file was successfully parsed with the following values:\n' parsed = json.dumps( { "security": { "ignore-cvss-severity-below": 0, "ignore-cvss-unknown-severity": False, "ignore-vulnerabilities": { "25853": { "reason": "we don't use the vulnerable function", "expires": "2022-10-21 00:00:00" } }, "continue-on-vulnerability-error": False }, "filename": path }, indent=4) + '\n' self.assertEqual(msg + parsed, cleaned_stdout) self.assertEqual(result.exit_code, 0)
def test_styling(): examples = [ ("x", dict(fg="black"), "\x1b[30mx\x1b[0m"), ("x", dict(fg="red"), "\x1b[31mx\x1b[0m"), ("x", dict(fg="green"), "\x1b[32mx\x1b[0m"), ("x", dict(fg="yellow"), "\x1b[33mx\x1b[0m"), ("x", dict(fg="blue"), "\x1b[34mx\x1b[0m"), ("x", dict(fg="magenta"), "\x1b[35mx\x1b[0m"), ("x", dict(fg="cyan"), "\x1b[36mx\x1b[0m"), ("x", dict(fg="white"), "\x1b[37mx\x1b[0m"), ("x", dict(bg="black"), "\x1b[40mx\x1b[0m"), ("x", dict(bg="red"), "\x1b[41mx\x1b[0m"), ("x", dict(bg="green"), "\x1b[42mx\x1b[0m"), ("x", dict(bg="yellow"), "\x1b[43mx\x1b[0m"), ("x", dict(bg="blue"), "\x1b[44mx\x1b[0m"), ("x", dict(bg="magenta"), "\x1b[45mx\x1b[0m"), ("x", dict(bg="cyan"), "\x1b[46mx\x1b[0m"), ("x", dict(bg="white"), "\x1b[47mx\x1b[0m"), ("foo bar", dict(blink=True), "\x1b[5mfoo bar\x1b[0m"), ("foo bar", dict(underline=True), "\x1b[4mfoo bar\x1b[0m"), ("foo bar", dict(bold=True), "\x1b[1mfoo bar\x1b[0m"), ("foo bar", dict(dim=True), "\x1b[2mfoo bar\x1b[0m"), ] for text, styles, ref in examples: assert click.style(text, **styles) == ref assert click.unstyle(ref) == text
def test_tty_fmt_storage_url_over_full(make_root: _MakeRoot) -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("storage://andrew/" + "/".join("folder" + str(i) for i in range(5)) + "/file.txt") assert (click.unstyle(report.fmt_url(url, FileStatusType.FILE, half=False)) == "'storage://andrew/.../folder2/folder3/folder4/file.txt'")
def test_tty_fmt_url_relative_over(make_root: _MakeRoot) -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("storage:folder1/folder2/folder3/folder4/folder5") assert (click.unstyle( report.fmt_url(url, FileStatusType.FILE, half=True)) == "'storage:.../folder3/folder4/folder5'")
def intro(): intro = [ click.style(".", dim=True), "Hi, I'm {}.".format(click.style("AJ", fg="red")), "I'm a {} with a strong interest in ".format( click.style("Python developer", fg="yellow") ), "APIs, CLIs and subverting the dominant paradigm.", "This is my resume.", "", "Note: this is primarily intended for command-line addicts.", "A more conventional version can be found on LinkedIn.", ] intro = [click.unstyle(item).center(80) for item in intro] intro = "\n".join(intro) intro = intro.replace("APIs", click.style("APIs", fg="green")) intro = intro.replace("CLIs", click.style("CLIs", fg="blue")) intro = intro.replace( "subverting the dominant paradigm", click.style("subverting the dominant paradigm", fg="magenta"), ) colSpan = 5 rowSpan = 3.5 ret = Markdown(data=intro, colSpan=colSpan, rowSpan=rowSpan, label="") return ret
def test_tty_fmt_url_over_half_long_segment(make_root: _MakeRoot) -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("file:///andrew/" + "a" * 30) assert (click.unstyle(report.fmt_url( url, FileStatusType.FILE, half=True)) == "'file:///.../aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'")
def test_tty_fmt_file_url_over_half(make_root: _MakeRoot) -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("file:///andrew/folder0/folder1/file.txt") assert (click.unstyle( report.fmt_url(url, FileStatusType.FILE, half=True)) == "'file:///.../folder1/file.txt'")
def test_tty_fmt_url_relative_over_single_segment() -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("storage:" + "a" * 35) assert (click.unstyle(report.fmt_url( url, FileStatusType.FILE, half=True)) == "'storage:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'")
def test_leak_message(result_input, snapshot, show_secrets, verbose): # The text output includes the version of the secrets engine, but this version is # None until we make an API call. Since this test does not make any API call, set # the version to a fake value. with mock.patch("ggshield.output.text.message.VERSIONS") as VERSIONS: VERSIONS.secrets_engine_version = "3.14.159" output_handler = TextOutputHandler(show_secrets=show_secrets, verbose=verbose) # _process_scan_impl() modifies its ScanCollection arg(!), so make a copy of it new_result = deepcopy(result_input) output = output_handler._process_scan_impl( ScanCollection( id="scan", type="test", results=[new_result], optional_header="> This is an example header", )) # Make output OS-independent, so that it can be safely compared to snapshots # regardless of the current OS: # - Remove colors because color codes are not the same on all OSes # - Replace any custom decoration with the default one output = click.unstyle(output).replace(_file_info_decoration(), _file_info_default_decoration()) snapshot.assert_match(output)
def test_display_single_error(capsys, swagger_20, endpoint, execution_context, show_errors_tracebacks): # Given exception is multiline exception = None try: exec("some invalid code") except SyntaxError as exc: exception = exc result = models.TestResult(endpoint) result.add_error(exception) # When the related test result is displayed execution_context.show_errors_tracebacks = show_errors_tracebacks default.display_single_error(execution_context, SerializedTestResult.from_test_result(result)) lines = capsys.readouterr().out.strip().split("\n") # Then it should be correctly formatted and displayed in red color if sys.version_info <= (3, 8): expected = ' File "<string>", line 1\n some invalid code\n ^\nSyntaxError: invalid syntax\n' else: expected = ' File "<string>", line 1\n some invalid code\n ^\nSyntaxError: invalid syntax\n' if show_errors_tracebacks: lines = click.unstyle("\n".join(lines)).split("\n") assert lines[1] == "Traceback (most recent call last):" # There is a path on the next line, it is simpler to not check it since it doesn't give much value # But presence of traceback itself is checked expected = f' exec("some invalid code")\n{expected}' assert "\n".join(lines[3:8]) == expected.strip("\n") else: assert "\n".join(lines[1:6]) == strip_style_win32( click.style(expected, fg="red")).rstrip("\n")
def test_tty_fmt_url() -> None: report = create_storage_progress(make_root(False, True, False), True) assert isinstance(report, TTYProgress) url = URL("storage://andrew/folder/file.txt") assert (click.unstyle( report.fmt_url(url, FileStatusType.FILE, half=True)) == "'storage://andrew/folder/file.txt'")
def print_labeled_bar(label, is_error=False, fg=None): terminal_width, _ = click.get_terminal_size() width = len(click.unstyle(label)) half_line = "=" * int((terminal_width - width - 2) / 2) click.secho("%s %s %s" % (half_line, label, half_line), fg=fg, err=is_error)
def write(self, results, unsafe_requirements, markers, hashes): for line in self._iter_lines(results, unsafe_requirements, markers, hashes): log.info(line) if not self.dry_run: self.dst_file.write(unstyle(line).encode()) self.dst_file.write(os.linesep.encode())
def __call__(self, context: CallbackContext) -> None: orig_context: CallbackContext = context.job.context user_data = get_user_data(orig_context) logger.info("Begin download of: %s for user %d", self.url, user_data.chat_id) context.bot.send_message(chat_id=user_data.chat_id, text=f"Download of '{self.url}' STARTED", **message_args) cwd = os.getcwd() try: os.chdir(config.DOWNLOAD_FOLDER) ydl = youtube_dl.YoutubeDL({"format": "bestvideo+bestaudio"}) with ydl: result = ydl.extract_info(self.url) context.bot.send_message( chat_id=user_data.chat_id, text=f"Download of '{self.url}' COMPLETED!", **message_args) except Exception as e: msg = """ Download of '{url}' FAILED! <pre>{exc}</pre> """.format(url=self.url, exc=click.unstyle(str(e))) logger.debug(msg) context.bot.send_message(chat_id=user_data.chat_id, parse_mode="HTML", text=msg, **message_args) finally: os.chdir(cwd)
def write(self, results, reverse_dependencies, primary_packages): with ExitStack() as stack: f = None if not self.dry_run: f = stack.enter_context(AtomicSaver(self.dst_file)) for line in self._iter_lines(results, reverse_dependencies, primary_packages): log.info(line) if f: f.write(unstyle(line).encode('utf-8')) f.write(os.linesep.encode('utf-8'))
def style_tweet(tweet, porcelain=False): if porcelain: return "{nick}\t{url}\t{tweet}".format( nick=tweet.source.nick, url=tweet.source.url, tweet=str(tweet)) else: styled_text = format_mentions(tweet.text) len_styling = len(styled_text) - len(click.unstyle(styled_text)) return "➤ {nick} ({time}):\n{tweet}".format( nick=click.style(tweet.source.nick, bold=True), tweet=textwrap.shorten(styled_text, 140 + len_styling), time=click.style(tweet.relative_datetime, dim=True))
def style_tweet(tweet, porcelain=False): conf = click.get_current_context().obj["conf"] limit = conf.character_limit if porcelain: return "{nick}\t{url}\t{tweet}".format(nick=tweet.source.nick, url=tweet.source.url, tweet=str(tweet)) else: if sys.stdout.isatty() and not tweet.text.isprintable(): return None styled_text = format_mentions(tweet.text) len_styling = len(styled_text) - len(click.unstyle(styled_text)) final_text = textwrap.shorten(styled_text, limit + len_styling) if limit else styled_text timestamp = tweet.absolute_datetime if conf.use_abs_time else tweet.relative_datetime return "➤ {nick} ({time}):\n{tweet}".format( nick=click.style(tweet.source.nick, bold=True), tweet=final_text, time=click.style(timestamp, dim=True) )
def style_tweet(tweet, porcelain=False): conf = click.get_current_context().obj["conf"] limit = conf.character_limit if porcelain: return "{nick}\t{url}\t{tweet}".format( nick=tweet.source.nick, url=tweet.source.url, tweet=str(tweet)) else: styled_text = format_mentions(tweet.text) len_styling = len(styled_text) - len(click.unstyle(styled_text)) final_text = textwrap.shorten(styled_text, limit + len_styling) if limit else styled_text return "➤ {nick} ({time}):\n{tweet}".format( nick=click.style(tweet.source.nick, bold=True), tweet=final_text, time=click.style(tweet.relative_datetime, dim=True))
def parse_tweet(raw_tweet, source, now=None): """ Parses a single raw tweet line from a twtxt file and returns a :class:`Tweet` object. :param str raw_tweet: a single raw tweet line :param Source source: the source of the given tweet :param Datetime now: the current datetime :returns: the parsed tweet :rtype: Tweet """ if now is None: now = datetime.now(timezone.utc) raw_created_at, text = raw_tweet.split("\t", 1) created_at = parse_iso8601(raw_created_at) if created_at > now: raise ValueError("Tweet is from the future") return Tweet(click.unstyle(text.strip()), created_at, source)
def intro(): intro = [ click.style(".", dim=True), "Hi, I'm {}.".format(click.style("AJ", fg='red')), "I'm a {} with a strong interest in ".format(click.style("Python developer", fg='yellow')), "APIs, CLIs and subverting the dominant paradigm.", "This is my resume.", "", "Note: this is primarily intended for command-line addicts.", "A more conventional version can be found on LinkedIn." ] intro = [click.unstyle(item).center(80) for item in intro] intro = "\n".join(intro) intro = intro.replace("APIs", click.style("APIs", fg='green')) intro = intro.replace("CLIs", click.style("CLIs", fg='blue')) intro = intro.replace("subverting the dominant paradigm", click.style("subverting the dominant paradigm", fg='magenta')) colSpan = 5 rowSpan = 3.5 ret = Markdown(data=intro, colSpan=colSpan, rowSpan=rowSpan, label="") return ret
def test_report(self) -> None: report = black.Report() out_lines = [] err_lines = [] def out(msg: str, **kwargs: Any) -> None: out_lines.append(msg) def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) with patch("black.out", out), patch("black.err", err): report.done(Path("f1"), black.Changed.NO) self.assertEqual(len(out_lines), 1) self.assertEqual(len(err_lines), 0) self.assertEqual(out_lines[-1], "f1 already well formatted, good job.") self.assertEqual(unstyle(str(report)), "1 file left unchanged.") self.assertEqual(report.return_code, 0) report.done(Path("f2"), black.Changed.YES) self.assertEqual(len(out_lines), 2) self.assertEqual(len(err_lines), 0) self.assertEqual(out_lines[-1], "reformatted f2") self.assertEqual( unstyle(str(report)), "1 file reformatted, 1 file left unchanged." ) report.done(Path("f3"), black.Changed.CACHED) self.assertEqual(len(out_lines), 3) self.assertEqual(len(err_lines), 0) self.assertEqual( out_lines[-1], "f3 wasn't modified on disk since last run." ) self.assertEqual( unstyle(str(report)), "1 file reformatted, 2 files left unchanged." ) self.assertEqual(report.return_code, 0) report.check = True self.assertEqual(report.return_code, 1) report.check = False report.failed(Path("e1"), "boom") self.assertEqual(len(out_lines), 3) self.assertEqual(len(err_lines), 1) self.assertEqual(err_lines[-1], "error: cannot format e1: boom") self.assertEqual( unstyle(str(report)), "1 file reformatted, 2 files left unchanged, " "1 file failed to reformat.", ) self.assertEqual(report.return_code, 123) report.done(Path("f3"), black.Changed.YES) self.assertEqual(len(out_lines), 4) self.assertEqual(len(err_lines), 1) self.assertEqual(out_lines[-1], "reformatted f3") self.assertEqual( unstyle(str(report)), "2 files reformatted, 2 files left unchanged, " "1 file failed to reformat.", ) self.assertEqual(report.return_code, 123) report.failed(Path("e2"), "boom") self.assertEqual(len(out_lines), 4) self.assertEqual(len(err_lines), 2) self.assertEqual(err_lines[-1], "error: cannot format e2: boom") self.assertEqual( unstyle(str(report)), "2 files reformatted, 2 files left unchanged, " "2 files failed to reformat.", ) self.assertEqual(report.return_code, 123) report.done(Path("f4"), black.Changed.NO) self.assertEqual(len(out_lines), 5) self.assertEqual(len(err_lines), 2) self.assertEqual(out_lines[-1], "f4 already well formatted, good job.") self.assertEqual( unstyle(str(report)), "2 files reformatted, 3 files left unchanged, " "2 files failed to reformat.", ) self.assertEqual(report.return_code, 123) report.check = True self.assertEqual( unstyle(str(report)), "2 files would be reformatted, 3 files would be left unchanged, " "2 files would fail to reformat.", )
def search(self, search_string, season=False, episode=False, date_search=None, search_type='torrent'): """ Return an array of values: [ [ ['Title string', 'search url'], [head1, head2, head3, id], [head1-width, head2-width, head3-width], [head1-alignment, head2-alignment, head3-alignment] ], [ [<column 1 data>, <column 2 data>, <column 3 data>, <id>], [<column 1 data>, <column 2 data>, <column 3 data>, <id>], # etc... ] ] """ self.season = season self.episode = episode self.show_name = search_string self.search_type = search_type click.echo() if self.search_type == 'torrent': header = [ [search_string, ''], ['Name', 'Size', 'Date', 'Seeds', 'SE'], [0, 10, 12, 6, 2], ['<', '>', '<', '>', '<']] else: header = [ [search_string, ''], ['Name', 'Size', 'Date', 'SE'], [0, 10, 12, 3], ['<', '>', '<', '<']] if self.search_type == 'torrent': engines = self.torrent_engines elif self.search_type == 'nzb': engines = self.newsgroup_engines else: raise ValueError('search_type can only be "torrent" or "nzb"') # socket.setdefaulttimeout(5) # socket.setdefaulttimeout(0.1) episodes = [] with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: # For nzb's, the idx is needed so Provider.download knows # which engine was used. It's not needed for torrents # because there is no download method. res = { executor.submit( self.job, engine, search_string, season, episode, date_search, idx ): engine for idx, engine in enumerate(engines) } names = [i.name for i in engines] names.sort() names = [' %s ' % i for i in names] names = [tu.style(i, fg='white', bg='red') for i in names] for future in concurrent.futures.as_completed(res): results = future.result() finished_name = results[-1] for i, e in enumerate(names): e = click.unstyle(e).strip() if e == finished_name: e = ' %s ' % e names[i] = tu.style(e, fg='white', bg='green') if date_search: title = '%s %s' % (search_string.strip(), date_search) else: title = '%s %s' % (search_string.strip(), tu.sxxexx(season, episode)) title = title.ljust(Config.console_columns) click.echo(tu.style(title, bold=True)) click.echo(' '.join(names)) # move up two lines click.echo('[%sA' % 3) episodes = episodes + results[:-1] # go up 3 lines to remove the progress bar click.echo('[%sA' % 2) if self.search_type == 'torrent': self.sort_torrents(episodes) self.episodes = episodes # return search_results return [header] + [episodes]
def test_unstyle(): print(unstyle(underline('non-underline'))) print(unstyle(italic('non-italic')))
def print_header(label, is_error=False): terminal_width, _ = click.get_terminal_size() width = len(click.unstyle(label)) half_line = "=" * ((terminal_width - width - 2) / 2) click.echo("%s %s %s" % (half_line, label, half_line), err=is_error)