xflr6 / graphviz

Simple Python interface for Graphviz
https://graphviz.readthedocs.io
MIT License
1.59k stars 209 forks source link

Testing fails under tox with 'Fontconfig error: No writable cache directories' #184

Closed mtelka closed 1 year ago

mtelka commented 1 year ago

I'm trying to package graphviz version 0.20.1 for OpenIndiana but some tests are failing. Here is an example of failure (all tests fails with the same error):

______________________ test_render[dot-pdf-None-None-pdf] ______________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fffa964c600>
tmp_path = PosixPath('/tmp/pytest-of-marcel/pytest-16/test_render_dot_pdf_None_None_0')
engine = 'dot', format_ = 'pdf', renderer = None, formatter = None
expected_suffix = 'pdf', filename = 'hello.gv'
data = b'digraph { hello -> world }'

    @pytest.mark.exe
    @pytest.mark.parametrize(
        'format_, renderer, formatter, expected_suffix',
        [('pdf', None, None, 'pdf'),
         ('plain', 'dot', 'core', 'core.dot.plain')])
    @pytest.mark.parametrize('engine', ['dot'])
    def test_render(capsys, tmp_path, engine, format_, renderer, formatter,
                    expected_suffix, filename='hello.gv',
                    data=b'digraph { hello -> world }'):
        lpath = tmp_path / filename
        assert lpath.write_bytes(data) == len(data) == lpath.stat().st_size
        rendered = lpath.with_suffix(f'{lpath.suffix}.{expected_suffix}')

        with pytest.deprecated_call():
            result = graphviz.render(engine, format_, str(lpath),
                                     renderer, formatter)

        assert result == str(rendered)

        assert rendered.stat().st_size
>       assert capsys.readouterr() == ('', '')
E       AssertionError: assert CaptureResult...irectories\n') == ('', '')
E         Full diff:
E         - ('', '')
E         + CaptureResult(out='', err='Fontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig error: No writable cache directories\nFontconfig...
E         
E         ...Full output truncated (1 line hidden), use '-vv' to show

tests/backend/test_rendering.py:63: AssertionError
------------------------------ Captured log call -------------------------------
DEBUG    graphviz.backend.execute:execute.py:61 run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'hello.gv']

Here is the complete list of failed tests:

=========================== short test summary info ============================
FAILED tests/backend/test_rendering.py::test_render_img - AssertionError: ass...
FAILED tests/backend/test_rendering.py::test_render[dot-plain-dot-core-core.dot.plain]
FAILED tests/backend/test_rendering.py::test_render[dot-pdf-None-None-pdf] - ...
FAILED tests/backend/test_rendering.py::test_render_outfile_differnt_parent
FAILED tests/test_graphs.py::test_subgraph_render[Graph-...] - AssertionError...
FAILED tests/test_graphs.py::test_subgraph_render[Digraph-...] - AssertionErr...
FAILED tests/backend/test_piping.py::test_pipe[dot-ps-ps-core-%!PS-] - Assert...
FAILED tests/backend/test_piping.py::test_pipe[dot-svg-None-None-(?s)^<\\?xml .+</svg>\\s*$]
FAILED tests/backend/test_piping.py::test_pipe[sfdp-svg-None-None-(?s)^<\\?xml .+</svg>\\s*$]

I'm running tests as non-root user. Any idea what is wrong here?

Thank you.

xflr6 commented 1 year ago

This looks like an upstream issue (in https://www.graphviz.org and/or how fontconfig is build/configured in your environment).

I think you can check if it's unrelated to this Python wrapper by rendering a graph with dot directly, e.g.:

$ echo "digraph { hello -> world }" | dot -T pdf -o /tmp/hello.pdf

There is some upstream advice on fonts here: https://graphviz.org/faq/font/ (not sure if that helps).

In case you do get the same error when using dot directly, you might want to seek help upstream: https://gitlab.com/graphviz/graphviz/-/issues

mtelka commented 1 year ago

I tried the command and it passed without any warning:

$ echo "digraph { hello -> world }" | dot -T pdf -o /tmp/hello.pdf
$ ls -l /tmp/hello.pdf
-rw-r--r-- 1 marcel staff 5598 Nov 23 21:29 /tmp/hello.pdf
$
xflr6 commented 1 year ago

Interesting. Let's make it more similar to the test case (as non-root user):

$ cd /tmp
$ echo "digraph { hello -> world }" > hello.gv
$ dot -Kdot -Tpdf -O hello.gv

In the failed test, the output file is created successfully.

The assertion that fails is that stderr should be empty, so we would expect to see the same message (a warning).

mtelka commented 1 year ago

Still no warning:

$ echo "digraph { hello -> world }" > hello.gv
$ dot -Kdot -Tpdf -O hello.gv
$ ls -l hello.gv*
-rw-r--r-- 1 marcel staff   27 Nov 23 21:43 hello.gv
-rw-r--r-- 1 marcel staff 5598 Nov 23 21:43 hello.gv.pdf
$
mtelka commented 1 year ago

BTW, we run tests like this:

tox --current-env --no-provision --recreate -e py39

While the --current-env option is provided by the tox-current-env plugin. The exactly same set of nine tests fails on both Python 3.7 and Python 3.9. We support only these two Python versions, so I do not know how it behave with newer Python.

Thank you.

xflr6 commented 1 year ago

We could check if the shell environment is relevant somehow:

$ python3 -c "import subprocess; subprocess.run(['dot',  '-Kdot', '-Tpdf', '-O', 'hello.gv'], check=True)"
$ python3 -c "import subprocess; subprocess.run(['dot',  '-Kdot', '-Tpdf', '-O', 'hello.gv'], check=True, cwd='/tmp')"

--current-env option

Might be worth checking this has an influence. Can you maybe try the methods from https://graphviz.readthedocs.io/en/stable/development.html#tests (the first one might require https://graphviz.readthedocs.io/en/stable/development.html#local-installation first):

$ ./run-tests.py
$ python3 -m tox
mtelka commented 1 year ago

We could check if the shell environment is relevant somehow:

$ python3 -c "import subprocess; subprocess.run(['dot',  '-Kdot', '-Tpdf', '-O', 'hello.gv'], check=True)"
$ python3 -c "import subprocess; subprocess.run(['dot',  '-Kdot', '-Tpdf', '-O', 'hello.gv'], check=True, cwd='/tmp')"

Both above behave as expected, i.e. when run with hello.gv they pass, without hello.gv they fail. The second one pass only in /tmp.

--current-env option

I tried to run our usual tests the exactly same way as before, just without --current-env => nine tests failed.

Might be worth checking this has an influence. Can you maybe try the methods from https://graphviz.readthedocs.io/en/stable/development.html#tests (the first one might require https://graphviz.readthedocs.io/en/stable/development.html#local-installation first):

$ ./run-tests.py

When run like this all tests passed. But, before I had a chance to run ./run-tests.py I had to convert line ends from DOS format to UNIX format and chmod +x it (I think you should fix both issues).

$ python3 -m tox

I ran it using python3.9 -m tox -e py39 (with the tox-current-env plugin uninstalled) and again, nine tests failed. So it looks like tox is the culprit. We use tox version 3.27.1.

xflr6 commented 1 year ago

Thanks for the updates.

But, before I had a chance to run ./run-tests.py I had to convert line ends from DOS format to UNIX format and chmod +x it (I think you should fix both issues).

I use autocrlf on this git repository and run-tests.py has the executeable bit, so IIUC this is with an extracted source distribution (not with a repository checkout). Just checked: because there is no executeable bit on Windows, we actually run the tests as python run-tests on the CI (to avoid platform-specific commands): https://github.com/xflr6/graphviz/blob/bf1023be2824536d198b40a845ec0ed585f53497/.github/workflows/build.yaml#L107

So I think the fix is to update the command(s) in https://graphviz.readthedocs.io/en/stable/development.html#tests that depend on the executeable bit accordingly.

I ran the tests with tox and could not reproduce yet, to be continued :)

mtelka commented 1 year ago

But, before I had a chance to run ./run-tests.py I had to convert line ends from DOS format to UNIX format and chmod +x it (I think you should fix both issues).

I use autocrlf on this git repository and run-tests.py has the executeable bit, so IIUC this is with an extracted source distribution (not with a repository checkout).

Yes, exactly, sdist from PyPI.

So I think the fix is to update the command(s) in https://graphviz.readthedocs.io/en/stable/development.html#tests that depend on the executeable bit accordingly.

Hmm, okay. But if you do that then you should remove the shebang from run-tests.py so there is no impression the file is intended to be runable.

xflr6 commented 1 year ago

But if you do that then you should remove the shebang

I don't think so: These files are indeed scripts, have the executeable bit, and are runable in the normal case (repo checkout). Having them highlighted in the shell as executable is useful. The sdist thing stems from ZIP-format.

mtelka commented 1 year ago

I tried to run tests again today and now all of them pass. No sure what exactly changed, but some X libraries got updated recently so maybe there was some bug fixed somewhere.

Thank you.

xflr6 commented 1 year ago

Great, thanks for updating.