Skip to content

Commit 7d18ecc

Browse files
TheTripleVItayZiv
andcommitted
refactor code
Co-authored-by: Itay Ziv <[email protected]>
1 parent 285768e commit 7d18ecc

File tree

5 files changed

+152
-125
lines changed

5 files changed

+152
-125
lines changed

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import subprocess
2+
23
import setuptools
34

45
# This will fail if something happens or if not in a git repository.

sphinxext/opengraph/__init__.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from typing import Any, Dict
2+
from urllib.parse import urljoin
3+
4+
import docutils.nodes as nodes
5+
from sphinx.application import Sphinx
6+
7+
from .descriptionparser import get_description
8+
from .titleparser import get_title
9+
10+
DEFAULT_DESCRIPTION_LENGTH = 200
11+
12+
def make_tag(property: str, content: str) -> str:
13+
return f'<meta property="{property}" content="{content}" />\n '
14+
15+
16+
def get_tags(
17+
context: Dict[str, Any], doctree: nodes.document, config: Dict[str, Any]
18+
) -> str:
19+
20+
# Set length of description
21+
try:
22+
desc_len = int(config["ogp_description_length"])
23+
except ValueError:
24+
desc_len = DEFAULT_DESCRIPTION_LENGTH
25+
26+
# Get the title and parse any html in it
27+
title = get_title(context["title"], skip_html_tags=False)
28+
title_excluding_html = get_title(context["title"], skip_html_tags=True)
29+
30+
# Parse/walk doctree for metadata (tag/description)
31+
description = get_description(doctree, desc_len, [title, title_excluding_html])
32+
33+
tags = "\n "
34+
35+
# title tag
36+
tags += make_tag("og:title", title)
37+
38+
# type tag
39+
tags += make_tag("og:type", config["ogp_type"])
40+
41+
# url tag
42+
# Get the URL of the specific page
43+
page_url = urljoin(
44+
config["ogp_site_url"], context["pagename"] + context["file_suffix"]
45+
)
46+
tags += make_tag("og:url", page_url)
47+
48+
# site name tag
49+
site_name = config["ogp_site_name"]
50+
if site_name:
51+
tags += make_tag("og:site_name", site_name)
52+
53+
# description tag
54+
tags += make_tag("og:description", description)
55+
56+
# image tag
57+
# Get the image from the config
58+
image_url = config["ogp_image"]
59+
if image_url:
60+
tags += make_tag("og:image", image_url)
61+
62+
# Add image alt text (either provided by config or from site_name)
63+
ogp_image_alt = config["ogp_image_alt"]
64+
if isinstance(ogp_image_alt, str):
65+
tags += make_tag("og:image:alt", ogp_image_alt)
66+
elif ogp_image_alt and site_name:
67+
tags += make_tag("og:image:alt", site_name)
68+
elif ogp_image_alt and title:
69+
tags += make_tag("og:image:alt", title)
70+
71+
# custom tags
72+
tags += "\n".join(config["ogp_custom_meta_tags"])
73+
74+
return tags
75+
76+
77+
def html_page_context(
78+
app: Sphinx,
79+
pagename: str,
80+
templatename: str,
81+
context: Dict[str, Any],
82+
doctree: nodes.document,
83+
) -> None:
84+
if doctree:
85+
context["metatags"] += get_tags(context, doctree, app.config)
86+
87+
88+
def setup(app: Sphinx) -> Dict[str, Any]:
89+
app.add_config_value("ogp_site_url", None, "html")
90+
app.add_config_value("ogp_description_length", DEFAULT_DESCRIPTION_LENGTH, "html")
91+
app.add_config_value("ogp_image", None, "html")
92+
app.add_config_value("ogp_image_alt", True, "html")
93+
app.add_config_value("ogp_type", "website", "html")
94+
app.add_config_value("ogp_site_name", None, "html")
95+
app.add_config_value("ogp_custom_meta_tags", [], "html")
96+
97+
app.connect("html-page-context", html_page_context)
98+
99+
return {
100+
"parallel_read_safe": True,
101+
"parallel_write_safe": True,
102+
}
Lines changed: 11 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,10 @@
1-
from typing import Any, Dict, Iterable, Sequence, Tuple
2-
from urllib.parse import urljoin
3-
import docutils.nodes as nodes
41
import string
5-
from html.parser import HTMLParser
6-
import sphinx
7-
from sphinx.application import Sphinx
8-
9-
DEFAULT_DESCRIPTION_LENGTH = 200
10-
11-
12-
class HTMLTextParser(HTMLParser):
13-
"""
14-
Parse HTML into text
15-
"""
16-
17-
def __init__(self):
18-
super().__init__()
19-
# All text found
20-
self.text = ""
21-
# Only text outside of html tags
22-
self.text_outside_tags = ""
23-
self.level = 0
2+
from typing import Iterable
243

25-
def handle_starttag(self, tag, attrs) -> None:
26-
self.level += 1
27-
28-
def handle_endtag(self, tag) -> None:
29-
self.level -= 1
30-
31-
def handle_data(self, data) -> None:
32-
self.text += data
33-
if self.level == 0:
34-
self.text_outside_tags += data
4+
import docutils.nodes as nodes
355

366

37-
class OGMetadataCreatorVisitor(nodes.NodeVisitor):
7+
class DescriptionParser(nodes.NodeVisitor):
388
"""
399
Finds the title and creates a description from a doctree
4010
"""
@@ -145,96 +115,13 @@ def dispatch_departure(self, node: nodes.Element) -> None:
145115
self.stop = True
146116

147117

148-
def make_tag(property: str, content: str) -> str:
149-
return f'<meta property="{property}" content="{content}" />\n '
150-
151-
152-
def get_tags(
153-
context: Dict[str, Any], doctree: nodes.document, config: Dict[str, Any]
154-
) -> str:
155-
156-
# Set length of description
157-
try:
158-
desc_len = int(config["ogp_description_length"])
159-
except ValueError:
160-
desc_len = DEFAULT_DESCRIPTION_LENGTH
161-
162-
# Get the title and parse any html in it
163-
htp = HTMLTextParser()
164-
htp.feed(context["title"])
165-
htp.close()
118+
def get_description(
119+
doctree: nodes.document,
120+
description_length: int,
121+
known_titles: Iterable[str] = None,
122+
document: nodes.document = None,
123+
):
166124

167-
# Parse/walk doctree for metadata (tag/description)
168-
mcv = OGMetadataCreatorVisitor(desc_len, [htp.text, htp.text_outside_tags])
125+
mcv = DescriptionParser(description_length, known_titles, document)
169126
doctree.walkabout(mcv)
170-
171-
tags = "\n "
172-
173-
# title tag
174-
tags += make_tag("og:title", htp.text)
175-
176-
# type tag
177-
tags += make_tag("og:type", config["ogp_type"])
178-
179-
# url tag
180-
# Get the URL of the specific page
181-
page_url = urljoin(
182-
config["ogp_site_url"], context["pagename"] + context["file_suffix"]
183-
)
184-
tags += make_tag("og:url", page_url)
185-
186-
# site name tag
187-
site_name = config["ogp_site_name"]
188-
if site_name:
189-
tags += make_tag("og:site_name", site_name)
190-
191-
# description tag
192-
tags += make_tag("og:description", mcv.description)
193-
194-
# image tag
195-
# Get the image from the config
196-
image_url = config["ogp_image"]
197-
if image_url:
198-
tags += make_tag("og:image", image_url)
199-
200-
# Add image alt text (either provided by config or from site_name)
201-
ogp_image_alt = config["ogp_image_alt"]
202-
if isinstance(ogp_image_alt, str):
203-
tags += make_tag("og:image:alt", ogp_image_alt)
204-
elif ogp_image_alt and site_name:
205-
tags += make_tag("og:image:alt", site_name)
206-
elif ogp_image_alt and htp.text:
207-
tags += make_tag("og:image:alt", htp.text)
208-
209-
# custom tags
210-
tags += "\n".join(config["ogp_custom_meta_tags"])
211-
212-
return tags
213-
214-
215-
def html_page_context(
216-
app: Sphinx,
217-
pagename: str,
218-
templatename: str,
219-
context: Dict[str, Any],
220-
doctree: nodes.document,
221-
) -> None:
222-
if doctree:
223-
context["metatags"] += get_tags(context, doctree, app.config)
224-
225-
226-
def setup(app: Sphinx) -> Dict[str, Any]:
227-
app.add_config_value("ogp_site_url", None, "html")
228-
app.add_config_value("ogp_description_length", DEFAULT_DESCRIPTION_LENGTH, "html")
229-
app.add_config_value("ogp_image", None, "html")
230-
app.add_config_value("ogp_image_alt", True, "html")
231-
app.add_config_value("ogp_type", "website", "html")
232-
app.add_config_value("ogp_site_name", None, "html")
233-
app.add_config_value("ogp_custom_meta_tags", [], "html")
234-
235-
app.connect("html-page-context", html_page_context)
236-
237-
return {
238-
"parallel_read_safe": True,
239-
"parallel_write_safe": True,
240-
}
127+
return mcv.description

sphinxext/opengraph/titleparser.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from html.parser import HTMLParser
2+
3+
4+
class HTMLTextParser(HTMLParser):
5+
"""
6+
Parse HTML into text
7+
"""
8+
9+
def __init__(self):
10+
super().__init__()
11+
# All text found
12+
self.text = ""
13+
# Only text outside of html tags
14+
self.text_outside_tags = ""
15+
self.level = 0
16+
17+
def handle_starttag(self, tag, attrs) -> None:
18+
self.level += 1
19+
20+
def handle_endtag(self, tag) -> None:
21+
self.level -= 1
22+
23+
def handle_data(self, data) -> None:
24+
self.text += data
25+
if self.level == 0:
26+
self.text_outside_tags += data
27+
28+
29+
def get_title(title: str, skip_html_tags: bool = False):
30+
htp = HTMLTextParser()
31+
htp.feed(title)
32+
htp.close()
33+
34+
if skip_html_tags:
35+
return htp.text_outside_tags
36+
else:
37+
return htp.text

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from sphinx.testing.path import path
21
import pytest
32
from bs4 import BeautifulSoup
3+
from sphinx.testing.path import path
44

55
pytest_plugins = "sphinx.testing.fixtures"
66

0 commit comments

Comments
 (0)