Exemple #1
0
def pformat_tabs(
		obj: object,
		width: int = 80,
		depth: Optional[int] = None,
		*,
		compact: bool = False,
		) -> str:
	"""
	Format a Python object into a pretty-printed representation.

	Indentation is set at one tab.

	:param obj: The object to format.
	:param width: The maximum width of the output.
	:param depth:
	:param compact:
	"""

	prettyprinter = FancyPrinter(indent=4, width=width, depth=depth, compact=compact)

	buf = StringList()
	for line in prettyprinter.pformat(obj).splitlines():
		buf.append(re.sub("^ {4}", r"\t", line))

	return str(buf)
    def test_copy(self):
        sl = StringList(['', '', "hello", "world", '', '', '', "1234"])
        sl2 = sl.copy()

        assert sl == sl2
        assert sl2 == ['', '', "hello", "world", '', '', '', "1234"]
        assert isinstance(sl2, StringList)
 def test_set_indent_error(self):
     sl = StringList()
     with pytest.raises(
             TypeError,
             match=
             "'size' argument cannot be used when providing an 'Indent' object."
     ):
         sl.set_indent(Indent(0, "    "), 5)
    def test_extend(self):
        sl = StringList(['', '', "hello", "world", '', '', '', "1234"])
        sl.extend(["\nfoo\nbar\n    baz"])

        assert sl == [
            '', '', "hello", "world", '', '', '', "1234", '', "foo", "bar",
            "    baz"
        ]
Exemple #5
0
def requirement(requirement: str, file: Optional[str] = None) -> int:
    """
	Add a requirement.
	"""

    # 3rd party
    from consolekit.utils import abort
    from domdf_python_tools.paths import PathPlus, traverse_to_file
    from domdf_python_tools.stringlist import StringList
    from packaging.requirements import InvalidRequirement
    from packaging.specifiers import SpecifierSet
    from shippinglabel import normalize_keep_dot
    from shippinglabel.requirements import ComparableRequirement, combine_requirements, read_requirements

    repo_dir: PathPlus = traverse_to_file(PathPlus.cwd(), "repo_helper.yml",
                                          "git_helper.yml")

    if file is None:
        requirements_file = repo_dir / "requirements.txt"

        if not requirements_file.is_file():
            raise abort(f"'{file}' not found.")

    else:
        requirements_file = PathPlus(file)

        if not requirements_file.is_file():
            raise abort("'requirements.txt' not found.")

    try:
        req = ComparableRequirement(requirement)
    except InvalidRequirement as e:
        raise BadRequirement(requirement, e)

    response = (PYPI_API / req.name / "json/").get()
    if response.status_code != 200:
        raise click.BadParameter(f"No such project {req.name}")
    else:
        req.name = normalize(response.json()["info"]["name"])
        if not req.specifier:
            req.specifier = SpecifierSet(
                f">={response.json()['info']['version']}")

        click.echo(f"Adding requirement '{req}'")

    requirements, comments, invalid_lines = read_requirements(
        req_file=requirements_file,
        include_invalid=True,
        normalize_func=normalize_keep_dot,
    )

    requirements.add(req)

    buf = StringList([*comments, *invalid_lines])
    buf.extend(str(req) for req in sorted(combine_requirements(requirements)))
    requirements_file.write_lines(buf)

    return 0
Exemple #6
0
def sort_requirements(filename: PathLike, allow_git: bool = False) -> int:
    """
	Sort the requirements in the given file alphabetically.

	:param filename: The file to sort the requirements in.
	:param allow_git: Whether to allow lines that start with ``git+``, which are allowed by pip but not :pep:`508`.
	"""

    ret = PASS
    filename = PathPlus(filename)
    comments: List[str]
    requirements: Set[ComparableRequirement]
    git_lines: List[str] = []

    requirements, comments, invalid_lines = read_requirements(
        req_file=filename,
        include_invalid=True,
        normalize_func=normalize_keep_dot,
    )

    for line in invalid_lines:
        if line.startswith("git+") and allow_git:
            git_lines.append(line)
        else:
            ret |= FAIL

    # find and remove pkg-resources==0.0.0
    # which is automatically added by broken pip package under Debian
    if ComparableRequirement("pkg-resources==0.0.0") in requirements:
        requirements.remove(ComparableRequirement("pkg-resources==0.0.0"))
        ret |= FAIL

    sorted_requirements = sorted(requirements)

    buf = StringList(
        [*comments, *git_lines, *[str(req) for req in sorted_requirements]])
    buf.blankline(ensure_single=True)

    if (requirements != sorted_requirements
            and buf != filename.read_lines()) or ret:
        print('\n'.join(buf))
        # print(coloured_diff(
        # 		filename.read_lines(),
        # 		buf,
        # 		str(filename),
        # 		str(filename),
        # 		"(original)",
        # 		"(sorted)",
        # 		lineterm='',
        # 		))
        ret |= FAIL
        filename.write_lines(buf)

    return ret
Exemple #7
0
def clean_writer(string: str, fp: IO) -> None:
    """
	Write string to ``fp`` without trailing spaces.

	:param string:
	:param fp:
	"""

    # this package
    from domdf_python_tools.stringlist import StringList

    buffer = StringList(string)
    buffer.blankline(ensure_single=True)
    fp.write(str(buffer))
Exemple #8
0
	def run(self) -> bool:
		"""
		Run the reformatter.

		:return: Whether the file was changed.
		"""

		hooks = parse_hooks(self.config)
		reformatted_source = StringList(call_hooks(hooks, self._unformatted_source, self.filename))
		reformatted_source.blankline(ensure_single=True)

		self._reformatted_source = str(reformatted_source)

		return self._reformatted_source != self._unformatted_source
Exemple #9
0
def configure(app: Sphinx, config: Config):
    """
	Configure Sphinx Extension.

	:param app: The Sphinx application.
	:param config:
	"""

    latex_elements = getattr(config, "latex_elements", {})

    latex_extrapackages = StringList(latex_elements.get("extrapackages", ''))
    latex_extrapackages.append(r"\usepackage{needspace}")
    latex_elements["extrapackages"] = str(latex_extrapackages)

    config.latex_elements = latex_elements  # type: ignore
Exemple #10
0
	def __init__(self, base_path: pathlib.Path):
		self.base_path = base_path
		self._ini = ConfigUpdater()

		self._output = StringList([
				f"# {self.managed_message}",
				"# You may add new sections, but any changes made to the following sections will be lost:",
				])

		self.managed_sections = self.managed_sections[:]

		for sec in self.managed_sections:
			self._ini.add_section(sec)
			self._output.append(f"#     * {sec}")

		self._output.blankline(ensure_single=True)
Exemple #11
0
def copy_assets(app: Sphinx, exception: Optional[Exception] = None) -> None:
	"""
	Copy asset files to the output.

	:param app: The Sphinx application.
	:param exception: Any exception which occurred and caused Sphinx to abort.
	"""

	if exception:  # pragma: no cover
		return

	style = StringList([
			".docutils.container {",
			"    padding-left: 0 !important;",
			"    padding-right: 0 !important;",
			'}',
			'',
			# "div.sphinx-tabs.docutils.container {",
			# "    padding-left: 0 !important;",
			# "    padding-right: 0 !important;",
			# "}",
			# '',
			"div.ui.top.attached.tabular.menu.sphinx-menu.docutils.container {",
			# "    padding-left: 0 !important;",
			# "    padding-right: 0 !important;",
			"    margin-left: 0 !important;",
			"    margin-right: 0 !important;",
			'}',
			])

	css_dir = PathPlus(app.builder.outdir) / "_static" / "css"
	css_dir.maybe_make(parents=True)
	css_file = css_dir / "tabs_customise.css"
	css_file.write_lines(style)
Exemple #12
0
def validate_config(app: Sphinx, config: Config):
    r"""
	Validate the provided configuration values.

	:param app: The Sphinx app.
	:param config:
	"""

    rst_prolog: Union[str, StringList] = config.rst_prolog or ''

    nbsp_sub = ".. |nbsp| unicode:: 0xA0\n   :trim:"
    if nbsp_sub not in rst_prolog:
        rst_prolog = StringList(rst_prolog)
        rst_prolog.append(nbsp_sub)

    config.rst_prolog = str(rst_prolog)  # type: ignore
Exemple #13
0
def test_prompt(capsys, monkeypatch, data_regression: DataRegressionFixture):

	inputs = iter([
			'',
			'',
			'',
			'',
			"24",
			"Bond007",
			"badpassword",
			"baspassword",
			"badpassword",
			"badpassword",
			"badpassword",
			"badpassword",
			])

	def fake_input(prompt):
		value = next(inputs)
		print(f"{prompt}{value}".rstrip())
		return value

	monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input)

	assert prompt(text="What is your age", prompt_suffix="? ", type=click.INT) == 24

	assert prompt(text="Username", type=click.STRING) == "Bond007"
	assert prompt(text="Password", type=click.STRING, confirmation_prompt=True) == "badpassword"
	assert prompt(
			text="Password",
			type=click.STRING,
			confirmation_prompt="Are you sure about that? ",
			) == "badpassword"

	data_regression.check(list(StringList(capsys.readouterr().out.splitlines())))
Exemple #14
0
    def check(self, page: BeautifulSoup, **kwargs):  # type: ignore
        r"""
		Check an HTML page generated by Sphinx for regressions,
		using `pytest-regressions <https://pypi.org/project/pytest-regressions/>`_

		:param page: The page to test.
		:param \*\*kwargs: Additional keyword arguments passed to
			:meth:`pytest_regressions.file_regression.FileRegressionFixture.check`.

		**Example usage**

		.. code-block:: python

			@pytest.mark.parametrize("page", ["index.html"], indirect=True)
			def test_page(page: BeautifulSoup, html_regression: HTMLRegressionFixture):
				html_regression.check(page, file_regression)
		"""  # noqa D400

        __tracebackhide__ = True

        page = remove_html_footer(page)
        page = remove_html_link_tags(page)

        for div in page.select("script"):
            if "_static/language_data.js" in str(div):
                div.extract()

        kwargs.pop("encoding", None)
        kwargs.pop("extension", None)

        super().check(
            str(StringList(page.prettify())),
            encoding="UTF-8",
            extension=".html",
        )
Exemple #15
0
def check_html_regression(page: BeautifulSoup,
                          file_regression: FileRegressionFixture):
    """
	Check an HTML page generated by Sphinx for regressions,
	using `pytest-regressions <https://pypi.org/project/pytest-regressions/>`_

	:param page: The page to test.
	:param file_regression: The file regression fixture.

	**Example usage**

	.. code-block:: python

		@pytest.mark.parametrize("page", ["index.html"], indirect=True)
		def test_page(page: BeautifulSoup, file_regression: FileRegressionFixture):
			check_html_regression(page, file_regression)
	"""  # noqa D400

    __tracebackhide__ = True

    page = remove_html_footer(page)
    page = remove_html_link_tags(page)

    for div in page.select("script"):
        if "_static/language_data.js" in str(div):
            div.extract()

    check_file_regression(
        StringList(page.prettify()),
        file_regression,
        extension=".html",
    )
    def test_sort(self):
        sl = StringList(['', '', "hello", "world", '', '', '', "1234"])
        sl.sort()
        assert sl == ['', '', '', '', '', "1234", "hello", "world"]
        assert isinstance(sl, StringList)

        sl = StringList(['', '', "hello", "world", '', '', '', "1234"])
        sl.sort(reverse=True)
        assert sl == ["world", "hello", "1234", '', '', '', '', '']
        assert isinstance(sl, StringList)
Exemple #17
0
    def dump_list(self, v) -> str:
        """
		Serialize a list to TOML.

		:param v:

		:rtype:

		.. latex:clearpage::
		"""

        single_line = super().dump_list(v)

        if len(single_line) <= self.max_width:
            return single_line

        retval = StringList(['['])

        with retval.with_indent("    ", 1):
            for u in v:
                retval.append(f"{str(self.dump_value(u))},")

        retval.append(']')

        return str(retval)
def test_make_style():
    style: css_parser.css.CSSStyleRule = make_style(
        "li p:last-child", {"max-width": (rem(1200), IMPORTANT)})
    assert str(style.selectorText) == "li p:last-child"
    assert StringList(style.cssText) == [
        "li p:last-child {",
        "    max-width: 1200rem !important",
        "    }",
    ]

    serializer = CSSSerializer(trailing_semicolon=True)

    with serializer.use():
        assert StringList(style.cssText) == [
            "li p:last-child {",
            "\tmax-width: 1200rem !important;",
            '}',
        ]
Exemple #19
0
    def get_linux_ci_requirements(self) -> List[str]:
        """
		Returns the Python requirements to run tests for on Linux.
		"""

        dependency_lines = StringList(
            self.templates.globals["github_ci_requirements"]["Linux"]["pre"])
        dependency_lines.extend(self.standard_python_install_lines)

        if self.templates.globals["enable_tests"]:
            dependency_lines.append(
                "python -m pip install --upgrade coverage_pyver_pragma")

        dependency_lines.extend(self._get_additional_requirements())
        dependency_lines.extend(
            self.templates.globals["github_ci_requirements"]["Linux"]["post"])

        return dependency_lines
    def test_creation(self):
        assert not StringList()
        assert not StringList([])
        assert not StringList(())

        assert StringList([1]) == ['1']
        assert StringList(['1']) == ['1']
        assert StringList('1') == ['1']
        assert StringList("1\n") == ['1', '']

        with pytest.raises(TypeError, match="'int' object is not iterable"):
            StringList(1)  # type: ignore
    def test_negative_getitem(self):
        sl = StringList(['', '', "hello", "world", '', '', "abc", "1234"])

        assert sl[-1] == "1234"
        sl[-1] += "5678"
        assert sl == ['', '', "hello", "world", '', '', "abc", "12345678"]

        assert sl[-2] == "abc"
        sl[-2] += "def"
        assert sl == ['', '', "hello", "world", '', '', "abcdef", "12345678"]
Exemple #22
0
def test_latex_output(app, latex_regression: LaTeXRegressionFixture):

    assert app.builder.name.lower() == "latex"

    with pytest.warns(UserWarning,
                      match="(No codes specified|No such code 'F401')"):
        app.build()

    output_file = PathPlus(app.outdir / "python.tex")
    latex_regression.check(StringList(output_file.read_lines()), jinja2=True)
    def check_modules(self) -> Iterator[Tuple[str, int]]:
        """
		Checks modules can be imported.

		:returns: An iterator of 2-element tuples comprising the name of the module and the import status:

			0. The module was imported successfully.
			1. The module could not be imported. If :attr:`~.show` is :py:obj:`True` the traceback will be shown.
		"""

        longest_name = 15
        echo = functools.partial(click.echo,
                                 color=resolve_color_default(self.colour))

        if self.modules:
            longest_name += max(map(len, self.modules))
        else:
            return

        for module_name in self.modules:
            echo(Style.BRIGHT(f"Checking {module_name!r}".ljust(
                longest_name, '.')),
                 nl=False)

            ret = check_module(module_name, combine_output=True)

            if ret:
                echo(Back.RED("Failed"))
                self.stats["failed"] += 1  # pylint: disable=loop-invariant-statement

                if self.show:
                    echo(Style.BRIGHT("Captured output:"))
                    stdout = StringList(ret.stdout)
                    stdout.blankline(ensure_single=True)
                    echo(stdout)

                yield module_name, 1

            else:
                echo(Back.GREEN("Passed"))
                self.stats["passed"] += 1  # pylint: disable=loop-invariant-statement
                yield module_name, 0
Exemple #24
0
def test_check_file_regression(tmp_pathplus: PathPlus,
                               file_regression: FileRegressionFixture):
    with pytest.raises(FileNotFoundError, match=no_such_file_pattern):
        check_file_output(tmp_pathplus / "file.txt", file_regression)

    check_file_regression("Success!\n\nThis is a test.", file_regression)

    result = StringList("Success!")
    result.blankline()
    result.blankline(ensure_single=True)
    result.append("This is a test.")

    check_file_regression(result, file_regression)
Exemple #25
0
def test_isort_stubs(advanced_file_regression: AdvancedFileRegressionFixture):
    source = StringList([
        'from natsort.natsort import as_ascii as as_ascii, as_utf8 as as_utf8, decoder as decoder, humansorted as '
        'humansorted, index_humansorted as index_humansorted, index_natsorted as index_natsorted, index_realsorted as '
        'index_realsorted, natsort_key as natsort_key, natsort_keygen as natsort_keygen, natsorted as natsorted, ns as ns, '
        'numeric_regex_chooser as numeric_regex_chooser, order_by_index as order_by_index, os_sort_key as os_sort_key, '
        'os_sort_keygen as os_sort_keygen, os_sorted as os_sorted, realsorted as realsorted',
        "from natsort.utils import chain_functions as chain_functions",
        '',
    ])
    advanced_file_regression.check(isort_hook(str(source), "utils.pyi"))
Exemple #26
0
def test_prompt_abort(capsys, monkeypatch, data_regression: DataRegressionFixture, exception):

	def fake_input(prompt):
		print(f"{prompt}", end='')
		raise exception

	monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input)

	with pytest.raises(click.Abort, match="^$"):
		prompt(text="Password", type=click.STRING, confirmation_prompt=True)

	assert list(StringList(capsys.readouterr().out.splitlines())) == ["Password:"]
def test_generics_functions(
        advanced_file_regression: AdvancedFileRegressionFixture):
    code = StringList([
        "def foo():",
        "\tdata: Tuple[int, int, str, float, str, int, bytes, int, int, str, float, str, int, bytes, int, int, str, float, str, int, bytes] = ()",
        '',
        "async def acync_foo():",
        "\tdata: Tuple[int, int, str, float, str, int, bytes, int, int, str, float, str, int, bytes, int, int, str, float, str, int, bytes] = ()",
    ])

    advanced_file_regression.check(reformat_generics(str(code)),
                                   extension="._py")
def test_latex_output(app, advanced_file_regression: AdvancedFileRegressionFixture):
	random.seed("5678")

	assert app.builder.name.lower() == "latex"
	app.build()

	output_file = PathPlus(app.outdir / "sphinx-highlights-demo.tex")
	content = str(StringList(output_file.read_lines())).replace("\\sphinxAtStartPar\n", '')
	advanced_file_regression.check(
			re.sub(r"\\date{.*}", r"\\date{Mar 11, 2021}", content),
			extension=".tex",
			)
Exemple #29
0
    def run(self) -> bool:
        """
		Run the reformatter.

		:return: Whether the file was changed.
		"""

        quote_formatted_code = reformat_quotes(self._unformatted_source)
        yapfed_code = FormatCode(quote_formatted_code,
                                 style_config=self.yapf_style)[0]
        generic_formatted_code = reformat_generics(yapfed_code)
        # TODO: support spaces

        try:
            isorted_code = StringList(
                isort.code(generic_formatted_code, config=self.isort_config))
        except FileSkipComment:
            isorted_code = StringList(generic_formatted_code)

        isorted_code.blankline(ensure_single=True)

        self._reformatted_source = str(isorted_code)

        # Fix for noqa comments being pushed to new line
        self._reformatted_source = noqa_reformat(self._reformatted_source)

        return self._reformatted_source != self._unformatted_source
    def document_keys(self, keys: List[str], types: Dict[str, Type],
                      docstrings: Dict[str, List[str]]):
        """
		Document keys in a :class:`typing.TypedDict`.

		:param keys: List of key names to document.
		:param types: Mapping of key names to types.
		:param docstrings: Mapping of key names to docstrings.
		"""

        content = StringList()

        for key in keys:
            if key in types:
                key_type = f"({format_annotation(types[key])}) "
            else:
                key_type = ''

            if key in docstrings:
                content.append(
                    f"    * **{key}** {key_type}-- {' '.join(docstrings.get(key, ''))}"
                )
            else:
                content.append(f"    * **{key}** {key_type}")

        for line in content:
            self.add_line(line, self.get_sourcename())