Skip to content
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

3.8.0: pytest is failing in ::project unit #9

Closed
kloczek opened this issue Jun 4, 2022 · 6 comments
Closed

3.8.0: pytest is failing in ::project unit #9

kloczek opened this issue Jun 4, 2022 · 6 comments

Comments

@kloczek
Copy link

kloczek commented Jun 4, 2022

I'm trying to package your module as an rpm package. So I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix>
  • run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>

Here is pytest output:

+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-jaraco-text-3.8.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-jaraco-text-3.8.0-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.13, pytest-7.1.2, pluggy-1.0.0
rootdir: /home/tkloczko/rpmbuild/BUILD/jaraco.text-3.8.0, configfile: pytest.ini
plugins: cov-3.0.0, flake8-1.1.1, checkdocs-2.7.1
collected 26 items

. F                                                                                                                                                                  [  4%]
jaraco/text/__init__.py ......................                                                                                                                       [ 92%]
jaraco/text/layouts.py ..                                                                                                                                            [100%]

================================================================================= FAILURES =================================================================================
_______________________________________________________________________________ test session _______________________________________________________________________________

cls = <class '_pytest.runner.CallInfo'>, func = <function call_runtest_hook.<locals>.<lambda> at 0x7f0e6b27ae50>, when = 'call'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)

    @classmethod
    def from_call(
        cls,
        func: "Callable[[], TResult]",
        when: "Literal['collect', 'setup', 'call', 'teardown']",
        reraise: Optional[
            Union[Type[BaseException], Tuple[Type[BaseException], ...]]
        ] = None,
    ) -> "CallInfo[TResult]":
        """Call func, wrapping the result in a CallInfo.

        :param func:
            The function to call. Called without arguments.
        :param when:
            The phase in which the function is called.
        :param reraise:
            Exception or exceptions that shall propagate if raised by the
            function, instead of being wrapped in the CallInfo.
        """
        excinfo = None
        start = timing.time()
        precise_start = timing.perf_counter()
        try:
>           result: Optional[TResult] = func()

/usr/lib/python3.8/site-packages/_pytest/runner.py:338:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

>       lambda: ihook(item=item, **kwds), when=when, reraise=reraise
    )

/usr/lib/python3.8/site-packages/_pytest/runner.py:259:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_HookCaller 'pytest_runtest_call'>, args = (), kwargs = {'item': <CheckdocsItem project>}, argname = 'item', firstresult = False

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()

        # This is written to avoid expensive operations when not needed.
        if self.spec:
            for argname in self.spec.argnames:
                if argname not in kwargs:
                    notincall = tuple(set(self.spec.argnames) - kwargs.keys())
                    warnings.warn(
                        "Argument(s) {} which are declared in the hookspec "
                        "can not be found in this hook call".format(notincall),
                        stacklevel=2,
                    )
                    break

            firstresult = self.spec.opts.get("firstresult")
        else:
            firstresult = False

>       return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)

/usr/lib/python3.8/site-packages/pluggy/_hooks.py:265:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.config.PytestPluginManager object at 0x7f0e6c7ebe20>, hook_name = 'pytest_runtest_call'
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/usr/lib/python3.8/site-packages/_pytest/runner...eption', plugin=<module '_pytest.threadexception' from '/usr/lib/python3.8/site-packages/_pytest/threadexception.py'>>]
kwargs = {'item': <CheckdocsItem project>}, firstresult = False

    def _hookexec(self, hook_name, methods, kwargs, firstresult):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook_name, methods, kwargs, firstresult)

/usr/lib/python3.8/site-packages/pluggy/_manager.py:80:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

hook_name = 'pytest_runtest_call'
hook_impls = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/usr/lib/python3.8/site-packages/_pytest/runner...eption', plugin=<module '_pytest.threadexception' from '/usr/lib/python3.8/site-packages/_pytest/threadexception.py'>>]
caller_kwargs = {'item': <CheckdocsItem project>}, firstresult = False

    def _multicall(hook_name, hook_impls, caller_kwargs, firstresult):
        """Execute a call into multiple python functions/methods and return the
        result(s).

        ``caller_kwargs`` comes from _HookCaller.__call__().
        """
        __tracebackhide__ = True
        results = []
        excinfo = None
        try:  # run impl and wrapper setup functions in a loop
            teardowns = []
            try:
                for hook_impl in reversed(hook_impls):
                    try:
                        args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                    except KeyError:
                        for argname in hook_impl.argnames:
                            if argname not in caller_kwargs:
                                raise HookCallError(
                                    f"hook call must provide argument {argname!r}"
                                )

                    if hook_impl.hookwrapper:
                        try:
                            gen = hook_impl.function(*args)
                            next(gen)  # first yield
                            teardowns.append(gen)
                        except StopIteration:
                            _raise_wrapfail(gen, "did not yield")
                    else:
                        res = hook_impl.function(*args)
                        if res is not None:
                            results.append(res)
                            if firstresult:  # halt further impl calls
                                break
            except BaseException:
                excinfo = sys.exc_info()
        finally:
            if firstresult:  # first result hooks return a single value
                outcome = _Result(results[0] if results else None, excinfo)
            else:
                outcome = _Result(results, excinfo)

            # run all wrapper post-yield blocks
            for gen in reversed(teardowns):
                try:
                    gen.send(outcome)
                    _raise_wrapfail(gen, "has second yield")
                except StopIteration:
                    pass

>           return outcome.get_result()

/usr/lib/python3.8/site-packages/pluggy/_callers.py:60:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pluggy._result._Result object at 0x7f0e6c074f10>

    def get_result(self):
        """Get the result(s) for this hook call.

        If the hook was marked as a ``firstresult`` only a single value
        will be returned otherwise a list of results.
        """
        __tracebackhide__ = True
        if self._excinfo is None:
            return self._result
        else:
            ex = self._excinfo
>           raise ex[1].with_traceback(ex[2])

/usr/lib/python3.8/site-packages/pluggy/_result.py:60:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

hook_name = 'pytest_runtest_call'
hook_impls = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/usr/lib/python3.8/site-packages/_pytest/runner...eption', plugin=<module '_pytest.threadexception' from '/usr/lib/python3.8/site-packages/_pytest/threadexception.py'>>]
caller_kwargs = {'item': <CheckdocsItem project>}, firstresult = False

    def _multicall(hook_name, hook_impls, caller_kwargs, firstresult):
        """Execute a call into multiple python functions/methods and return the
        result(s).

        ``caller_kwargs`` comes from _HookCaller.__call__().
        """
        __tracebackhide__ = True
        results = []
        excinfo = None
        try:  # run impl and wrapper setup functions in a loop
            teardowns = []
            try:
                for hook_impl in reversed(hook_impls):
                    try:
                        args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                    except KeyError:
                        for argname in hook_impl.argnames:
                            if argname not in caller_kwargs:
                                raise HookCallError(
                                    f"hook call must provide argument {argname!r}"
                                )

                    if hook_impl.hookwrapper:
                        try:
                            gen = hook_impl.function(*args)
                            next(gen)  # first yield
                            teardowns.append(gen)
                        except StopIteration:
                            _raise_wrapfail(gen, "did not yield")
                    else:
>                       res = hook_impl.function(*args)

/usr/lib/python3.8/site-packages/pluggy/_callers.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

item = <CheckdocsItem project>

    def pytest_runtest_call(item: Item) -> None:
        _update_current_test_var(item, "call")
        try:
            del sys.last_type
            del sys.last_value
            del sys.last_traceback
        except AttributeError:
            pass
        try:
            item.runtest()
        except Exception as e:
            # Store trace info to allow postmortem debugging
            sys.last_type = type(e)
            sys.last_value = e
            assert e.__traceback__ is not None
            # Skip *this* frame
            sys.last_traceback = e.__traceback__.tb_next
>           raise e

/usr/lib/python3.8/site-packages/_pytest/runner.py:174:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

item = <CheckdocsItem project>

    def pytest_runtest_call(item: Item) -> None:
        _update_current_test_var(item, "call")
        try:
            del sys.last_type
            del sys.last_value
            del sys.last_traceback
        except AttributeError:
            pass
        try:
>           item.runtest()

/usr/lib/python3.8/site-packages/_pytest/runner.py:166:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <CheckdocsItem project>

    def runtest(self):
>       desc = self.get_long_description()

/usr/lib/python3.8/site-packages/pytest_checkdocs/__init__.py:40:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <CheckdocsItem project>

    def get_long_description(self):
        with _suppress_deprecation():
>           return Description.from_md(ensure_clean(pep517.meta.load('.').metadata))

/usr/lib/python3.8/site-packages/pytest_checkdocs/__init__.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

root = '.'

    def load(root):
        """
        Given a source directory (root) of a package,
        return an importlib.metadata.Distribution object
        with metadata build from that package.
        """
        root = os.path.expanduser(root)
        system = compat_system(root)
        builder = functools.partial(build, source_dir=root, system=system)
>       path = Path(build_as_zip(builder))

/usr/lib/python3.8/site-packages/pep517/meta.py:71:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

builder = functools.partial(<function build at 0x7f0e6b387790>, source_dir='.', system={'requires': ['setuptools>=56', 'setuptools_scm[toml]>=3.4.1'], 'build-backend': 'setuptools.build_meta'})

    def build_as_zip(builder=build):
        with tempdir() as out_dir:
>           builder(dest=out_dir)

/usr/lib/python3.8/site-packages/pep517/meta.py:58:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

source_dir = '.', dest = '/tmp/tmpuiulg6cv', system = {'build-backend': 'setuptools.build_meta', 'requires': ['setuptools>=56', 'setuptools_scm[toml]>=3.4.1']}

    def build(source_dir='.', dest=None, system=None):
        system = system or load_system(source_dir)
        dest = os.path.join(source_dir, dest or 'dist')
        mkdir_p(dest)
        validate_system(system)
        hooks = Pep517HookCaller(
            source_dir, system['build-backend'], system.get('backend-path')
        )

        with hooks.subprocess_runner(quiet_subprocess_runner):
            with BuildEnvironment() as env:
                env.pip_install(system['requires'])
>               _prep_meta(hooks, env, dest)

/usr/lib/python3.8/site-packages/pep517/meta.py:53:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

hooks = <pep517.wrappers.Pep517HookCaller object at 0x7f0e6bffd6a0>, env = <pep517.envbuild.BuildEnvironment object at 0x7f0e6c0171f0>, dest = '/tmp/tmpuiulg6cv'

    def _prep_meta(hooks, env, dest):
>       reqs = hooks.get_requires_for_build_wheel({})

/usr/lib/python3.8/site-packages/pep517/meta.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pep517.wrappers.Pep517HookCaller object at 0x7f0e6bffd6a0>, config_settings = {}

    def get_requires_for_build_wheel(self, config_settings=None):
        """Identify packages required for building a wheel

        Returns a list of dependency specifications, e.g.::

            ["wheel >= 0.25", "setuptools"]

        This does not include requirements specified in pyproject.toml.
        It returns the result of calling the equivalently named hook in a
        subprocess.
        """
>       return self._call_hook('get_requires_for_build_wheel', {
            'config_settings': config_settings
        })

/usr/lib/python3.8/site-packages/pep517/wrappers.py:172:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pep517.wrappers.Pep517HookCaller object at 0x7f0e6bffd6a0>, hook_name = 'get_requires_for_build_wheel', kwargs = {'config_settings': {}}

    def _call_hook(self, hook_name, kwargs):
        # On Python 2, pytoml returns Unicode values (which is correct) but the
        # environment passed to check_call needs to contain string values. We
        # convert here by encoding using ASCII (the backend can only contain
        # letters, digits and _, . and : characters, and will be used as a
        # Python identifier, so non-ASCII content is wrong on Python 2 in
        # any case).
        # For backend_path, we use sys.getfilesystemencoding.
        if sys.version_info[0] == 2:
            build_backend = self.build_backend.encode('ASCII')
        else:
            build_backend = self.build_backend
        extra_environ = {'PEP517_BUILD_BACKEND': build_backend}

        if self.backend_path:
            backend_path = os.pathsep.join(self.backend_path)
            if sys.version_info[0] == 2:
                backend_path = backend_path.encode(sys.getfilesystemencoding())
            extra_environ['PEP517_BACKEND_PATH'] = backend_path

        with tempdir() as td:
            hook_input = {'kwargs': kwargs}
            compat.write_json(hook_input, pjoin(td, 'input.json'),
                              indent=2)

            # Run the hook in a subprocess
            with _in_proc_script_path() as script:
                python = self.python_executable
>               self._subprocess_runner(
                    [python, abspath(str(script)), hook_name, td],
                    cwd=self.source_dir,
                    extra_environ=extra_environ
                )

/usr/lib/python3.8/site-packages/pep517/wrappers.py:322:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cmd = ['/usr/bin/python3', '/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py', 'get_requires_for_build_wheel', '/tmp/tmpl5gvt1ft']
cwd = '/home/tkloczko/rpmbuild/BUILD/jaraco.text-3.8.0', extra_environ = {'PEP517_BUILD_BACKEND': 'setuptools.build_meta'}

    def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None):
        """A method of calling the wrapper subprocess while suppressing output."""
        env = os.environ.copy()
        if extra_environ:
            env.update(extra_environ)

>       check_output(cmd, cwd=cwd, env=env, stderr=STDOUT)

/usr/lib/python3.8/site-packages/pep517/wrappers.py:75:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

timeout = None, popenargs = (['/usr/bin/python3', '/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py', 'get_requires_for_build_wheel', '/tmp/tmpl5gvt1ft'],)
kwargs = {'cwd': '/home/tkloczko/rpmbuild/BUILD/jaraco.text-3.8.0', 'env': {'AR': '/usr/bin/gcc-ar', 'BASH_ENV': '/usr/share/lm...echo "Shell debugging restarted" 1>&2;\n set -$__lmod_sh_dbg;\n fi;\n return $__lmod_my_status\n}', ...}, 'stderr': -2}

    def check_output(*popenargs, timeout=None, **kwargs):
        r"""Run command with arguments and return its output.

        If the exit code was non-zero it raises a CalledProcessError.  The
        CalledProcessError object will have the return code in the returncode
        attribute and output in the output attribute.

        The arguments are the same as for the Popen constructor.  Example:

        >>> check_output(["ls", "-l", "/dev/null"])
        b'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

        The stdout argument is not allowed as it is used internally.
        To capture standard error in the result, use stderr=STDOUT.

        >>> check_output(["/bin/sh", "-c",
        ...               "ls -l non_existent_file ; exit 0"],
        ...              stderr=STDOUT)
        b'ls: non_existent_file: No such file or directory\n'

        There is an additional optional argument, "input", allowing you to
        pass a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it too will be used internally.  Example:

        >>> check_output(["sed", "-e", "s/foo/bar/"],
        ...              input=b"when in the course of fooman events\n")
        b'when in the course of barman events\n'

        By default, all communication is in bytes, and therefore any "input"
        should be bytes, and the return value will be bytes.  If in text mode,
        any "input" should be a string, and the return value will be a string
        decoded according to locale encoding, or by "encoding" if set. Text mode
        is triggered by setting any of text, encoding, errors or universal_newlines.
        """
        if 'stdout' in kwargs:
            raise ValueError('stdout argument not allowed, it will be overridden.')

        if 'input' in kwargs and kwargs['input'] is None:
            # Explicitly passing input=None was previously equivalent to passing an
            # empty string. That is maintained here for backwards compatibility.
            if kwargs.get('universal_newlines') or kwargs.get('text'):
                empty = ''
            else:
                empty = b''
            kwargs['input'] = empty

>       return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
                   **kwargs).stdout

/usr/lib64/python3.8/subprocess.py:415:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

input = None, capture_output = False, timeout = None, check = True
popenargs = (['/usr/bin/python3', '/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py', 'get_requires_for_build_wheel', '/tmp/tmpl5gvt1ft'],)
kwargs = {'cwd': '/home/tkloczko/rpmbuild/BUILD/jaraco.text-3.8.0', 'env': {'AR': '/usr/bin/gcc-ar', 'BASH_ENV': '/usr/share/lm...bugging restarted" 1>&2;\n set -$__lmod_sh_dbg;\n fi;\n return $__lmod_my_status\n}', ...}, 'stderr': -2, 'stdout': -1}
process = <subprocess.Popen object at 0x7f0e6c017dc0>
stdout = b'Traceback (most recent call last):\n  File "/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py", line...ng pip, instead of https://github.com/user/proj/archive/master.zip use git+https://github.com/user/proj.git#egg=proj\n'
stderr = None, retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.

        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.

        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output & stderr attributes if those streams
        were captured.

        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.

        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.

        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.

        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE

        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE

        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
>               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['/usr/bin/python3', '/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py', 'get_requires_for_build_wheel', '/tmp/tmpl5gvt1ft']' returned non-zero exit status 1.

/usr/lib64/python3.8/subprocess.py:516: CalledProcessError
========================================================================= short test summary info ==========================================================================
FAILED ::project - subprocess.CalledProcessError: Command '['/usr/bin/python3', '/usr/lib/python3.8/site-packages/pep517/in_process/_in_process.py', 'get_requires_for_bu...
======================================================================= 1 failed, 24 passed in 3.12s =======================================================================

I'm going add that unit in my build procedure to --deselet list.

@jaraco
Copy link
Owner

jaraco commented Jul 6, 2022

It appears that in your environment, when pytest-checkdocs invokes:

pep517.meta.load('.')

Which results in an exception. Unfortunately, the exception is unclear from the output.

It fails to create a build environment in order to compute the metadata.

I'd suggest to try to replicate the error using pep517 only.

If you can create a Dockerfile that replicates the issue, I can probably inspect more deeply.

I don't believe this project is doing anything special compared to other projects I maintain, so I'm surprised the issue is only happening with this project in particular.

To work around the issue, you can probably disable the checkdocs plugin by passing -p no:checkdocs to pytest.

@kloczek
Copy link
Author

kloczek commented Jul 6, 2022

I'd suggest to try to replicate the error using pep517 only.

Please have look one more time on top of this ticket.
I'm usin pep517 build procedure.

If you can create a Dockerfile that replicates the issue, I can probably inspect more deeply.

I'm not using docker and ano go related software as it popents seriouse security risk (please look on rate of CVEs in golang; docker implemeted in python is no longer maintained).
Here is list of modyules with versions installed in build env

Package                       Version
----------------------------- -----------------
alabaster                     0.7.12
attrs                         22.1.0.dev0
Babel                         2.10.2
Brlapi                        0.8.3
build                         0.8.0
charset-normalizer            2.1.0
codespell                     2.1.0
cycler                        0.11.0
distro                        1.7.0
docutils                      0.17.1
extras                        1.0.0
fixtures                      4.0.0
fonttools                     4.33.3
gpg                           1.17.1-unknown
idna                          3.3
imagesize                     1.4.1
importlib-metadata            4.12.0
importlib-resources           5.8.0
iniconfig                     1.1.1
jaraco.context                4.1.1
jaraco.functools              3.5.0
jaraco.packaging              9.0.0
Jinja2                        3.1.1
kiwisolver                    1.4.3
libcomps                      0.1.18
louis                         3.22.0
MarkupSafe                    2.1.1
matplotlib                    3.5.2
more-itertools                8.13.0
numpy                         1.23.0
olefile                       0.46
packaging                     21.3
pbr                           5.8.1
pep517                        0.12.0
Pillow                        9.2.0
pip                           22.0.4
pluggy                        1.0.0
py                            1.11.0
Pygments                      2.12.0
PyGObject                     3.42.1
pyparsing                     3.0.9
pyrsistent                    0.18.1
pytest                        7.1.2
python-dateutil               2.8.2
pytz                          2022.1
requests                      2.28.1
rpm                           4.17.0
rst.linker                    2.3.0
setuptools                    63.1.0
setuptools-scm                7.0.4
six                           1.16.0
snowballstemmer               2.2.0
Sphinx                        5.0.2
sphinxcontrib-applehelp       1.0.2.dev20220410
sphinxcontrib-devhelp         1.0.2.dev20220410
sphinxcontrib-htmlhelp        2.0.0
sphinxcontrib-jsmath          1.0.1.dev20220704
sphinxcontrib-qthelp          1.0.3.dev20220704
sphinxcontrib-serializinghtml 1.1.5
testtools                     2.5.0
tomli                         2.0.1
traitlets                     5.3.0
typing_extensions             4.2.0
urllib3                       1.26.9
wheel                         0.37.1
zipp                          3.8.0

To work around the issue, you can probably disable the checkdocs plugin by passing -p no:checkdocs to pytest.

Is ti not easier to fix that issue?

@jaraco
Copy link
Owner

jaraco commented Jul 29, 2022

The problem is that I don't have a way to replicate the issue. Tests pass for me. Moreover, this project is using the same technique of pytest-checkdocs. I can't think of any reason why this project should have trouble but the dozens of others I maintain do not.

@jaraco
Copy link
Owner

jaraco commented Jul 29, 2022

I did try replicating the issue by using pip to install packages to system Python 3.10 on Ubuntu 20.04, but the tests still run. I need help replicating the issue. If not a dockerfile, can you provide a script that replicates the issue on a clean OS image?

@jaraco jaraco closed this as completed Jul 30, 2023
@kloczek
Copy link
Author

kloczek commented Jul 30, 2023

This issue is possible to solve by:

  • fixing ::project unit
  • add pytest settings testpaths variable to force pytest to scan only in exact directory/directories

@jaraco
Copy link
Owner

jaraco commented Jul 30, 2023

The ::project unit is the test for pytest-checkdocs. It's part of the test suite and ensures that the README renders properly. The test works fine, but it relies on being able to resolve the metadata, which requires downloading and installing build dependencies.

pytest-checkdocs was recently rewritten to use build instead of pep517 (jaraco/pytest-checkdocs#17). This issue is the same as jaraco/pytest-checkdocs#19, whose root cause is tracked in pypa/build#556.

Someone needs to implement a mechanism for offline builds to support building metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants