File: future.py

package info (click to toggle)
waagent 2.15.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,820 kB
  • sloc: python: 60,164; xml: 4,126; sh: 1,354; makefile: 22
file content (208 lines) | stat: -rw-r--r-- 7,432 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import contextlib
import datetime
import platform
import sys
import os
import re

# Note broken dependency handling to avoid potential backward
# compatibility issues on different distributions
try:
    import distro  # pylint: disable=E0401
except Exception:
    pass

# pylint: disable=W0105
"""
Add alias for python2 and python3 libs and functions.
""" 
# pylint: enable=W0105

if sys.version_info[0] == 3:
    import http.client as httpclient  # pylint: disable=W0611,import-error
    from urllib.parse import urlparse  # pylint: disable=W0611,import-error,no-name-in-module

    """Rename Python3 str to ustr"""  # pylint: disable=W0105
    ustr = str

    bytebuffer = memoryview

    # We aren't using these imports in this file, but we want them to be available
    # to import from this module in others.
    # Additionally, python2 doesn't have this, so we need to disable import-error
    # as well.

    # unused-import<W0611>, import-error<E0401> Disabled: Due to backward compatibility between py2 and py3
    from builtins import int, range  # pylint: disable=unused-import,import-error
    from collections import OrderedDict  # pylint: disable=W0611
    from queue import Queue, Empty  # pylint: disable=W0611,import-error

    # unused-import<W0611> Disabled: python2.7 doesn't have subprocess.DEVNULL
    # so this import is only used by python3.
    import subprocess   # pylint: disable=unused-import

elif sys.version_info[0] == 2:
    import httplib as httpclient  # pylint: disable=E0401,W0611
    from urlparse import urlparse  # pylint: disable=E0401
    from Queue import Queue, Empty  # pylint: disable=W0611,import-error

    
    # We want to suppress the following:
    #   -   undefined-variable<E0602>: 
    #           These builtins are not defined in python3
    #   -   redefined-builtin<W0622>:
    #           This is intentional, so that code that wants to use builtins we're
    #           assigning new names to doesn't need to check python versions before
    #           doing so.

    # pylint: disable=undefined-variable,redefined-builtin

    ustr = unicode # Rename Python2 unicode to ustr 
    bytebuffer = buffer
    range = xrange
    int = long

    if sys.version_info[1] >= 7:
        from collections import OrderedDict  # For Py 2.7+
    else:
        from ordereddict import OrderedDict  # Works only on 2.6  # pylint: disable=E0401
else:
    raise ImportError("Unknown python version: {0}".format(sys.version_info))


#
# datetime.utcnow triggers a DeprecationWarning on 3.12 and will be removed in a future version.
#
# To work around this, we use timezone.utc on 3.5-3.10 (it was introduced on 3.2, but currently we test from 3.5), and
# datetime.UTC (introduced on Python 3.11) for >= 3.11.
#
if sys.version_info[0] > 3 or sys.version_info[0] == 3 and sys.version_info[1] >= 11:
    # E1101: Module 'datetime' has no 'UTC' member (no-member)
    UTC = datetime.UTC  # pylint: disable=E1101
elif sys.version_info[0] == 3 and sys.version_info[1] >= 5:
    UTC = datetime.timezone.utc
else:
    from datetime import tzinfo, timedelta

    class _UTC(tzinfo):
        def utcoffset(self, dt):
            return timedelta(0)
        def tzname(self, dt):
            return "UTC"
        def dst(self, dt):
            return timedelta(0)

    UTC = _UTC()

datetime_max_utc = datetime.datetime.max.replace(tzinfo=UTC)
datetime_min_utc = datetime.datetime.min.replace(tzinfo=UTC)

def get_linux_distribution(get_full_name, supported_dists):
    """Abstract platform.linux_distribution() call which is deprecated as of
       Python 3.5 and removed in Python 3.7"""
    try:
        supported = platform._supported_dists + (supported_dists,)
        osinfo = list(
            platform.linux_distribution(  # pylint: disable=W1505
                full_distribution_name=get_full_name,
                supported_dists=supported
            )
        )

        # The platform.linux_distribution() lib has issue with detecting OpenWRT linux distribution.
        # Merge the following patch provided by OpenWRT as a temporary fix.
        if os.path.exists("/etc/openwrt_release"):
            osinfo = get_openwrt_platform()

        if not osinfo or osinfo == ['', '', '']:
            return get_linux_distribution_from_distro(get_full_name)
        full_name = platform.linux_distribution()[0].strip()  # pylint: disable=W1505
        osinfo.append(full_name)
    except AttributeError:
        return get_linux_distribution_from_distro(get_full_name)

    return osinfo


def get_linux_distribution_from_distro(get_full_name):
    """Get the distribution information from the distro Python module."""
    # If we get here we have to have the distro module, thus we do
    # not wrap the call in a try-except block as it would mask the problem
    # and result in a broken agent installation
    osinfo = list(
        distro.linux_distribution(
            full_distribution_name=get_full_name
        )
    )
    full_name = distro.linux_distribution()[0].strip()
    osinfo.append(full_name)

    # Fixing is the problem https://github.com/Azure/WALinuxAgent/issues/2715. Distro.linux_distribution method not retuning full version
    # If best is true, the most precise version number out of all examined sources is returned.
    if "mariner" in osinfo[0].lower():
        osinfo[1] = distro.version(best=True)

    return osinfo


def get_openwrt_platform():
    """
    Add this workaround for detecting OpenWRT products because
    the version and product information is contained in the /etc/openwrt_release file.
    """
    result = [None, None, None]
    openwrt_version = re.compile(r"^DISTRIB_RELEASE=['\"](\d+\.\d+.\d+)['\"]")
    openwrt_product = re.compile(r"^DISTRIB_ID=['\"]([\w-]+)['\"]")

    with open('/etc/openwrt_release', 'r') as fh:
        content = fh.readlines()
        for line in content:
            version_matches = openwrt_version.match(line)
            product_matches = openwrt_product.match(line)
            if version_matches:
                result[1] = version_matches.group(1)
            elif product_matches:
                if product_matches.group(1) == "OpenWrt":
                    result[0] = "openwrt"
    return result

def is_file_not_found_error(exception):
    
    # pylint for python2 complains, but FileNotFoundError is
    # defined for python3.
    
    # pylint: disable=undefined-variable

    if sys.version_info[0] == 2:
        # Python 2 uses OSError(errno=2)
        return isinstance(exception, OSError) and exception.errno == 2
    elif sys.version_info[0] == 3:
        return isinstance(exception, FileNotFoundError)
    
    return isinstance(exception, FileNotFoundError)

@contextlib.contextmanager
def subprocess_dev_null():

    if sys.version_info[0] == 3:
        # Suppress no-member errors on python2.7
        yield subprocess.DEVNULL # pylint: disable=no-member
    else:
        try:
            devnull = open(os.devnull, "a+")
            yield devnull
        except Exception:
            yield None
        finally:
            if devnull is not None:
                devnull.close()

def array_to_bytes(buff):
    # Python 3.9 removed the tostring() method on arrays, the new alias is tobytes()
    if sys.version_info[0] == 2:
        return buff.tostring()

    if sys.version_info[0] == 3 and sys.version_info[1] <= 8:
        return buff.tostring()

    return buff.tobytes()