Base class for a context manager which allows changing of time zones. Subclasses may define a guard variable to either block or or allow time zone changes by redefining ``_guard_var_name`` and ``_guard_allows_change``. The default is that the guard variable must be affirmatively se
| 47 | |
| 48 | |
| 49 | class TZContextBase(object): |
| 50 | """ |
| 51 | Base class for a context manager which allows changing of time zones. |
| 52 | |
| 53 | Subclasses may define a guard variable to either block or or allow time |
| 54 | zone changes by redefining ``_guard_var_name`` and ``_guard_allows_change``. |
| 55 | The default is that the guard variable must be affirmatively set. |
| 56 | |
| 57 | Subclasses must define ``get_current_tz`` and ``set_current_tz``. |
| 58 | """ |
| 59 | _guard_var_name = "DATEUTIL_MAY_CHANGE_TZ" |
| 60 | _guard_allows_change = True |
| 61 | |
| 62 | def __init__(self, tzval): |
| 63 | self.tzval = tzval |
| 64 | self._old_tz = None |
| 65 | |
| 66 | @classmethod |
| 67 | def tz_change_allowed(cls): |
| 68 | """ |
| 69 | Class method used to query whether or not this class allows time zone |
| 70 | changes. |
| 71 | """ |
| 72 | guard = bool(os.environ.get(cls._guard_var_name, False)) |
| 73 | |
| 74 | # _guard_allows_change gives the "default" behavior - if True, the |
| 75 | # guard is overcoming a block. If false, the guard is causing a block. |
| 76 | # Whether tz_change is allowed is therefore the XNOR of the two. |
| 77 | return guard == cls._guard_allows_change |
| 78 | |
| 79 | @classmethod |
| 80 | def tz_change_disallowed_message(cls): |
| 81 | """ Generate instructions on how to allow tz changes """ |
| 82 | msg = ('Changing time zone not allowed. Set {envar} to {gval} ' |
| 83 | 'if you would like to allow this behavior') |
| 84 | |
| 85 | return msg.format(envar=cls._guard_var_name, |
| 86 | gval=cls._guard_allows_change) |
| 87 | |
| 88 | def __enter__(self): |
| 89 | if not self.tz_change_allowed(): |
| 90 | msg = self.tz_change_disallowed_message() |
| 91 | pytest.skip(msg) |
| 92 | |
| 93 | # If this is used outside of a test suite, we still want an error. |
| 94 | raise ValueError(msg) # pragma: no cover |
| 95 | |
| 96 | self._old_tz = self.get_current_tz() |
| 97 | self.set_current_tz(self.tzval) |
| 98 | |
| 99 | def __exit__(self, type, value, traceback): |
| 100 | if self._old_tz is not None: |
| 101 | self.set_current_tz(self._old_tz) |
| 102 | |
| 103 | self._old_tz = None |
| 104 | |
| 105 | def get_current_tz(self): |
| 106 | raise NotImplementedError |
nothing calls this directly
no outgoing calls
no test coverage detected