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.
- htmlmeta_hub/__init__.py +198 -0
- htmlmeta_hub/py.typed +0 -0
- htmlmeta_hub/pyramid_helpers.py +25 -0
- htmlmeta_hub-1.0.0.dist-info/METADATA +92 -0
- htmlmeta_hub-1.0.0.dist-info/RECORD +8 -0
- htmlmeta_hub-1.0.0.dist-info/WHEEL +5 -0
- htmlmeta_hub-1.0.0.dist-info/licenses/LICENSE.txt +23 -0
- htmlmeta_hub-1.0.0.dist-info/top_level.txt +1 -0
htmlmeta_hub/__init__.py
ADDED
|
@@ -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: 
|
|
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,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
|