]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/__init__.py
Add configuration info for RTD config file
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / __init__.py
1 # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 """
5 `adafruit_blinka` - Runtime utility objects for re-implementation of CircuitPython API
6 ======================================================================================
7
8 * Author(s): cefn
9 """
10
11 import os
12
13
14 class Enum:
15     """
16     Object supporting CircuitPython-style of static symbols
17     as seen with Direction.OUTPUT, Pull.UP
18     """
19
20     def __repr__(self):
21         """
22         Assumes instance will be found as attribute of own class.
23         Returns dot-subscripted path to instance
24         (assuming absolute import of containing package)
25         """
26         cls = type(self)
27         for key in dir(cls):
28             if getattr(cls, key) is self:
29                 return "{}.{}.{}".format(cls.__module__, cls.__qualname__, key)
30         return repr(self)
31
32     @classmethod
33     def iteritems(cls):
34         """
35         Inspects attributes of the class for instances of the class
36         and returns as key,value pairs mirroring dict#iteritems
37         """
38         for key in dir(cls):
39             val = getattr(cls, key)
40             if isinstance(cls, val):
41                 yield (key, val)
42
43
44 class ContextManaged:
45     """An object that automatically deinitializes hardware with a context manager."""
46
47     def __enter__(self):
48         return self
49
50     def __exit__(self, exc_type, exc_value, traceback):
51         self.deinit()
52
53     # pylint: disable=no-self-use
54     def deinit(self):
55         """Free any hardware used by the object."""
56         return
57
58     # pylint: enable=no-self-use
59
60
61 class Lockable(ContextManaged):
62     """An object that must be locked to prevent collisions on a microcontroller resource."""
63
64     _locked = False
65
66     def try_lock(self):
67         """Attempt to grab the lock. Return True on success, False if the lock is already taken."""
68         if self._locked:
69             return False
70         self._locked = True
71         return True
72
73     def unlock(self):
74         """Release the lock so others may use the resource."""
75         if self._locked:
76             self._locked = False
77
78
79 def load_settings_toml():
80     """Load values from settings.toml into os.environ, so that os.getenv returns them.
81     Note: This does not work in MicroPython because of the tomllib module not being available.
82     """
83     try:
84         import tomllib
85     except ImportError:
86         import toml as tomllib
87
88     if not os.path.isfile("settings.toml"):
89         raise FileNotFoundError("settings.toml not found in current directory.")
90
91     print("settings.toml found. Updating environment variables:")
92     with open("settings.toml", "rb") as toml_file:
93         try:
94             settings = tomllib.load(toml_file)
95         except tomllib.TOMLDecodeError as e:
96             raise tomllib.TOMLDecodeError("Error with settings.toml file.") from e
97
98     invalid_types = set()
99     for key, value in settings.items():
100         if not isinstance(value, (bool, int, float, str)):
101             invalid_types.add(type(value).__name__)
102     if invalid_types:
103         invalid_types_string = ", ".join(invalid_types)
104         raise ValueError(
105             f"The types: '{invalid_types_string}' are not supported in settings.toml."
106         )
107
108     for key, value in settings.items():
109         key = str(key)
110         if key in os.environ:
111             print(f" - {key} already exists in environment")
112             continue
113         os.environ[key] = str(value)
114         print(f" - {key} added")
115
116     return settings
117
118
119 def patch_system():
120     """Patch modules that may be different due to the platform."""
121     # pylint: disable=import-outside-toplevel
122     import sys
123     from adafruit_blinka.agnostic import time
124
125     # pylint: enable=import-outside-toplevel
126
127     sys.modules["time"] = time