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 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
|
"""
Bag of settings values
"""
# pylint: disable = invalid-name
import importlib
import os
import pathlib
from collections.abc import Generator, Iterable
from pprint import pformat
from types import ModuleType as Module
from typing import Any, Optional, Union
from moderngl_window.conf import default
from moderngl_window.exceptions import ImproperlyConfigured
SETTINGS_ENV_VAR = "MODERNGL_WINDOW_SETTINGS_MODULE"
class Settings:
"""
Bag of settings values. New attributes can be freely added runtime.
Various apply* methods are supplied so the user have full control over how
settings values are initialized. This is especially useful for more custom usage.
And instance of the `Settings` class is created when the `conf` module is imported.
Attribute names must currently be in upper case to be recognized.
Some examples of usage::
from moderngl_window.conf import settings
# Mandatory settings values
try:
value = settings.VALUE
except KeyError:
raise ValueError("This settings value is required")
# Fallback in code
value = getattr(settings, 'VALUE', 'default_value')
# Pretty printed string representation for easy inspection
print(settings)
"""
WINDOW: dict[str, Any] = dict()
"""
Window/screen properties. Most importantly the ``class`` attribute
decides what class should be used to handle the window.
.. code:: python
# Default values
WINDOW = {
"gl_version": (3, 3),
"class": "moderngl_window.context.pyglet.Window",
"size": (1280, 720),
"aspect_ratio": 16 / 9,
"fullscreen": False,
"resizable": True,
"title": "ModernGL Window",
"vsync": True,
"cursor": True,
"samples": 0,
}
Other Properties:
- ``gl_version``: The minimum required major/minor OpenGL version
- ``size``: The window size to open.
- ``aspect_ratio`` is the enforced aspect ratio of the viewport.
- ``fullscreen``: True if you want to create a context in fullscreen mode
- ``resizable``: If the window should be resizable. This only applies in
windowed mode.
- ``vsync``: Only render one frame per screen refresh
- ``title``: The visible title on the window in windowed mode
- ``cursor``: Should the mouse cursor be visible on the screen? Disabling
this is also useful in windowed mode when controlling the camera on some
platforms as moving the mouse outside the window can cause issues.
- ``Samples``: Number if samples used in multisampling. Values above 1
enables multisampling.
The created window frame buffer will by default use:
- RGBA8 (32 bit per pixel)
- 24 bit depth buffer
- Double buffering
- color and depth buffer is cleared for every frame
"""
SCREENSHOT_PATH: Optional[str] = None
"""
Absolute path to the directory screenshots will be saved by the screenshot module.
Screenshots will end up in the project root of not defined.
If a path is configured, the directory will be auto-created.
"""
# Finders
PROGRAM_FINDERS: list[str] = []
"""
Finder classes for locating programs/shaders.
.. code:: python
# Default values
PROGRAM_FINDERS = [
"moderngl_window.finders.program.FileSystemFinder",
]
"""
TEXTURE_FINDERS: list[str] = []
"""
Finder classes for locating textures.
.. code:: python
# Default values
TEXTURE_FINDERS = [
"moderngl_window.finders.texture.FileSystemFinder",
]
"""
SCENE_FINDERS: list[str] = []
"""
Finder classes for locating scenes.
.. code:: python
# Default values
SCENE_FINDERS = [
"moderngl_window.finders.scene.FileSystemFinder",
]
"""
DATA_FINDERS: list[str] = []
"""
Finder classes for locating data files.
.. code:: python
# Default values
DATA_FINDERS = [
"moderngl_window.finders.data.FileSystemFinder",
]
"""
# Finder dirs
PROGRAM_DIRS: list[Union[str, pathlib.Path]] = []
"""
Lists of `str` or `pathlib.Path` used by ``FileSystemFinder``
to looks for programs/shaders.
"""
TEXTURE_DIRS: list[Union[str, pathlib.Path]] = []
"""
Lists of `str` or `pathlib.Path` used by ``FileSystemFinder``
to looks for textures.
"""
SCENE_DIRS: list[Union[str, pathlib.Path]] = []
"""
Lists of `str` or `pathlib.Path` used by ``FileSystemFinder``
to looks for scenes (obj, gltf, stl etc).
"""
DATA_DIRS: list[Union[str, pathlib.Path]] = []
"""
Lists of `str` or `pathlib.Path` used by ``FileSystemFinder``
to looks for data files.
"""
# Loaders
PROGRAM_LOADERS: list[str] = []
"""
Classes responsible for loading programs/shaders.
.. code:: python
# Default values
PROGRAM_LOADERS = [
'moderngl_window.loaders.program.single.Loader',
'moderngl_window.loaders.program.separate.Loader',
]
"""
TEXTURE_LOADERS: list[str] = []
"""
Classes responsible for loading textures.
.. code:: python
# Default values
TEXTURE_LOADERS = [
'moderngl_window.loaders.texture.t2d.Loader',
'moderngl_window.loaders.texture.array.Loader',
]
"""
SCENE_LOADERS: list[str] = []
"""
Classes responsible for loading scenes.
.. code:: python
# Default values
SCENE_LOADERS = [
"moderngl_window.loaders.scene.gltf.GLTF2",
"moderngl_window.loaders.scene.wavefront.ObjLoader",
"moderngl_window.loaders.scene.stl_loader.STLLoader",
]
"""
DATA_LOADERS: list[str] = []
"""
Classes responsible for loading data files.
.. code:: python
# Default values
DATA_LOADERS = [
'moderngl_window.loaders.data.binary.Loader',
'moderngl_window.loaders.data.text.Loader',
'moderngl_window.loaders.data.json.Loader',
]
"""
def __init__(self) -> None:
"""Initialize settings with default values"""
self.apply_default_settings()
def apply_default_settings(self) -> None:
"""
Apply keys and values from the default settings module
located in this package. This is to ensure we always
have the minimal settings for the system to run.
If replacing or customizing the settings class
you must always apply default settings to ensure
compatibility when new settings are added.
"""
self.apply_from_module(default)
def apply_settings_from_env(self) -> None:
"""
Apply settings from ``MODERNGL_WINDOW_SETTINGS_MODULE`` environment variable.
If the environment variable is undefined no action will be taken.
Normally this would be used to easily be able to switch between
different configuration by setting env vars before executing the program.
Example::
import os
from moderngl_window.conf import settings
os.environ['MODERNGL_WINDOW_SETTINGS_MODULE'] = 'python.path.to.module'
settings.apply_settings_from_env()
Raises:
ImproperlyConfigured if the module was not found
"""
name = os.environ.get(SETTINGS_ENV_VAR)
if name:
self.apply_from_module_name(name)
def apply_from_module_name(self, settings_module_name: str) -> None:
"""
Apply settings from a python module by supplying the full
pythonpath to the module.
Args:
settings_module_name (str): Full python path to the module
Raises:
ImproperlyConfigured if the module was not found
"""
try:
module = importlib.import_module(settings_module_name)
except ImportError as ex:
raise ImproperlyConfigured(
"Settings module '{}' not found. From importlib: {}".format(
settings_module_name,
ex,
)
)
self.apply_from_module(module)
def apply_from_dict(self, data: dict[str, Any]) -> None:
"""
Apply settings values from a dictionary
Example::
>> from moderngl_window.conf import settings
>> settings.apply_dict({'SOME_VALUE': 1})
>> settings.SOME_VALUE
1
"""
self.apply_from_iterable(data.items())
def apply_from_module(self, module: Module) -> None:
"""
Apply settings values from a python module
Example::
my_settings.py module containing the following line:
SOME_VALUE = 1
>> from moderngl_window.conf import settings
>> import my_settings
>> settings.apply_module(my_settings)
>> settings.SOME_VALUE
1
"""
self.apply_from_iterable(module.__dict__.items())
def apply_from_cls(self, cls: Any) -> None:
"""
Apply settings values from a class namespace
Example::
>> from moderngl_window.conf import settings
>> class MySettings:
>> SOME_VALUE = 1
>>
>> settings.apply(MySettings)
>> settings.SOME_VALUE
1
"""
self.apply_from_iterable(cls.__dict__.items())
def apply_from_iterable(self, iterable: Iterable[tuple[str, Any]]) -> None:
"""
Apply (key, value) pairs from an iterable or generator
"""
if not isinstance(iterable, Iterable) and not isinstance(self, Generator):
raise ValueError(
"Input value is not a generator or iterable, but of type: {}".format(type(iterable))
)
for name, value in iterable:
if name.isupper():
setattr(self, name, value)
def to_dict(self) -> dict[str, Any]:
"""Create a dict representation of the settings
Only uppercase attributes are included
Returns:
dict: dict representation
"""
return {k: v for k, v in self.__dict__.items() if k.upper()}
def __repr__(self) -> str:
return "\n".join(
"{}={}".format(k, pformat(v, indent=2)) for k, v in self.__dict__.items() if k.isupper()
)
settings = Settings()
|