I'm using Pyperclip to put something into the clipboard and testing it with Pytest. I'm using GitHub actions for CI/CD that runs tox. Running pytest on my local system works just fine, but doing the same in tox fails because of the following display errors
@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)
I'm assuming it's because of the virtual environment tox is creating. How can I simulate a display environment so at least the pyperclip functionality works?
Output for 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
I haven't used pyperclip in CI/CD before, so I might be totally wrong, but my guess is that you need to start an X server within a virtual frame buffer. Here's a link to one of my projects that does this, but I've copied the important part below:
Basically, I just use GabrielBB/xvfb-action and it sets everything up for me. Again, I'm not sure that this will work for you, but I figured I'd put it out there just in case.
Edit: Starting an X server is just the first step, you also need to provide pyperclip with a way to access the clipboard, i.e. by installing
xsel
,xclip
,gtk
, orqt
. See this stack overflow post for more details, but basically you need to add something like this to your CI workflow: