Coverage for flogin/errors.py: 84%
31 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
1from __future__ import annotations
3TYPE_CHECKING = False
4if TYPE_CHECKING:
5 from subprocess import (
6 CalledProcessError, # https://github.com/astral-sh/ruff/issues/15681
7 )
9 import requests # https://github.com/astral-sh/ruff/issues/15681
11__all__ = (
12 "EnvNotSet",
13 "PipException",
14 "PipExecutionError",
15 "PluginException",
16 "PluginNotInitialized",
17 "UnableToDownloadPip",
18)
21class PluginException(Exception):
22 r"""A class that represents exceptions with your plugin"""
25class PluginNotInitialized(PluginException):
26 r"""This is raised when you try to access something that needs data from the initialize method, and it hasn't been called yet."""
28 def __init__(self) -> None:
29 super().__init__("The plugin hasn't been initialized yet")
32class EnvNotSet(PluginException):
33 """This is raised when an environment variable that flow automatically sets is not set and can not be retrieved. This should only get raised when your plugin gets run, but not by flow.
35 .. versionadded: 1.1.0
37 Attributes
38 -----------
39 name: :class:`str`
40 The name of the environment variable that was not found
41 alternative: Optional[:class:`str`]
42 Optionally, the name of the keyword argument in the :class:`~flogin.testing.plugin_tester.PluginTester` constructor that will set the variable for you.
43 """
45 def __init__(self, name: str, alternative: str | None = None) -> None:
46 self.name = name
47 self.alternative = alternative
48 alt = (
49 f"If you ran your plugin via the plugin tester, you can use the {alternative!r} keyword argument to quickly set this."
50 if alternative
51 else ""
52 )
53 super().__init__(
54 f"The {name!r} environment variable is not set. These should be set by flow when it runs your plugin. {alt}"
55 )
58class PipException(Exception):
59 r"""This is a base class to represent errors derived from the :class:`~flogin.pip.Pip` object.
61 .. versionadded:: 2.0.0
62 """
65class UnableToDownloadPip(PipException):
66 r"""This is an exception which is used to indicate that an error occurred while attempting to download pip.
68 .. versionadded:: 2.0.0
70 Attributes
71 ----------
72 error: :class:`requests.exceptions.HTTPError` | :class:`requests.Timeout` | :class:`requests.ConnectionError`
73 The error that was raised by the :doc:`req:index` module.
74 """
76 def __init__(self, err: requests.RequestException) -> None:
77 super().__init__(err)
78 self.error = err
81class PipExecutionError(PipException):
82 r"""This is an exception which is raised whenever :meth:`flogin.pip.Pip.run` gets a return code that isn't ``0``.
84 .. versionadded:: 2.0.0
86 Attributes
87 ----------
88 error: :class:`subprocess.CalledProcessError`
89 The original error that was raised by subprocess
90 """
92 def __init__(self, err: CalledProcessError) -> None:
93 super().__init__(
94 f"An error occurred while attempting to use pip: {err.stderr.decode()}"
95 )
96 self.error = err
98 @property
99 def output(self) -> str:
100 """:class:`str` The output from :attr:`subprocess.CalledProcessError.output`"""
101 return self.error.output.decode()
103 @property
104 def returncode(self) -> int:
105 """:class:`int` The returncode from :attr:`subprocess.CalledProcessError.returncode`"""
106 return self.error.returncode
108 @property
109 def stderr(self) -> str:
110 """:class:`str` The stderr from :attr:`subprocess.CalledProcessError.stderr`"""
111 return self.error.stderr.decode()