File: client.py

package info (click to toggle)
python-etelemetry 0.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 224 kB
  • sloc: python: 1,731; makefile: 8; sh: 8
file content (131 lines) | stat: -rw-r--r-- 4,131 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import os
from packaging.version import Version

try:
    import ci_info
except ImportError:
    import warnings
    warnings.warn(
        "Deprecated version of ci-info found, upgrade to remove this warning", DeprecationWarning
    )
    import ci as ci_info

from .config import ET_PROJECTS

_available_version_checked = None


class BadVersionError(RuntimeError):
    """Local version is known to contain a critical bug etc."""
    pass


def _etrequest(endpoint, method="get", **kwargs):
    # Delay requests import until actually used to at least not
    # add runtime penalty of requests import whenever not needed
    from requests import request, ConnectionError, ReadTimeout
    if kwargs.get('timeout') is None:
        kwargs['timeout'] = 5

    params = {}
    if ci_info.is_ci():
        # send along CI information
        params = ci_info.info()

    try:
        res = request(method, endpoint, params=params, **kwargs)
    except ConnectionError:
        raise RuntimeError("Connection to server could not be made")
    except ReadTimeout:
        raise RuntimeError(
            "No response from server in {timeout} seconds".format(
                timeout=kwargs.get('timeout')
            )
        )
    res.raise_for_status()
    return res


def get_project(repo, **rargs):
    """
    Fetch latest version from server.

    Parameters
    ==========
    repo : str
        GitHub repository as <owner>/<project>
    **rargs
        Request keyword arguments

    Returns
    =======
    response
        Dictionary with `version` field
    """
    if "NO_ET" in os.environ:
        return None
    if "/" not in repo:
        raise ValueError("Invalid repository")
    res = _etrequest(ET_PROJECTS.format(repo=repo), **rargs)
    return res.json()


def check_available_version(project, version, lgr=None, raise_exception=False):
    """A helper to check (and report) if newer version of project is available
    Should be ok to execute multiple times, it will be checked only one time

    Parameters
    ----------
    project: str
      as on GitHub (e.g., sensein/etelemetry-client. Releases will be checked
    version: str
      local version of project
    lgr: python logger object
      external logger to be used
    raise_exception: bool
      raise a BadVersionError exception if a bad local version is detected
    """
    global _available_version_checked
    if _available_version_checked is not None:
        return _available_version_checked

    if lgr is None:
        import logging
        lgr = logging.getLogger('et-client')

    latest = {"version": "Unknown", "bad_versions": []}
    ret = None
    try:
        ret = get_project(project)
    except Exception as e:
        lgr.debug("Could not check %s for version updates: %s", project, e)
        return None
    finally:
        if ret:
            latest.update(**ret)
            local_version = Version(version)
            remote_version = Version(latest["version"])
            if local_version < remote_version:
                lgr.warning("A newer version (%s) of %s is available. You are "
                            "using %s", latest["version"], project, version)
            elif remote_version < local_version:
                lgr.debug(
                    "Running a newer version (%s) of %s than available (%s)",
                    version, project, latest["version"])
            else:  # ==
                lgr.debug("No newer (than %s) version of %s found available",
                          version, project)
            if latest["bad_versions"] and any(
                    [
                        local_version == Version(ver)
                        for ver in latest["bad_versions"]
                    ]
            ):
                message = ("You are using a version of {0} with a critical bug. "
                          "Please use a different version.").format(project)
                if raise_exception:
                    raise BadVersionError(message)
                else:
                    lgr.critical(message)
            _available_version_checked = latest
    return latest