htmlmeta-hub 1.0.0__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.
@@ -0,0 +1,198 @@
1
+ # stdlib
2
+ import re
3
+ from typing import Dict
4
+ from typing import Optional
5
+
6
+ # local
7
+ from metadata_utils import html_attribute_escape
8
+
9
+
10
+ __VERSION__ = "1.0.0"
11
+
12
+
13
+ # ==============================================================================
14
+
15
+
16
+ _http_equivs = ("content-type", "expires", "refresh")
17
+ _link_rels = ("canonical", "link")
18
+ _invalid_attribute_name_character = re.compile(
19
+ r"""[\x00-\x20"'<>/=\x7f-\x9f\ud800-\udfff\ufdd0-\ufdef]"""
20
+ )
21
+
22
+
23
+ def _validate_attribute_name(name: str) -> None:
24
+ """Reject empty names, HTML delimiters, controls, and invalid code points."""
25
+ if (
26
+ not name
27
+ or _invalid_attribute_name_character.search(name)
28
+ or any((ord(character) & 0xFFFF) >= 0xFFFE for character in name)
29
+ ):
30
+ raise ValueError("Expected a valid HTML attribute name")
31
+
32
+
33
+ class HtmlMetaHub(object):
34
+ data_struct: Dict[str, Dict]
35
+
36
+ def __init__(self, **kwargs):
37
+ """Sets up self.data_struct dict which we use for storage of metadata.
38
+
39
+ This package is rather silly, but it affords a consistent way to manage metadata across multiple projects.
40
+ """
41
+ self.data_struct = {
42
+ "http-equiv": {},
43
+ "name": {},
44
+ "other": {},
45
+ "link": {},
46
+ "_multi": {}, # private namespace for setmulti
47
+ }
48
+ self.set_many(**kwargs)
49
+
50
+ def set_http_equiv(self, key: str, value: str):
51
+ self.data_struct["http-equiv"][key] = value
52
+
53
+ def set_link(self, rel: str, value: str):
54
+ self.data_struct["link"][rel] = value
55
+
56
+ def set_name(self, key: str, value: str):
57
+ self.data_struct["name"][key] = value
58
+
59
+ def set_other(self, key: str, value: str) -> None:
60
+ """Set a meta attribute, raising ValueError for a malformed name."""
61
+ _validate_attribute_name(key)
62
+ self.data_struct["other"][key] = value
63
+
64
+ def set(self, key: str, value: str):
65
+ """set uses (k,v) as there exists valid meta names which are not kwarg safe"""
66
+ if key.lower() in _http_equivs:
67
+ self.data_struct["http-equiv"][key] = value
68
+ elif key.lower() in _link_rels:
69
+ self.data_struct["link"][key] = value
70
+ else:
71
+ self.data_struct["name"][key] = value
72
+
73
+ def set_many(self, **kwargs):
74
+ """set simply iterates over the **kwargs; here for legacy compatibility"""
75
+ for key, value in kwargs.items():
76
+ self.set(key, value)
77
+
78
+ def get(self, key: str) -> Optional[str]:
79
+ if key.lower() in _http_equivs:
80
+ return self.data_struct["http-equiv"].get(key, None)
81
+ elif key.lower() in _link_rels:
82
+ return self.data_struct["link"].get(key, None)
83
+ else:
84
+ return self.data_struct["name"].get(key, None)
85
+
86
+ def unset(self, key: str):
87
+ if key.lower() in _http_equivs:
88
+ if key in self.data_struct["http-equiv"]:
89
+ del self.data_struct["http-equiv"][key]
90
+ elif key.lower() in _link_rels:
91
+ if key in self.data_struct["link"]:
92
+ del self.data_struct["link"][key]
93
+ else:
94
+ if key in self.data_struct["name"]:
95
+ del self.data_struct["name"][key]
96
+
97
+ # --------------------------------------------------------------------------
98
+ # these are used for multile items.
99
+ # sometimes you'll have several 'authors' in a link
100
+
101
+ def _hasmulti(self, section: str, key: str, value: str) -> bool:
102
+ if section in self.data_struct["_multi"]:
103
+ if key in self.data_struct["_multi"][section]:
104
+ if value in self.data_struct["_multi"][section][key]:
105
+ return True
106
+ return False
107
+
108
+ def _setmulti(self, section: str, key: str, value: str):
109
+ if section not in self.data_struct["_multi"]:
110
+ self.data_struct["_multi"][section] = {}
111
+ if key not in self.data_struct["_multi"][section]:
112
+ self.data_struct["_multi"][section][key] = []
113
+ if not self._hasmulti(section, key, value):
114
+ self.data_struct["_multi"][section][key].append(value)
115
+
116
+ def _unsetmulti(self, section: str, key: str, value: str):
117
+ if self._hasmulti(section, key, value):
118
+ self.data_struct["_multi"][section][key] = [
119
+ i for i in self.data_struct["_multi"][section][key] if i != value
120
+ ]
121
+
122
+ def _clearmulti(self, section: str, key: str):
123
+ if section in self.data_struct["_multi"]:
124
+ if key in self.data_struct["_multi"][section]:
125
+ del self.data_struct["_multi"][section][key]
126
+
127
+ def setmulti_link(self, key: str, value: str):
128
+ """sets a value for a non-unique key"""
129
+ self._setmulti("link", key, value)
130
+
131
+ def unsetmulti_link(self, key: str, value: str):
132
+ """unsets a value for a non-unique key"""
133
+ self._unsetmulti("link", key, value)
134
+
135
+ def clearmulti_link(self, key: str):
136
+ """clears a value for a non-unique key"""
137
+ self._clearmulti("link", key)
138
+
139
+ # --------------------------------------------------------------------------
140
+
141
+ def as_html(self) -> str:
142
+ """helper function. prints out metadata for you.
143
+
144
+ You'd probably call it like this in a Mako template:
145
+ <head>
146
+ ${meta.as_html()|n}
147
+ </head>
148
+
149
+ Notice that you have to escape under Mako. For more information on mako escape options - http://www.makotemplates.org/docs/filtering.html
150
+ """
151
+ output = []
152
+ _others = self.data_struct["other"].items()
153
+ _equivs = self.data_struct["http-equiv"].items()
154
+ _others_2 = []
155
+ _equivs_2 = []
156
+ for k, v in _others:
157
+ _validate_attribute_name(k)
158
+ if k.lower() == "charset":
159
+ output.append(
160
+ """<meta %s="%s"/>"""
161
+ % (k, html_attribute_escape(v))
162
+ )
163
+ else:
164
+ _others_2.append((k, v))
165
+ for k, v in _equivs:
166
+ if "charset" in v.lower():
167
+ output.append(
168
+ """<meta http-equiv="%s" content="%s"/>"""
169
+ % (html_attribute_escape(k), html_attribute_escape(v))
170
+ )
171
+ else:
172
+ _equivs_2.append((k, v))
173
+ for k, v in _equivs_2:
174
+ output.append(
175
+ """<meta http-equiv="%s" content="%s"/>"""
176
+ % (html_attribute_escape(k), html_attribute_escape(v))
177
+ )
178
+ for k, v in self.data_struct["name"].items():
179
+ output.append(
180
+ """<meta name="%s" content="%s"/>"""
181
+ % (html_attribute_escape(k), html_attribute_escape(v))
182
+ )
183
+ for k, v in _others_2:
184
+ output.append("""<meta %s="%s"/>""" % (k, html_attribute_escape(v)))
185
+ for rel, v in self.data_struct["link"].items():
186
+ output.append(
187
+ """<link rel="%s" href="%s"/>"""
188
+ % (html_attribute_escape(rel), html_attribute_escape(v))
189
+ )
190
+ if self.data_struct["_multi"]:
191
+ if "link" in self.data_struct["_multi"]:
192
+ for rel in self.data_struct["_multi"]["link"]:
193
+ for v in self.data_struct["_multi"]["link"][rel]:
194
+ output.append(
195
+ """<link rel="%s" href="%s"/>"""
196
+ % (html_attribute_escape(rel), html_attribute_escape(v))
197
+ )
198
+ return "\n".join(output)
htmlmeta_hub/py.typed ADDED
File without changes
@@ -0,0 +1,25 @@
1
+ # stdlib
2
+ import typing
3
+
4
+ # local
5
+ from . import HtmlMetaHub
6
+
7
+ if typing.TYPE_CHECKING:
8
+ from pyramid.config import Configurator
9
+ from pyramid.request import Request
10
+
11
+ # ==============================================================================
12
+
13
+
14
+ def includeme(config: "Configurator"):
15
+ """the pyramid includeme command
16
+ including this will automatically setup the htmlmeta object for every request
17
+ """
18
+ config.add_request_method(
19
+ "htmlmeta_hub.pyramid_helpers.new_HtmlMetaHub", "htmlmeta", reify=True
20
+ )
21
+
22
+
23
+ def new_HtmlMetaHub(request: "Request"):
24
+ """simply creates a new hub"""
25
+ return HtmlMetaHub()
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.4
2
+ Name: htmlmeta_hub
3
+ Version: 1.0.0
4
+ Summary: Lightweight support for managing metadata on webpages.
5
+ Home-page: https://github.com/jvanasco/htmlmeta_hub
6
+ Author: Jonathan Vanasco
7
+ Author-email: jvanasco@2xlp.com
8
+ License: MIT
9
+ Keywords: metadata,html,web,pyramid
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Framework :: Pyramid
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.6
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
23
+ Requires-Python: >=3.6
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE.txt
26
+ Requires-Dist: metadata_utils>=0.2.0
27
+ Requires-Dist: setuptools<82; python_version >= "3.7" and python_version < "3.10"
28
+ Provides-Extra: testing
29
+ Requires-Dist: mypy; extra == "testing"
30
+ Requires-Dist: pyramid; extra == "testing"
31
+ Requires-Dist: pytest; extra == "testing"
32
+ Dynamic: license-file
33
+
34
+ htmlmeta_hub
35
+ ============
36
+
37
+ Build Status: ![Python package](https://github.com/jvanasco/htmlmeta_hub/workflows/Python%20package/badge.svg)
38
+
39
+ `htmlmeta_hub` offers lightweight support for managing metadata on webpages.
40
+
41
+ This package simply and conveniently manages a dict of "metadata"", and renders
42
+ it appropriately.
43
+
44
+ There are helpers for the Pyramid framework which will attach the metdata object
45
+ to a request, allowing you to build up metadata throughtout the request cycle
46
+ and then finally render.
47
+
48
+ A typical way to use this package in the Pyramid framework:
49
+
50
+
51
+ Include this package in your application's `__init__.py`:
52
+
53
+ def main(global_config, **settings):
54
+ ...
55
+ # custom htmlmeta
56
+ config.include("htmlmeta_hub.pyramid_helpers")
57
+
58
+
59
+ If you are using "class based views", you can set some default metadata in a core
60
+ handler:
61
+
62
+ class Handler(object):
63
+ def __init__(self,request):
64
+ self.request = request
65
+ # set some defaults
66
+ self.reqesut.htmlmeta.set_many(\
67
+ title="MyApp",
68
+ description="awesome",
69
+ keywords="fun!",
70
+ )
71
+
72
+ and then you can add specific metadata in each view's handler:
73
+
74
+ class ContentPage(Handler):
75
+ def view(self):
76
+ content= ...
77
+ self.request.htmlmeta.set('title', content.title)
78
+ self.request.htmlmeta.set('description', content.description)
79
+
80
+ In a template, such as this `page.mako` example, you can access specific bits of
81
+ the metadata, or render an entire payload:
82
+
83
+ <title>${request.htmlmeta.get('title')|n}</title>
84
+ ${request.htmlmeta.as_html()|n}
85
+
86
+
87
+ Pyramid helpers existed until version `0.3.x` but were dropped in favor of the
88
+ `@reify` request method offered by the `config.include` method.
89
+
90
+ Pylons helpers existed until version `0.1.2` but were dropped.
91
+
92
+
@@ -0,0 +1,8 @@
1
+ htmlmeta_hub/__init__.py,sha256=7s_MNornmfEm8_VwzhN1-E5D3NXBRFm7WcyLddErycA,7461
2
+ htmlmeta_hub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ htmlmeta_hub/pyramid_helpers.py,sha256=XHM0Yq5qnsKldAvGevMAI2k-bU_wUqSr89ZmJUuh-jo,637
4
+ htmlmeta_hub-1.0.0.dist-info/licenses/LICENSE.txt,sha256=Enmm9ncWfBBUfXnpzvOXiZjo3AzSx8JX7y8MsQz66Kk,1181
5
+ htmlmeta_hub-1.0.0.dist-info/METADATA,sha256=_Vq5U1E9I0dDOnSHPlCi6VsIDyiUSvOuwiAIo_3-hw0,3000
6
+ htmlmeta_hub-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
7
+ htmlmeta_hub-1.0.0.dist-info/top_level.txt,sha256=kTgYvlNJFM3qBn1ctfEvOYW0M2l_6ZLU3sOMaa5XuyU,13
8
+ htmlmeta_hub-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,23 @@
1
+ The code is licensed as follows:
2
+
3
+ Copyright (c) 2012, Jonathan Vanasco <jonathan@findmeon.com>
4
+
5
+ MIT License -- http://www.opensource.org/licenses/mit-license
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ htmlmeta_hub