joop 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- joop/__init__.py +9 -0
- joop/abstract/README.md +3 -0
- joop/abstract/__init__.py +95 -0
- joop/cli/README.md +6 -0
- joop/cli/__init__.py +1 -0
- joop/cli/__main__.py +39 -0
- joop/cli/test_flask.py +36 -0
- joop/dao/__init__.py +151 -0
- joop/flask/__init__.py +31 -0
- joop/flask/example.py +19 -0
- joop/flask/flask_view.py +71 -0
- joop/http/methods.py +49 -0
- joop/tests/__init__.py +5 -0
- joop/tests/test_joop.py +29 -0
- joop/tests/test_templater.py +31 -0
- joop/tests/test_view.py +46 -0
- joop/tests/test_web.py +75 -0
- joop/web/__init__.py +14 -0
- joop/web/component.py +163 -0
- joop/web/components.py +116 -0
- joop/web/examples/hello.py +148 -0
- joop/web/examples/table.py +148 -0
- joop/web/examples/view.py +30 -0
- joop/web/html.py +212 -0
- joop/web/j_env.py +39 -0
- joop/web/templater.py +139 -0
- joop/web/view.py +214 -0
- joop-0.0.1.dist-info/METADATA +133 -0
- joop-0.0.1.dist-info/RECORD +31 -0
- joop-0.0.1.dist-info/WHEEL +4 -0
- joop-0.0.1.dist-info/entry_points.txt +3 -0
joop/web/html.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
""" An HTML Component is a joop Component that renders to HTML.
|
|
2
|
+
|
|
3
|
+
Like many projects, joop achieves this via jinja templating.
|
|
4
|
+
There is a specific structure for template variables that joop imposes to meet
|
|
5
|
+
its goals of providing a "place for everything and everything in its place."
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
HTML:
|
|
9
|
+
A base class for managing Jinja2 templates and rendering HTML content.
|
|
10
|
+
|
|
11
|
+
HTMLComponent:
|
|
12
|
+
A component class that extends both Component and HTML to provide
|
|
13
|
+
functionality for rendering HTML components with subcomponents and data.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import jinja2
|
|
18
|
+
from typing import Optional
|
|
19
|
+
from dataclasses import asdict, fields
|
|
20
|
+
from joop.web.component import Component
|
|
21
|
+
from joop.web.j_env import get_joop_env
|
|
22
|
+
|
|
23
|
+
class HTML():
|
|
24
|
+
"""
|
|
25
|
+
A base class for managing Jinja2 templates and rendering HTML content.
|
|
26
|
+
|
|
27
|
+
Its main purpose is to tie behavior to a specific Jinja2 env, especially
|
|
28
|
+
in terms of template location.
|
|
29
|
+
|
|
30
|
+
This class provides methods for initializing and managing a Jinja2 environment
|
|
31
|
+
and loading templates for rendering HTML.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
_template_location (str): The location of the Jinja2 template file.
|
|
35
|
+
_jinja_env (Optional[jinja2.Environment]): The Jinja2 environment used for rendering.
|
|
36
|
+
|
|
37
|
+
Methods:
|
|
38
|
+
__init__(j_env: Optional[jinja2.Environment] = None):
|
|
39
|
+
Initializes the HTML class with a Jinja2 environment.
|
|
40
|
+
|
|
41
|
+
_get_template() -> jinja2.Template:
|
|
42
|
+
Retrieves the Jinja2 template based on the template location.
|
|
43
|
+
"""
|
|
44
|
+
_template_location: None
|
|
45
|
+
_jinja_env: Optional[jinja2.Environment] = None
|
|
46
|
+
|
|
47
|
+
def __init__(self, j_env: Optional[jinja2.Environment] = None):
|
|
48
|
+
"""
|
|
49
|
+
Initialize the HTML class with a Jinja2 environment.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
j_env (Optional[jinja2.Environment]): The Jinja2 environment to use for rendering.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If no Jinja2 environment is provided or available.
|
|
56
|
+
"""
|
|
57
|
+
if j_env is not None:
|
|
58
|
+
self._jinja_env = j_env
|
|
59
|
+
elif self._jinja_env is None:
|
|
60
|
+
self._jinja_env = get_joop_env()
|
|
61
|
+
|
|
62
|
+
if self._jinja_env is None:
|
|
63
|
+
raise ValueError("A Jinja2 environment must be provided either as a class property or during initialization.")
|
|
64
|
+
|
|
65
|
+
def _get_template(self) -> jinja2.Template:
|
|
66
|
+
"""
|
|
67
|
+
Retrieve the Jinja2 template based on the template location.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
jinja2.Template: The Jinja2 template object.
|
|
71
|
+
"""
|
|
72
|
+
_res = self._jinja_env.get_template(self._template_location)
|
|
73
|
+
return _res
|
|
74
|
+
|
|
75
|
+
class HTMLComponent(Component, HTML):
|
|
76
|
+
"""
|
|
77
|
+
A component class that extends both Component and HTML to provide functionality
|
|
78
|
+
for rendering HTML components with subcomponents and data.
|
|
79
|
+
|
|
80
|
+
This class integrates the base Component class with the HTML class to enable
|
|
81
|
+
dynamic rendering of HTML components using Jinja2 templates.
|
|
82
|
+
|
|
83
|
+
Attributes:
|
|
84
|
+
_loaded_template (jinja2.Template): The loaded Jinja2 template for the component.
|
|
85
|
+
|
|
86
|
+
Methods:
|
|
87
|
+
__init__(j_env: Optional[jinja2.Environment] = None, parent: Optional[Component] = None):
|
|
88
|
+
Initializes the HTMLComponent with a Jinja2 environment and an optional parent component.
|
|
89
|
+
|
|
90
|
+
_load_template():
|
|
91
|
+
Loads the Jinja2 template for the component.
|
|
92
|
+
|
|
93
|
+
render(as_subcomponent: bool = False, **kwargs) -> str:
|
|
94
|
+
Renders the component as a string, optionally as a subcomponent.
|
|
95
|
+
|
|
96
|
+
Nested Classes:
|
|
97
|
+
SubComponents:
|
|
98
|
+
A class for managing subcomponents of the HTMLComponent.
|
|
99
|
+
|
|
100
|
+
Methods:
|
|
101
|
+
get_all -> dict[str, 'Component']:
|
|
102
|
+
Retrieves all subcomponents as a dictionary.
|
|
103
|
+
|
|
104
|
+
render():
|
|
105
|
+
Renders all subcomponents and stores their HTML output.
|
|
106
|
+
|
|
107
|
+
get_rendered() -> dict[str, str]:
|
|
108
|
+
Returns the rendered HTML output of all subcomponents.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
class SubComponents(Component.SubComponents):
|
|
112
|
+
"""
|
|
113
|
+
A class for managing subcomponents of the HTMLComponent.
|
|
114
|
+
|
|
115
|
+
Methods:
|
|
116
|
+
get_all -> dict[str, 'Component']:
|
|
117
|
+
Retrieves all subcomponents as a dictionary.
|
|
118
|
+
|
|
119
|
+
render():
|
|
120
|
+
Renders all subcomponents and stores their HTML output.
|
|
121
|
+
|
|
122
|
+
get_rendered() -> dict[str, str]:
|
|
123
|
+
Returns the rendered HTML output of all subcomponents.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def get_all(self) -> dict[str, 'Component']:
|
|
128
|
+
"""
|
|
129
|
+
Retrieve all subcomponents as a dictionary.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
dict[str, Component]: A dictionary where keys are subcomponent names
|
|
133
|
+
and values are the subcomponent instances.
|
|
134
|
+
"""
|
|
135
|
+
return {field.name: getattr(self, field.name) for field in fields(self)}
|
|
136
|
+
|
|
137
|
+
def render(self):
|
|
138
|
+
"""
|
|
139
|
+
Render all subcomponents and store their HTML output.
|
|
140
|
+
|
|
141
|
+
This method iterates through all subcomponents, renders each one, and
|
|
142
|
+
stores the resulting HTML in a dictionary.
|
|
143
|
+
"""
|
|
144
|
+
self._rendered_sc_html = {}
|
|
145
|
+
for _sc_name, _sc_inst in self.get_all.items():
|
|
146
|
+
self._rendered_sc_html[_sc_name] = _sc_inst.render(as_subcomponent = True)
|
|
147
|
+
|
|
148
|
+
def get_rendered(self) -> dict[str, str]:
|
|
149
|
+
"""
|
|
150
|
+
Return the rendered HTML output of all subcomponents.
|
|
151
|
+
|
|
152
|
+
This method ensures that all subcomponents are rendered and returns
|
|
153
|
+
their HTML output as a dictionary.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
dict[str, str]: A dictionary where keys are subcomponent names and
|
|
157
|
+
values are their rendered HTML output.
|
|
158
|
+
"""
|
|
159
|
+
self.render()
|
|
160
|
+
return self._rendered_sc_html
|
|
161
|
+
|
|
162
|
+
def __init__(self, j_env: Optional[jinja2.Environment] = None, parent: Optional[Component] = None):
|
|
163
|
+
"""
|
|
164
|
+
Initialize the HTMLComponent with a Jinja2 environment and an optional parent component.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
j_env (Optional[jinja2.Environment]): The Jinja2 environment to use for rendering.
|
|
168
|
+
parent (Optional[Component]): The parent component, if any.
|
|
169
|
+
"""
|
|
170
|
+
super().__init__(parent=parent, j_env=j_env) # Pass both arguments to super()
|
|
171
|
+
|
|
172
|
+
_loaded_template: jinja2.Template
|
|
173
|
+
|
|
174
|
+
def _load_template(self):
|
|
175
|
+
"""
|
|
176
|
+
Load the Jinja2 template for the component.
|
|
177
|
+
|
|
178
|
+
This method retrieves the template using the _get_template method and
|
|
179
|
+
stores it in the _loaded_template attribute.
|
|
180
|
+
"""
|
|
181
|
+
self._loaded_template = self._get_template()
|
|
182
|
+
|
|
183
|
+
def render(self, as_subcomponent : bool = False, **kwargs) -> str:
|
|
184
|
+
"""
|
|
185
|
+
Render the component as a string, optionally as a subcomponent.
|
|
186
|
+
|
|
187
|
+
This method prepares the component for rendering, loads the template,
|
|
188
|
+
and renders the HTML output using the provided data and subcomponents.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
as_subcomponent (bool): Whether to render the component as a subcomponent.
|
|
192
|
+
**kwargs: Additional keyword arguments for rendering.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
str: The rendered HTML output.
|
|
196
|
+
"""
|
|
197
|
+
if as_subcomponent == True:
|
|
198
|
+
self.inputs = self.Inputs(**kwargs)
|
|
199
|
+
super().render()
|
|
200
|
+
if as_subcomponent == True:
|
|
201
|
+
self.subs = self.SubComponents()
|
|
202
|
+
self._load_template()
|
|
203
|
+
_joop = {
|
|
204
|
+
'sc' : self.subs.get_rendered(),
|
|
205
|
+
'data' : asdict(self.data)
|
|
206
|
+
}
|
|
207
|
+
print(_joop)
|
|
208
|
+
return self._loaded_template.render(
|
|
209
|
+
joop = _joop
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# render.__isabstractmethod__ = True
|
joop/web/j_env.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Environment management module for joop.
|
|
2
|
+
|
|
3
|
+
Important: The main purpose of this module is to be an interface layer for the jinja environment proxy
|
|
4
|
+
contained within joop for cross platform purposes (ex. run with or without flask.)
|
|
5
|
+
|
|
6
|
+
This module provides functions to set and get the global templating environment for the joop instance.
|
|
7
|
+
|
|
8
|
+
Variables:
|
|
9
|
+
joop_env:
|
|
10
|
+
A global variable to store the current templating environment.
|
|
11
|
+
|
|
12
|
+
Functions:
|
|
13
|
+
set_joop_env(value):
|
|
14
|
+
Sets the global templating environment to the provided value.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
value: The new environment to set as the global environment.
|
|
18
|
+
|
|
19
|
+
get_joop_env():
|
|
20
|
+
Retrieves the current global templating environment.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The current global templating environment.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
- Use `set_joop_env(value)` to set the global environment.
|
|
27
|
+
- Use `get_joop_env()` to retrieve the current global environment.
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
joop_env = None
|
|
32
|
+
|
|
33
|
+
def set_joop_env(value):
|
|
34
|
+
global joop_env
|
|
35
|
+
joop_env = value
|
|
36
|
+
|
|
37
|
+
def get_joop_env():
|
|
38
|
+
global joop_env
|
|
39
|
+
return(joop_env)
|
joop/web/templater.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Templating environment factory for joop.
|
|
2
|
+
|
|
3
|
+
Contains key implementation for joop templates, providing structure for data
|
|
4
|
+
access inside jinja templates.
|
|
5
|
+
If it isn't a joop env, it won't work with joop templating.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
EnvironmentFactory:
|
|
9
|
+
A factory class for creating and configuring Jinja2 Environment instances.
|
|
10
|
+
|
|
11
|
+
Methods:
|
|
12
|
+
create_environment(**kwargs):
|
|
13
|
+
Creates and configures a Jinja2 Environment instance.
|
|
14
|
+
Registers subcomponent and ata functions.
|
|
15
|
+
|
|
16
|
+
_get_joop(ctx: Context) -> dict:
|
|
17
|
+
Retrieves the 'joop' dictionary from the Jinja2 context.
|
|
18
|
+
|
|
19
|
+
subcomponent(ctx: Context, subcomponent_name: str) -> Markup:
|
|
20
|
+
Retrieves and marks a subcomponent as safe HTML.
|
|
21
|
+
|
|
22
|
+
data(ctx: Context, key: str) -> str:
|
|
23
|
+
Retrieves data associated with a key from the Jinja2 context.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
- Use `EnvironmentFactory.create_environment()` to create a Jinja2 Environment.
|
|
27
|
+
- Use `subcomponent` and `data` methods to access joop data and subcomponents within a rendered template.
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from jinja2 import Environment as JinjaEnvironment, pass_context
|
|
32
|
+
from jinja2.runtime import Context
|
|
33
|
+
from markupsafe import Markup
|
|
34
|
+
|
|
35
|
+
_JOOP_ROOT = 'joop'
|
|
36
|
+
_SUBCOMPONENT_ROOT = 'sc'
|
|
37
|
+
_DATA_ROOT = 'data'
|
|
38
|
+
|
|
39
|
+
class EnvironmentFactory:
|
|
40
|
+
"""
|
|
41
|
+
A factory class for creating and configuring Jinja2 Environment instances.
|
|
42
|
+
|
|
43
|
+
This class provides static methods to create a Jinja2 Environment and to define custom
|
|
44
|
+
functions for interacting with the Jinja2 context, such as retrieving subcomponents
|
|
45
|
+
and data.
|
|
46
|
+
|
|
47
|
+
Methods:
|
|
48
|
+
create_environment(**kwargs):
|
|
49
|
+
Creates and configures a Jinja2 Environment instance.
|
|
50
|
+
|
|
51
|
+
_get_joop(ctx: Context) -> dict:
|
|
52
|
+
Retrieves the 'joop' dictionary from the Jinja2 context.
|
|
53
|
+
|
|
54
|
+
subcomponent(ctx: Context, subcomponent_name: str) -> Markup:
|
|
55
|
+
Retrieves and marks a subcomponent as safe HTML.
|
|
56
|
+
|
|
57
|
+
data(ctx: Context, key: str) -> str:
|
|
58
|
+
Retrieves data associated with a key from the Jinja2 context.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def create_environment(**kwargs):
|
|
63
|
+
"""Factory method to create and configure a Jinja2 Environment.
|
|
64
|
+
|
|
65
|
+
Important: Registers the two main joop functions to the environment:
|
|
66
|
+
'subcomponents' and 'data'.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
**kwargs: Arbitrary keyword arguments to configure the Jinja2 Environment.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
JinjaEnvironment: A configured Jinja2 Environment instance.
|
|
73
|
+
|
|
74
|
+
Usage Example:
|
|
75
|
+
env = EnvironmentFactory.create_environment(autoescape=True)
|
|
76
|
+
"""
|
|
77
|
+
env = JinjaEnvironment(**kwargs)
|
|
78
|
+
env.globals.update({
|
|
79
|
+
'subcomponent': EnvironmentFactory.subcomponent,
|
|
80
|
+
'data': EnvironmentFactory.data,
|
|
81
|
+
})
|
|
82
|
+
return env
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def _get_joop(ctx: Context) -> dict:
|
|
86
|
+
"""
|
|
87
|
+
Retrieve the 'joop' dictionary from the Jinja2 context.
|
|
88
|
+
|
|
89
|
+
Used by both `subcomponent` and `data` functions.
|
|
90
|
+
May seem like a lot of overhead, but it centralizes logic
|
|
91
|
+
and keeps everything in its place.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
ctx (Context): The Jinja2 context object.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
dict: The 'joop' dictionary if it exists, otherwise an empty dictionary.
|
|
98
|
+
"""
|
|
99
|
+
return ctx.get(_JOOP_ROOT, {})
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
@pass_context
|
|
103
|
+
def subcomponent(ctx: Context, subcomponent_name: str) -> Markup:
|
|
104
|
+
"""
|
|
105
|
+
Retrieve and mark a subcomponent as safe HTML.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
ctx (Context): The Jinja2 context object.
|
|
109
|
+
subcomponent_name (str): The name of the subcomponent to retrieve.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Markup: The safe HTML content of the subcomponent, or an empty string if the subcomponent is not found.
|
|
113
|
+
|
|
114
|
+
This function accesses the Jinja2 context to fetch a subcomponent stored under a specific name.
|
|
115
|
+
It ensures that the subcomponent is retrieved safely and marked as safe HTML.
|
|
116
|
+
If the subcomponent does not exist, an empty string is returned.
|
|
117
|
+
"""
|
|
118
|
+
_sc_val = EnvironmentFactory._get_joop(ctx).get(_SUBCOMPONENT_ROOT, {}).get(subcomponent_name, "")
|
|
119
|
+
return Markup(_sc_val)
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
@pass_context
|
|
123
|
+
def data(ctx: Context, key: str) -> str:
|
|
124
|
+
"""
|
|
125
|
+
Retrieve data associated with a key from the Jinja2 context.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
ctx (Context): The Jinja2 context object.
|
|
129
|
+
key (str): The key for the data to be retrieved.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
str: The data associated with the key, or an empty string if not found.
|
|
133
|
+
|
|
134
|
+
This function accesses the Jinja2 context to fetch data stored under a specific key.
|
|
135
|
+
It ensures that the data is retrieved safely and returns an empty string if the key
|
|
136
|
+
does not exist in the context.
|
|
137
|
+
"""
|
|
138
|
+
_sc_val = EnvironmentFactory._get_joop(ctx).get(_DATA_ROOT, {}).get(key, "")
|
|
139
|
+
return _sc_val
|
joop/web/view.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Views are how components are integrated with webservers. The view (or route) is defined
|
|
4
|
+
and established by this class.
|
|
5
|
+
|
|
6
|
+
Classes:
|
|
7
|
+
View:
|
|
8
|
+
The base class for defining and managing views in the joop project.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import List, Callable, Type
|
|
13
|
+
|
|
14
|
+
from joop.abstract import AbstractMethod
|
|
15
|
+
from joop.http.methods import HttpMethod
|
|
16
|
+
from joop.web.component import Component
|
|
17
|
+
|
|
18
|
+
class View():
|
|
19
|
+
"""
|
|
20
|
+
The base class for defining and managing views in the joop project.
|
|
21
|
+
|
|
22
|
+
This class provides methods for rendering components, managing inputs and
|
|
23
|
+
subcomponents, and integrating views with web frameworks.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
_component_type (Type[Component]):
|
|
27
|
+
The type of the component associated with the view.
|
|
28
|
+
|
|
29
|
+
_args_to_inputs (bool):
|
|
30
|
+
Determines whether to automatically map arguments to component inputs.
|
|
31
|
+
|
|
32
|
+
_get_default_subs (bool):
|
|
33
|
+
Determines whether to automatically retrieve default subcomponents.
|
|
34
|
+
|
|
35
|
+
_as_response (bool):
|
|
36
|
+
Determines whether the view should render a response instead of a component.
|
|
37
|
+
|
|
38
|
+
Methods:
|
|
39
|
+
_get_inputs(**kwargs):
|
|
40
|
+
Retrieves the inputs for the component based on the provided keyword arguments.
|
|
41
|
+
|
|
42
|
+
_get_subs(**kwargs):
|
|
43
|
+
Retrieves the default subcomponents for the component.
|
|
44
|
+
|
|
45
|
+
render(**kwargs):
|
|
46
|
+
Renders the component and returns the rendered output as a string.
|
|
47
|
+
|
|
48
|
+
_add_to_app(app: object, view_func: Callable):
|
|
49
|
+
Abstract method to add the view to a web application.
|
|
50
|
+
|
|
51
|
+
add_to_app(app: object):
|
|
52
|
+
Adds the view to a web application with the specified configuration.
|
|
53
|
+
|
|
54
|
+
_get_jinja_env():
|
|
55
|
+
Abstract method to retrieve the Jinja2 environment.
|
|
56
|
+
|
|
57
|
+
get_jinja_env():
|
|
58
|
+
Retrieves the Jinja2 environment by calling the abstract method.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
_component_type : Type[Component]
|
|
62
|
+
|
|
63
|
+
class Endpoint():
|
|
64
|
+
_url: str
|
|
65
|
+
_name : str
|
|
66
|
+
_methods : List[HttpMethod]
|
|
67
|
+
|
|
68
|
+
_args_to_inputs : bool = True
|
|
69
|
+
_get_default_subs : bool = True
|
|
70
|
+
|
|
71
|
+
'''
|
|
72
|
+
aliases might be added later
|
|
73
|
+
_arg_aliases : dict = {} # aliases might be added later
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def _process_kwargs_aliases(cls, **kwargs):
|
|
77
|
+
# Rename the keys in kwargs based on the _arg_aliases mapping
|
|
78
|
+
for old_key, new_key in cls._arg_aliases.items():
|
|
79
|
+
if kwargs.get(old_key) is not None:
|
|
80
|
+
if new_key not in kwargs:
|
|
81
|
+
kwargs[new_key] = kwargs[old_key]
|
|
82
|
+
del(kwargs[old_key])
|
|
83
|
+
else:
|
|
84
|
+
raise KeyError(f"Key conflict: '{new_key}' already exists in kwargs.")
|
|
85
|
+
'''
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def _get_inputs(cls, **kwargs):
|
|
89
|
+
"""
|
|
90
|
+
Retrieve the inputs for the component based on the provided keyword arguments.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
**kwargs: Keyword arguments to be mapped to the component's inputs.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Component.Inputs: The inputs for the component, or None if `_args_to_inputs` is False.
|
|
97
|
+
"""
|
|
98
|
+
_res = None
|
|
99
|
+
if cls._args_to_inputs == True:
|
|
100
|
+
_res = cls._component_type.Inputs(**kwargs)
|
|
101
|
+
# cls._process_kwargs_aliases(**kwargs)
|
|
102
|
+
return _res
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def _get_subs(cls, **kwargs):
|
|
106
|
+
"""
|
|
107
|
+
Retrieve the default subcomponents for the component.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
**kwargs: Keyword arguments (not used in the default implementation).
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Component.SubComponents: The default subcomponents for the component, or None if `_get_default_subs` is False.
|
|
114
|
+
"""
|
|
115
|
+
_res = None
|
|
116
|
+
if cls._get_default_subs == True:
|
|
117
|
+
_res = cls._component_type.SubComponents()
|
|
118
|
+
return _res
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def render(cls, **kwargs):
|
|
123
|
+
"""
|
|
124
|
+
Render the component and return the rendered output as a string.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
**kwargs: Keyword arguments to be passed to the component's inputs and subcomponents.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
str: The rendered output of the component.
|
|
131
|
+
"""
|
|
132
|
+
_component = cls._component_type()
|
|
133
|
+
_component.inputs = cls._get_inputs(**kwargs)
|
|
134
|
+
_component.subs = cls._get_subs()
|
|
135
|
+
return _component.render()
|
|
136
|
+
|
|
137
|
+
_as_response : bool = False
|
|
138
|
+
|
|
139
|
+
''' To be implemented. For cases where specific response rendering logic is needed.
|
|
140
|
+
@classmethod
|
|
141
|
+
def render_response(cls, instance : 'View' = None, **kwargs):
|
|
142
|
+
if cls._template_name is None:
|
|
143
|
+
raise NotImplementedError("Abstract; not implemented")
|
|
144
|
+
|
|
145
|
+
if instance is None:
|
|
146
|
+
instance = cls(req)
|
|
147
|
+
|
|
148
|
+
rendered = cls.render_template(instance= instance, **kwargs)
|
|
149
|
+
return instance._site.make_response(rendered)
|
|
150
|
+
'''
|
|
151
|
+
|
|
152
|
+
@classmethod
|
|
153
|
+
def _add_to_app(cls, app : object, view_func : Callable):
|
|
154
|
+
"""
|
|
155
|
+
Abstract method to add the view to a web application.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
app (object): The web application instance.
|
|
159
|
+
view_func (Callable): The view function to associate with the application.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
NotImplementedError: If the method is not implemented in a subclass.
|
|
163
|
+
"""
|
|
164
|
+
raise NotImplementedError("Abstract; not implemented")
|
|
165
|
+
|
|
166
|
+
_add_to_app = AbstractMethod(_add_to_app)
|
|
167
|
+
|
|
168
|
+
@classmethod
|
|
169
|
+
def add_to_app(cls, app : object):
|
|
170
|
+
"""
|
|
171
|
+
Add the view to a web application with the specified configuration.
|
|
172
|
+
|
|
173
|
+
This method validates the view's configuration and registers it with the
|
|
174
|
+
web application using the `_add_to_app` method.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
app (object): The web application instance.
|
|
178
|
+
|
|
179
|
+
Raises:
|
|
180
|
+
NotImplementedError: If the view's configuration is incomplete or invalid.
|
|
181
|
+
"""
|
|
182
|
+
if (cls.Endpoint._url is None or
|
|
183
|
+
cls.Endpoint._name is None or
|
|
184
|
+
cls.Endpoint._methods is None or
|
|
185
|
+
cls._component_type is None):
|
|
186
|
+
raise NotImplementedError("Abstract; not implemented")
|
|
187
|
+
|
|
188
|
+
view_func = cls.render
|
|
189
|
+
if cls._as_response == True:
|
|
190
|
+
view_func = cls.render_response
|
|
191
|
+
|
|
192
|
+
cls._add_to_app(app, view_func)
|
|
193
|
+
|
|
194
|
+
@classmethod
|
|
195
|
+
def _get_jinja_env(cls):
|
|
196
|
+
"""
|
|
197
|
+
Abstract method to retrieve the Jinja2 environment.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
NotImplementedError: If the method is not implemented in a subclass.
|
|
201
|
+
"""
|
|
202
|
+
raise NotImplementedError("Abstract; not implemented")
|
|
203
|
+
|
|
204
|
+
_get_jinja_env = AbstractMethod(_get_jinja_env)
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def get_jinja_env(cls):
|
|
208
|
+
"""
|
|
209
|
+
Retrieve the Jinja2 environment by calling the abstract method.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
jinja2.Environment: The Jinja2 environment associated with the view.
|
|
213
|
+
"""
|
|
214
|
+
return cls._get_jinja_env()
|