如何在 tox python 环境中使用 pytest 和 pyclip?

How to use pytest with pyclip inside a tox python env?

我正在使用 Pyperclip 将内容放入剪贴板并使用 Pytest 对其进行测试。我正在对运行 tox 的 CI/CD 使用 GitHub 操作。 运行 我本地系统上的 pytest 工作正常,但由于以下显示错误,在 tox 中做同样的事情失败了

    @pytest.mark.parametrize(
        ("rs", "ip", "port", "expected"),
        (("Something {} {}", "192", "1234", "Something 192 1234"),),
    )
    def test_rs_clipper(rs, ip, port, expected):
>       provide_rs(rs, ip, port)

tests/test_langhandler.py:39: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/python3.6/lib/python3.9/site-packages/rst/lang_handler.py:130: in provide_rs
    pyperclip.copy(f"{rs.format(ip,port)}")
.tox/python3.6/lib/python3.9/site-packages/pyperclip/__init__.py:618: in lazy_load_stub_copy
    return copy(text)

我假设这是因为虚拟环境 tox 正在创建。我如何模拟显示环境,以便至少 pyperclip 功能有效?

tox -rvv 的输出

setting PATH=/opt/rst/.tox/python3.6/bin:/opt/rst/venv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:/root/.local/bin:/snap/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:/root/.local/bin:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[1512278] /opt/rst$ /opt/rst/.tox/python3.6/bin/python -m pip freeze >.tox/python3.6/log/python3.6-0.log
python3.6 finish: envreport  after 0.57 seconds
python3.6 installed: attrs==21.4.0,black==22.3.0,certifi==2021.10.8,charset-normalizer==2.0.12,click==8.1.2,commonmark==0.9.1,coverage==6.3.2,coverage-badge==1.1.0,distlib==0.3.4,filelock==3.6.0,flake8==4.0.1,idna==3.3,iniconfig==1.1.1,keyboard==0.13.5,mccabe==0.6.1,mypy==0.942,mypy-extensions==0.4.3,netifaces==0.10.9,packaging==21.3,pathspec==0.9.0,platformdirs==2.5.2,pluggy==1.0.0,py==1.11.0,pycodestyle==2.8.0,pyflakes==2.4.0,Pygments==2.12.0,pyngrok==5.1.0,pyparsing==3.0.8,pyperclip==1.8.0,pytest==7.1.1,pytest-cov==3.0.0,python-coveralls==2.9.3,PyYAML==6.0,requests==2.27.1,reverse-shell-tool @ file:///opt/rst/.tox/.tmp/package/1/reverse-shell-tool-1.0.2.tar.gz,rich==12.2.0,simple-term-menu==1.4.1,six==1.16.0,toml==0.10.2,tomli==2.0.1,tox==3.25.0,typing_extensions==4.2.0,urllib3==1.26.9,virtualenv==20.14.1
python3.6 start: run-test-pre 
python3.6 run-test-pre: PYTHONHASHSEED='2092568237'
python3.6 finish: run-test-pre  after 0.00 seconds
python3.6 start: run-test 
python3.6 run-test: commands[0] | pytest --cov=/opt/rst/.tox/python3.6/tmp/src --basetemp=/opt/rst/.tox/python3.6/tmp
setting PATH=/opt/rst/.tox/python3.6/bin:/opt/rst/venv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:/root/.local/bin:/snap/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:/root/.local/bin:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[1512279] /opt/rst$ /opt/rst/.tox/python3.6/bin/pytest --cov=/opt/rst/.tox/python3.6/tmp/src --basetemp=/opt/rst/.tox/python3.6/tmp
============================================================== test session starts ===============================================================
platform linux -- Python 3.9.2, pytest-7.1.1, pluggy-1.0.0
cachedir: .tox/python3.6/.pytest_cache
rootdir: /opt/rst, configfile: pyproject.toml, testpaths: tests
plugins: cov-3.0.0
collected 2 items                                                                                                                                

tests/test_langhandler.py .F                                                                                                               [100%]/opt/rst/.tox/python3.6/lib/python3.9/site-packages/coverage/inorout.py:519: CoverageWarning: Module /opt/rst/.tox/python3.6/tmp/src was never imported. (module-not-imported)
  self.warn(f"Module {pkg} was never imported.", slug="module-not-imported")
/opt/rst/.tox/python3.6/lib/python3.9/site-packages/coverage/control.py:793: CoverageWarning: No data was collected. (no-data-collected)
  self._warn("No data was collected.", slug="no-data-collected")
WARNING: Failed to generate report: No data to report.

/opt/rst/.tox/python3.6/lib/python3.9/site-packages/pytest_cov/plugin.py:294: CovReportWarning: Failed to generate report: No data to report.

  self.cov_controller.finish()


==================================================================== FAILURES ====================================================================
__________________________________________ test_rs_clipper[Something {} {}-192-1234-Something 192 1234] __________________________________________

rs = 'Something {} {}', ip = '192', port = '1234', expected = 'Something 192 1234'

    @pytest.mark.parametrize(
        ("rs", "ip", "port", "expected"),
        (("Something {} {}", "192", "1234", "Something 192 1234"),),
    )
    def test_rs_clipper(rs, ip, port, expected):
>       provide_rs(rs, ip, port)

tests/test_langhandler.py:39: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/python3.6/lib/python3.9/site-packages/rst/lang_handler.py:130: in provide_rs
    pyperclip.copy(f"{rs.format(ip,port)}")
.tox/python3.6/lib/python3.9/site-packages/pyperclip/__init__.py:618: in lazy_load_stub_copy
    return copy(text)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pyperclip.init_no_clipboard.<locals>.ClipboardUnavailable object at 0x7f35938c1970>, args = ('Something 192 1234',), kwargs = {}

    def __call__(self, *args, **kwargs):
>       raise PyperclipException(EXCEPT_MSG)
E       pyperclip.PyperclipException: 
E           Pyperclip could not find a copy/paste mechanism for your system.
E           For more information, please visit https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error

.tox/python3.6/lib/python3.9/site-packages/pyperclip/__init__.py:303: PyperclipException

----------- coverage: platform linux, python 3.9.2-final-0 -----------

============================================================ short test summary info =============================================================
FAILED tests/test_langhandler.py::test_rs_clipper[Something {} {}-192-1234-Something 192 1234] - pyperclip.PyperclipException: 
========================================================== 1 failed, 1 passed in 0.19s ===========================================================
ERROR: InvocationError for command /opt/rst/.tox/python3.6/bin/pytest --cov=/opt/rst/.tox/python3.6/tmp/src --basetemp=/opt/rst/.tox/python3.6/tmp (exited with code 1)
python3.6 finish: run-test  after 0.59 seconds
python3.6 start: run-test-post 
python3.6 finish: run-test-post  after 0.00 seconds

我以前没有在 CI/CD 中使用过 pyperclip,所以我可能完全错了,但我的猜测是您需要在虚拟帧缓冲区中启动 X 服务器。这是我的一个项目的 link,但我已经复制了下面的重要部分:

# .github/workflows/test_and_release.yml
...
jobs:
  test:
    ...
    steps:
      - name: Run test suite
        uses: GabrielBB/xvfb-action@v1.2
        with:
          run: |
            pytest tests --cov glooey
    ...
...

基本上,我只使用 GabrielBB/xvfb-action,它会为我设置好一切。同样,我不确定这是否适合您,但我想我会把它放在那里以防万一。


编辑:启动 X 服务器只是第一步,您还需要为 pyperclip 提供访问剪贴板的方法,即通过安装 xselxclipgtk,或qt。有关详细信息,请参阅 ,但基本上您需要在 CI 工作流程中添加如下内容:

jobs:
  test:
    ...
    steps:
      - name: Install test dependencies
        run: sudo apt-get install xclip
    ...
...