xflr6 / graphviz

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

PermissionError when using graphviz.version() #175

Closed ThinkNaive closed 2 years ago

ThinkNaive commented 2 years ago

I tried to use APIs such as graphviz.version() or g.render() but encoutered errors PermissionError: [Errno 13] Permission denied: PosixPath('dot') like

In [1]: import graphviz

In [2]: graphviz.version(
   ...: )
---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
Input In [2], in <cell line: 1>()
----> 1 graphviz.version(
      2 )

File ~/anaconda3/lib/python3.9/site-packages/graphviz/backend/upstream_version.py:54, in version()
     30 """Return the upstream version number tuple from ``stderr`` of ``dot -V``.
     31 
     32 Returns:
   (...)
     51     https://gitlab.com/graphviz/graphviz/-/blob/f94e91ba819cef51a4b9dcb2d76153684d06a913/gen_version.py#L17-20
     52 """
     53 cmd = [dot_command.DOT_BINARY, '-V']
---> 54 proc = execute.run_check(cmd,
     55                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
     56                          encoding='ascii')
     58 ma = VERSION_PATTERN.search(proc.stdout)
     59 if ma is None:

File ~/anaconda3/lib/python3.9/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79         proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80     else:
---> 81         proc = subprocess.run(cmd, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:

File ~/anaconda3/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    502     kwargs['stdout'] = PIPE
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:
    507         stdout, stderr = process.communicate(input, timeout=timeout)

File ~/anaconda3/lib/python3.9/subprocess.py:951, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask)
    947         if self.text_mode:
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.
    962     for f in filter(None, (self.stdin, self.stdout, self.stderr)):

File ~/anaconda3/lib/python3.9/subprocess.py:1821, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1819     if errno_num != 0:
   1820         err_msg = os.strerror(errno_num)
-> 1821     raise child_exception_type(errno_num, err_msg, err_filename)
   1822 raise child_exception_type(err_msg)

PermissionError: [Errno 13] Permission denied: PosixPath('dot')

and like

In [3]: import graphviz

In [4]: dot = graphviz.Digraph(comment='The Round Table')

In [5]: dot.node('A', 'King Arthur')

In [6]: dot.node('B', 'Sir Bedevere the Wise')

In [7]: dot.node('L', 'Sir Lancelot the Brave')

In [8]: dot.edges(['AB', 'AL'])

In [9]: dot.edge('B', 'L', constraint='false')

In [10]: dot.render()
---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
Input In [10], in <cell line: 1>()
----> 1 dot.render()

File ~/anaconda3/lib/python3.9/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/lib/python3.9/site-packages/graphviz/rendering.py:122, in Render.render(self, filename, directory, view, cleanup, format, renderer, formatter, neato_no_op, quiet, quiet_view, outfile, engine, raise_if_result_exists, overwrite_source)
    118 filepath = self.save(filename, directory=directory, skip_existing=None)
    120 args.append(filepath)
--> 122 rendered = self._render(*args, **kwargs)
    124 if cleanup:
    125     log.debug('delete %r', filepath)

File ~/anaconda3/lib/python3.9/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/lib/python3.9/site-packages/graphviz/backend/rendering.py:324, in render(engine, format, filepath, renderer, formatter, neato_no_op, quiet, outfile, raise_if_result_exists, overwrite_filepath)
    320     raise exceptions.FileExistsError(f'output file exists: {os.fspath(outfile)!r}')
    322 cmd += args
--> 324 execute.run_check(cmd,
    325                   cwd=filepath.parent if filepath.parent.parts else None,
    326                   quiet=quiet,
    327                   capture_output=True)
    329 return os.fspath(outfile)

File ~/anaconda3/lib/python3.9/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     79         proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80     else:
---> 81         proc = subprocess.run(cmd, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:

File ~/anaconda3/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    502     kwargs['stdout'] = PIPE
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:
    507         stdout, stderr = process.communicate(input, timeout=timeout)

File ~/anaconda3/lib/python3.9/subprocess.py:951, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask)
    947         if self.text_mode:
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.
    962     for f in filter(None, (self.stdin, self.stdout, self.stderr)):

File ~/anaconda3/lib/python3.9/subprocess.py:1821, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1819     if errno_num != 0:
   1820         err_msg = os.strerror(errno_num)
-> 1821     raise child_exception_type(errno_num, err_msg, err_filename)
   1822 raise child_exception_type(err_msg)

PermissionError: [Errno 13] Permission denied: PosixPath('dot')

My environment is Anaconda Python 3.9.12 in Windows 10 WSL2 Ubuntu 20.04. However, I can run the code above on Ubuntu real machine.

ThinkNaive commented 2 years ago

sorry I didn't install the Graphviz dependency.

xflr6 commented 2 years ago

No worries; can we close the issue then?

I am curious why you got a PermissionError instead of an OSError, any idea?

ThinkNaive commented 2 years ago

Sorry, I have no idea about the error. Maybe it is attributed to WSL implementation.

ThinkNaive commented 2 years ago

No worries; can we close the issue then?

I am curious why you got a PermissionError instead of an OSError, any idea?

I test with a minimum example on Ubuntu WSL2 with the code:

from subprocess import run
from pathlib import PosixPath
run([PosixPath("dot")])

and the error message is as follows:

Traceback (most recent call last):
  File "/mnt/f/OSNotes/test.py", line 4, in <module>
    run([PosixPath("dot")])
  File "/usr/lib/python3.8/subprocess.py", line 493, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.8/subprocess.py", line 858, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.8/subprocess.py", line 1704, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
PermissionError: [Errno 13] Permission denied: PosixPath('dot')

I also test this:

from subprocess import run
run(["what?"])

and get same error.

xflr6 commented 2 years ago

Thanks, let me look into that.