Giter VIP home page Giter VIP logo

xvfbwrapper's Introduction

xvfbwrapper

Manage headless displays with Xvfb (X virtual framebuffer)

image


Info:


About xvfbwrapper:

xvfbwrapper is a python module for controlling virtual displays with Xvfb.


What is Xvfb?:

Xvfb (X virtual framebuffer) is a display server implementing the X11 display server protocol. It runs in memory and does not require a physical display. Only a network layer is necessary.

Xvfb is useful for running acceptance tests on headless servers.


Install xvfbwrapper from PyPI:

pip install xvfbwrapper

System Requirements:

  • X11 Windowing System
  • Xvfb (sudo apt-get install xvfb, yum install xorg-x11-server-Xvfb, etc)
  • Python 2.7 or 3.4+

Examples

Basic Usage:

from xvfbwrapper import Xvfb

vdisplay = Xvfb()
vdisplay.start()

try:
    # launch stuff inside virtual display here.
finally:
    # always either wrap your usage of Xvfb() with try / finally,
    # or alternatively use Xvfb as a context manager.
    # If you don't, you'll probably end up with a bunch of junk in /tmp
    vdisplay.stop()

Basic Usage, specifying display geometry:

from xvfbwrapper import Xvfb

vdisplay = Xvfb(width=1280, height=740)
vdisplay.start()

try:
    # launch stuff inside virtual display here.
finally:
    vdisplay.stop()

Basic Usage, specifying display number:

from xvfbwrapper import Xvfb

vdisplay = Xvfb(display=23)
vdisplay.start()
# Xvfb is started with display :23
# see vdisplay.new_display

Usage as a Context Manager:

from xvfbwrapper import Xvfb

with Xvfb() as xvfb:
    # launch stuff inside virtual display here.
    # Xvfb will stop when this block completes

Testing Example: Headless Selenium WebDriver Tests:

This test class uses selenium webdriver and xvfbwrapper to run test cases on Firefox with a headless display.

import unittest

from selenium import webdriver
from xvfbwrapper import Xvfb


class TestPages(unittest.TestCase):

    def setUp(self):
        self.xvfb = Xvfb(width=1280, height=720)
        self.addCleanup(self.xvfb.stop)
        self.xvfb.start()
        self.browser = webdriver.Firefox()
        self.addCleanup(self.browser.quit)

    def testUbuntuHomepage(self):
        self.browser.get('http://www.ubuntu.com')
        self.assertIn('Ubuntu', self.browser.title)

    def testGoogleHomepage(self):
        self.browser.get('http://www.google.com')
        self.assertIn('Google', self.browser.title)


if __name__ == '__main__':
    unittest.main()
  • virtual display is launched
  • Firefox launches inside virtual display (headless)
  • browser is not shown while tests are run
  • conditions are asserted in each test case
  • browser quits during cleanup
  • virtual display stops during cleanup

Look Ma', no browser!

(You can also take screenshots inside the virtual display to help diagnose test failures)

xvfbwrapper's People

Contributors

alkuzad avatar cgoldberg avatar fuhrysteve avatar gesellc avatar jayakumarc avatar koterpillar avatar miljank avatar moschlar avatar peterdemin avatar pjw91 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xvfbwrapper's Issues

`_get_next_unused_display` broken on Ubuntu 16.04 + Python 3.5

Something seems to have changed when I upgraded from Ubuntu 15.10 with Python 3.4 to Ubuntu 16.04 with Python 3.5. Everything used to work fine, but now the _get_next_unused_display method fails to find the lock files in the right place and as a result xvfbwrapper will try to open multiple Xvfb instances on the same port when run in parallel.

The problem seems to be that tempfile.gettempdir cannot be relied on to return the same directory that Xvfb actually uses. In my case, the actual log files exist in /tmp, but tempfile.gettempdir() returns /tmp/amagee. I am able to fix the problem by changing

    tmpdir = tempfile.gettempdir()

to

    tmpdir = "/tmp"

but obviously this is not a portable solution and I'm not sure what would be.

The docs for tempfile.gettempdir (https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir) say:

Python searches a standard list of directories to find one which the calling user can create files in. The list is:

  1. The directory named by the TMPDIR environment variable.

And my TMPDIR environment variable is indeed /tmp/amagee.

Browser instances are always shown!

Hello Cgoldberg,

I'm playing around with this module... but the browser instances are always being shown, while the test run! The installation of xvfbwrapper is happened inside an venv, together with selenium... There are no error logs shown... Test runs with your examples only, on a MacOS-X 10.12.4

Any help would be very nice!
Thank you

_get_next_unused_display not multi process friendly

I'm playing with parallel instances of xvfbwrapper, each on a different process, and when I start all my processes at the same time, logs look like:

RuntimeError: Xvfb did not start
RuntimeError: Xvfb did not start
RuntimeError: Xvfb did not start
RuntimeError: Xvfb did not start
RuntimeError: Xvfb did not start
[...]

I have a few that succeed to start, and a lot failing, they tried to reuse the same X Display number than previous ones.

dealing with race conditions

I am having an issue with parallel execution when using Xvfb.

For the purposes of testing, I am attempting to run programs on several virtual displays at once, as well as some on the physical display. I need to run some things on the physical display for the tests to work on MacOS (Xvfb on Xquartz is not compiled with support for the GLX extension by default and some of the programs I am trying to run make use of OpenGL).

Currently the only way I see to run all of this is to use a resource lock for physical and virtual displays alike. This is because os.environ['DISPLAY'] is overwritten when the Xvfb instance is started and restored to its original value when it is stopped. I would like to avoid this as it would greatly slow down the testing.

Based on my understanding of the xvfbwrapper code, the problem would be fixed by an optional argument environ which is modified in place of os.environ (which would be the default value for the variable).

So usage would be something like:

locally_scoped_environ = os.environ.copy()
xvfb = Xvfb(environ=locall_scoped_environ)
xvfb.start()
subprocess.run("cmd",env=locally_scoped_environ)
xvfb.stop()

This would prevent other threads being exposed to the change in the DISPLAY variable but still make use of the resource locking that currently occurs for virtual displays. Would a PR for this functionality be welcome/accepted?

Another detail that may or may not be relevant is that I am running this using pytest and the pytest-parallel plugin with the --worker flag for several processes at once... or at least the documentation indicates that each worker is run in a separate process but my understanding is that os.environ changes would not effect the environment of other workers.

support for args upon initialization of Xvfb instance

Hi, thanks for the great tool.

I am wondering if you are willing to support extra arguments. To the wrapper upon initialization.

My use case is to pass arguments that are not a key value pair following the pattern '-'. Specifically I would do:

with Xvfb("+iglx") as xvfb:
    run_x_command_requiring_glx_extension()

Not a big deal. Currently I can resort to:

xvfb = Xvfb()
xvfb.extra_xvfb_args += ['+iglx']
xvfb.start()
run_x_command_requiring_glx_extension()
xvfb.stop()

It might be nice though. Or more generally making it more explicit in the documentation how one can deal with adding arguments that do not follow the pattern "Xvfb -key value"

EDIT: I see this is along the lines of #13. Apologies, I checked issues but not pull requests

KeyError: 'DISPLAY' in stop

Hi,
Thanks for the awesome wrapper!
I'm getting the below error running dryscrape with xvfbwrapper.
Ubuntu 16.04.2 LTS (Ubuntu Mate)
Python 2.7.12
xvfbwrapper-0.2.9

Error in sys.exitfunc:
Traceback (most recent call last):
File "/usr/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
func(*targs, **kargs)
File "/usr/local/lib/python2.7/dist-packages/xvfbwrapper.py", line 84, in stop
del os.environ['DISPLAY']
File "/usr/lib/python2.7/os.py", line 498, in delitem
del self.data[key]
KeyError: 'DISPLAY'

I'm not sure this is the best solution, but I was able to fix this by adding "if 'DISPLAY' in os.environ:" to check that 'DISPLAY' actually exists.

            if self.orig_display is None:
                if 'DISPLAY' in os.environ:
                   del os.environ['DISPLAY']

Adding the ability to take video on xvfb?

Would it be possible to take video using xvfbwrapper?

Looks like xvfb has this capability (ruby's headless does it) but I don't see it in the API here.

Obviously being able to take screenshots (with selenium) is really cool, but it'd be nice to be able to take videos. This might also be possible within selenium? Please let me know if i'm wrong about any of this. Thanks!

xvfbwrapper.py:93 cygwin/win32 compatibility

I recommend adding addition handling in xvfbwrapper.py on line 93 to include running on a win32/cygwin setup by also including looking for the executable 'xvfb-run', not just 'Xvfb' where 'Xvfb' hard string is the default for compatibility to the win32 OS and cygwin\bin binary bits version of Xvfb is installed.

Crash if DISPLAY is empty string

if 'DISPLAY' in os.environ:

Ran into an issue using this library. When os.environ['DISPLAY'] is an empty string, then it will perform the split based on ':' which has no second element. Rather than just checking if DISPLAY is set, it should check if it is set with a correct format.

Testsuite fails on i586 in test_xvfb.TestXvfb.test_start_fails_with_unknown_kwargs

[   84s] 
[   84s] ======================================================================
[   84s] FAIL: test_start_fails_with_unknown_kwargs (test_xvfb.TestXvfb)
[   84s] ----------------------------------------------------------------------
[   84s] Traceback (most recent call last):
[   84s]   File "/home/abuild/rpmbuild/BUILD/xvfbwrapper-0.2.9/test_xvfb.py", line 89, in test_start_fails_with_unknown_kwargs
[   84s]     xvfb.start()
[   84s] AssertionError: RuntimeError not raised

Full build log

OSError: Can not find Xvfb. Please install it and try again.

I have already installed it in my conda environment, but when I use
vdisplay = Xvfb() , I get this error
OSError: Can not find Xvfb. Please install it and try again. How can I solve this problem?
I am using Ubuntu 14.04 and python 3.7.16 with 0.2.9 wvbfwrapper
image

Update the start() method to do polling instead of a fixed sleep.

this code is from the start() method in xvfbwrapper.py:

# give Xvfb time to start
time.sleep(self.__class__.SLEEP_TIME_BEFORE_START)
ret_code = self.proc.poll()

It uses a fixed time.sleep(.1) to wait for Xvfb startup. Change this so it calls proc.poll() in a loop with a timeout.

Does not work as dependency - problems with easyinstall

mkdir test
cd test

cat << 'EOF' > setup.py
from setuptools import setup

setup(name='test', version='test', description='test', py_modules=['test'],
      install_requires=['xvfbwrapper'])
EOF

cat << 'EOF' > test.py
print("Module test is working and installed")
EOF

python setup.py install
python -mtest # Should output "print("Module test is working and installed")"

Instead easy_install prints error:

Best match: xvfbwrapper 0.2.9
Processing xvfbwrapper-0.2.9.tar.gz
Writing /tmp/easy_install-yl6fus8n/xvfbwrapper-0.2.9/setup.cfg
Running xvfbwrapper-0.2.9/setup.py -q bdist_egg --dist-dir /tmp/easy_install-yl6fus8n/xvfbwrapper-0.2.9/egg-dist-tmp-ih2vd38w
zip_safe flag not set; analyzing archive contents...
No eggs found in /tmp/easy_install-yl6fus8n/xvfbwrapper-0.2.9/egg-dist-tmp-ih2vd38w (setup script problem?)

API change breaking OpenStack Horizon integration tests

Hi,

Good news: your project is used in integration tests of OpenStack Horizon!

Bad news: you broke your API without any warning, nor bumping the major version :-/ (no semantic version? ;-))

I'm talking about the change 9a8c0e8 which renamed xvfb_cmd to extra_xvfb_args.

Horizon bug report: https://bugs.launchpad.net/horizon/+bug/1540495

One fix (which doesn't look to work?): https://review.openstack.org/274812

My fix: https://review.openstack.org/275401

Failure when DISPLAY is empty

This is possibly related to #27.

If DISPLAY is an empty string (rather than being unset), xvfbwrapper fails with the following exception:

Traceback (most recent call last):
  File "<string>", line 11, in <module>
  File "/usr/lib/python3/dist-packages/xvfbwrapper.py", line 50, in __init__
    self.orig_display = os.environ['DISPLAY'].split(':')[1]
IndexError: list index out of range

r: Fatal IO error: client killed

Any idea what could be causing this? Is it xvfbwrapper or qt/webkit's problem?

As a workaround, what would be the consequences xvfb.stop() is not called? Will the buffer hang around until the process that created it terminates? Or will it live beyond that?

import fcntl - Issue

File "C:\Users\xxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\xvfbwrapper.py", line 15, in
import fcntl

Using windows 11, and cant import.

New release

The last release on PyPI is a bit dated and does not include the file locking for getting unique displays.

Let me know if there is anything I can do to help!

xvfbwrapper.py:57 cygwin/win32 compatibility

I recommend on line 57 setting the keyword argument close_fds=False as the fourth positional argument in the function call to self.proc = subprocess.Popen() checking and/or if: block handling to maintain correct/better compatibility to the win32 OS with cygwin\bin version of Xvfb that is installed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.