File: base.py

package info (click to toggle)
python-moderngl-window 3.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 69,096 kB
  • sloc: python: 12,076; makefile: 21
file content (147 lines) | stat: -rw-r--r-- 4,358 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
import logging
from collections.abc import Iterable
from pathlib import Path
from typing import Any, Optional, Union

import moderngl

import moderngl_window as mglw
from moderngl_window.finders import data, program, scene, texture
from moderngl_window.finders.base import BaseFilesystemFinder
from moderngl_window.meta.base import ResourceDescription

logger = logging.getLogger(__name__)


class BaseLoader:
    """Base loader class for all resources"""

    kind = "unknown"
    """
    The kind of resource this loaded supports.
    This can be used when file extensions is not enough
    to decide what loader should be selected.
    """
    file_extensions: list[list[str]] = []
    """
    A list defining the file extensions accepted by this loader.

    Example::

        # Loader will match .xyz and .xyz.gz files.
        file_extensions = [
            ['.xyz'],
            ['.xyz', '.gz'],
        ]
    """

    def __init__(self, meta: ResourceDescription) -> None:
        """Initialize loader.

        Loaders take a ResourceDescription instance
        containing all the parameters needed to load and initialize
        this data.

        Args:
            meta (ResourceDescription): The resource to load
        """
        self.meta = meta
        if self.kind is None:
            raise ValueError("Loader {} doesn't have a kind".format(self.__class__))

    @classmethod
    def supports_file(cls: type["BaseLoader"], meta: ResourceDescription) -> bool:
        """Check if the loader has a supported file extension.

        What extensions are supported can be defined in the
        :py:attr:`file_extensions` class attribute.
        """
        path = Path(meta.path if meta.path is not None else "")

        for ext in cls.file_extensions:
            if path.suffixes[: len(ext)] == ext:
                return True

        return False

    def load(self) -> Any:
        """Loads a resource.

        When creating a loader this is the only
        method that needs to be implemented.

        Returns:
            The loaded resource
        """
        raise NotImplementedError()

    def find_data(self, path: Optional[Union[str, Path]]) -> Optional[Path]:
        """Find resource using data finders.

        This is mainly a shortcut method to simplify the task.

        Args:
            path: Path to resource
        """
        return self._find(path, data.get_finders())

    def find_program(self, path: Optional[Union[str, Path]]) -> Optional[Path]:
        """Find resource using program finders.

        This is mainly a shortcut method to simplify the task.

        Args:
            path: Path to resource
        """
        return self._find(path, program.get_finders())

    def find_texture(self, path: Optional[Union[str, Path]]) -> Optional[Path]:
        """Find resource using texture finders.

        This is mainly a shortcut method to simplify the task.

        Args:
            path: Path to resource
        """
        return self._find(path, texture.get_finders())

    def find_scene(self, path: Optional[Union[str, Path]]) -> Optional[Path]:
        """Find resource using scene finders.

        This is mainly a shortcut method to simplify the task.

        Args:
            path: Path to resource
        """
        return self._find(path, scene.get_finders())

    def _find(
        self, path: Optional[Union[str, Path]], finders: Iterable[BaseFilesystemFinder]
    ) -> Optional[Path]:
        """Find the first occurrance of this path in all finders.
        If the incoming path is an absolute path we assume this
        path exist and return it.

        Args:
            path (str): The path to find
        """
        if not path:
            return None
        if isinstance(path, str):
            path = Path(path)

        if path.is_absolute():
            return path

        for finder in finders:
            result = finder.find(path)
            if result:
                return result

        logger.debug("No finder was able to locate: %s", path)
        return None

    @property
    def ctx(self) -> moderngl.Context:
        """moderngl.Context: ModernGL context"""
        return mglw.ctx()