sphinxcontrib-screenshot 0.1.4__py3-none-any.whl → 0.2.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.
@@ -24,7 +24,7 @@ from urllib.parse import urlparse
24
24
 
25
25
  from docutils import nodes
26
26
  from docutils.parsers.rst import directives
27
- from docutils.statemachine import ViewList
27
+ from docutils.parsers.rst.directives.images import Figure
28
28
  from playwright._impl._helper import ColorScheme
29
29
  from playwright.sync_api import Browser, BrowserContext
30
30
  from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
@@ -40,8 +40,11 @@ Meta = typing.TypedDict('Meta', {
40
40
  'parallel_write_safe': bool
41
41
  })
42
42
 
43
+ ContextBuilder = typing.Optional[typing.Callable[[Browser, str, str],
44
+ BrowserContext]]
43
45
 
44
- class ScreenshotDirective(SphinxDirective):
46
+
47
+ class ScreenshotDirective(SphinxDirective, Figure):
45
48
  """Sphinx Screenshot Dirctive.
46
49
 
47
50
  This directive embeds a screenshot of a webpage.
@@ -54,20 +57,13 @@ class ScreenshotDirective(SphinxDirective):
54
57
  .. screenshot:: http://www.example.com
55
58
  ```
56
59
 
57
- You can also specify the screen size for the screenshot with `width` and
58
- `height` parameters in pixel.
60
+ You can also specify the screen size for the screenshot with
61
+ `viewport-width` and `viewport-height` parameters in pixel.
59
62
 
60
63
  ```rst
61
64
  .. screenshot:: http://www.example.com
62
- :width: 1280
63
- :height: 960
64
- ```
65
-
66
- You can include a caption for the screenshot's `figure` directive.
67
-
68
- ```rst
69
- .. screenshot:: http://www.example.com
70
- :caption: This is a screenshot for www.example.com
65
+ :viewport-width: 1280
66
+ :viewport-height: 960
71
67
  ```
72
68
 
73
69
  You can describe the interaction that you want to have with the webpage
@@ -79,52 +75,65 @@ class ScreenshotDirective(SphinxDirective):
79
75
  document.querySelector('button').click();
80
76
  ```
81
77
 
82
- Use `figclass` option if you want to specify a class name to the image.
78
+ It also generates a PDF file when `pdf` option is given, which might be
79
+ useful when you need scalable image assets.
83
80
 
84
81
  ```rst
85
82
  .. screenshot:: http://www.example.com
86
- :figclass: foo
83
+ :pdf:
87
84
  ```
88
85
 
89
- It also generates a PDF file when `pdf` option is given, which might be
90
- useful when you need scalable image assets.
86
+ You can take a screenshot of a local file using a root-relative path.
91
87
 
92
88
  ```rst
93
- .. screenshot:: http://www.example.com
94
- :pdf:
89
+ .. screenshot:: /static/example.html
90
+ ```
91
+
92
+ Or you can use a document-relative path.
93
+
94
+ ```rst
95
+ .. screenshot:: ./example.html
95
96
  ```
97
+
98
+ The `file://` protocol is also supported.
99
+
100
+ ```rst
101
+ .. screenshot:: file:///path/to/your/file.html
102
+ ```
96
103
  """
97
104
 
98
105
  required_arguments = 1 # URL
99
- has_content = True
100
106
  option_spec = {
107
+ **Figure.option_spec,
101
108
  'browser': str,
102
- 'height': directives.positive_int,
103
- 'width': directives.positive_int,
104
- 'caption': directives.unchanged,
105
- 'figclass': directives.unchanged,
109
+ 'viewport-height': directives.positive_int,
110
+ 'viewport-width': directives.positive_int,
111
+ 'interactions': str,
106
112
  'pdf': directives.flag,
107
113
  'color-scheme': str,
108
114
  'full-page': directives.flag,
109
115
  'context': str,
110
116
  'headers': directives.unchanged,
117
+ 'locale': str,
118
+ 'timezone': str,
111
119
  }
112
120
  pool = ThreadPoolExecutor()
113
121
 
114
122
  @staticmethod
115
- def take_screenshot(
116
- url: str, browser_name: str, width: int, height: int, filepath: str,
117
- init_script: str, interactions: str, generate_pdf: bool,
118
- color_scheme: ColorScheme, full_page: bool,
119
- context_builder: typing.Optional[typing.Callable[[Browser, str, str],
120
- BrowserContext]],
121
- headers: dict):
123
+ def take_screenshot(url: str, browser_name: str, viewport_width: int,
124
+ viewport_height: int, filepath: str, init_script: str,
125
+ interactions: str, generate_pdf: bool,
126
+ color_scheme: ColorScheme, full_page: bool,
127
+ context_builder: ContextBuilder, headers: dict,
128
+ locale: typing.Optional[str],
129
+ timezone: typing.Optional[str]):
122
130
  """Takes a screenshot with Playwright's Chromium browser.
123
131
 
124
132
  Args:
125
133
  url (str): The HTTP/HTTPS URL of the webpage to screenshot.
126
- width (int): The width of the screenshot in pixels.
127
- height (int): The height of the screenshot in pixels.
134
+ browser_name (str): Browser to use ('chromium', 'firefox' or 'webkit').
135
+ viewport_width (int): The width of the screenshot in pixels.
136
+ viewport_height (int): The height of the screenshot in pixels.
128
137
  filepath (str): The path to save the screenshot to.
129
138
  init_script (str): JavaScript code to be evaluated after the document
130
139
  was created but before any of its scripts were run. See more details at
@@ -133,10 +142,14 @@ class ScreenshotDirective(SphinxDirective):
133
142
  after the page was loaded.
134
143
  generate_pdf (bool): Generate a PDF file along with the screenshot.
135
144
  color_scheme (str): The preferred color scheme. Can be 'light' or 'dark'.
145
+ full_page (bool): Take a full page screenshot.
136
146
  context: A method to build the Playwright context.
147
+ headers (dict): Custom request header.
148
+ locale (str, optional): User locale for the request.
149
+ timezone (str, optional): User timezone for the request.
137
150
  """
138
151
  with sync_playwright() as playwright:
139
- browser = getattr(playwright, browser_name).launch()
152
+ browser: Browser = getattr(playwright, browser_name).launch()
140
153
 
141
154
  if context_builder:
142
155
  try:
@@ -146,11 +159,15 @@ class ScreenshotDirective(SphinxDirective):
146
159
  'Timeout error occured at %s in executing py init script %s' %
147
160
  (url, context_builder.__name__))
148
161
  else:
149
- context = browser.new_context(color_scheme=color_scheme)
162
+ context = browser.new_context(
163
+ color_scheme=color_scheme, locale=locale, timezone_id=timezone)
150
164
 
151
165
  page = context.new_page()
152
166
  page.set_default_timeout(10000)
153
- page.set_viewport_size({'width': width, 'height': height})
167
+ page.set_viewport_size({
168
+ 'width': viewport_width,
169
+ 'height': viewport_height
170
+ })
154
171
 
155
172
  try:
156
173
  if init_script:
@@ -170,7 +187,10 @@ class ScreenshotDirective(SphinxDirective):
170
187
  if generate_pdf:
171
188
  page.emulate_media(media='screen')
172
189
  root, ext = os.path.splitext(filepath)
173
- page.pdf(width=f'{width}px', height=f'{height}px', path=root + '.pdf')
190
+ page.pdf(
191
+ width=f'{viewport_width}px',
192
+ height=f'{viewport_height}px',
193
+ path=root + '.pdf')
174
194
  page.close()
175
195
  browser.close()
176
196
 
@@ -180,30 +200,52 @@ class ScreenshotDirective(SphinxDirective):
180
200
  text = text.replace(f"|{key}|", value.astext())
181
201
  return text
182
202
 
183
- def run(self) -> typing.List[nodes.Node]:
203
+ def run(self) -> typing.Sequence[nodes.Node]:
184
204
  screenshot_init_script: str = self.env.config.screenshot_init_script or ''
205
+ docdir = os.path.dirname(self.env.doc2path(self.env.docname))
185
206
 
186
207
  # Ensure the screenshots directory exists
187
208
  ss_dirpath = os.path.join(self.env.app.outdir, '_static', 'screenshots')
188
209
  os.makedirs(ss_dirpath, exist_ok=True)
189
210
 
190
211
  # Parse parameters
191
- raw_url = self.arguments[0]
192
- url = self.evaluate_substitutions(raw_url)
212
+ raw_path = self.arguments[0]
213
+ url_or_filepath = self.evaluate_substitutions(raw_path)
214
+
215
+ # Check if the path is a local file path.
216
+ if urlparse(url_or_filepath).scheme == '':
217
+ # root-relative path
218
+ if url_or_filepath.startswith('/'):
219
+ url_or_filepath = os.path.join(self.env.srcdir,
220
+ url_or_filepath.lstrip('/'))
221
+ # document-relative path
222
+ else:
223
+ url_or_filepath = os.path.join(docdir, url_or_filepath)
224
+ url_or_filepath = "file://" + os.path.normpath(url_or_filepath)
225
+
226
+ if urlparse(url_or_filepath).scheme not in {'http', 'https', 'file'}:
227
+ raise RuntimeError(
228
+ f'Invalid URL: {url_or_filepath}. ' +
229
+ 'Only HTTP/HTTPS/FILE URLs or root/document-relative file paths ' +
230
+ 'are supported.')
231
+
232
+ interactions = self.options.get('interactions', '')
193
233
  browser = self.options.get('browser',
194
234
  self.env.config.screenshot_default_browser)
195
- height = self.options.get('height',
196
- self.env.config.screenshot_default_height)
197
- width = self.options.get('width', self.env.config.screenshot_default_width)
235
+ viewport_height = self.options.get(
236
+ 'viewport-height', self.env.config.screenshot_default_viewport_height)
237
+ viewport_width = self.options.get(
238
+ 'viewport-width', self.env.config.screenshot_default_viewport_width)
198
239
  color_scheme = self.options.get(
199
240
  'color-scheme', self.env.config.screenshot_default_color_scheme)
200
- caption_text = self.options.get('caption', '')
201
- figclass = self.options.get('figclass', '')
202
241
  pdf = 'pdf' in self.options
203
242
  full_page = ('full-page' in self.options or
204
243
  self.env.config.screenshot_default_full_page)
244
+ locale = self.options.get('locale',
245
+ self.env.config.screenshot_default_locale)
246
+ timezone = self.options.get('timezone',
247
+ self.env.config.screenshot_default_timezone)
205
248
  context = self.options.get('context', '')
206
- interactions = '\n'.join(self.content)
207
249
  headers = self.options.get('headers', '')
208
250
 
209
251
  request_headers = {**self.env.config.screenshot_default_headers}
@@ -212,15 +254,11 @@ class ScreenshotDirective(SphinxDirective):
212
254
  name, value = header.split(" ", 1)
213
255
  request_headers[name] = value
214
256
 
215
- if urlparse(url).scheme not in {'http', 'https'}:
216
- raise RuntimeError(
217
- f'Invalid URL: {url}. Only HTTP/HTTPS URLs are supported.')
218
-
219
257
  # Generate filename based on hash of parameters
220
258
  hash_input = "_".join([
221
- raw_url, browser,
222
- str(height),
223
- str(width), color_scheme, context, interactions,
259
+ raw_path, browser,
260
+ str(viewport_height),
261
+ str(viewport_width), color_scheme, context, interactions,
224
262
  str(full_page)
225
263
  ])
226
264
  filename = hashlib.md5(hash_input.encode()).hexdigest() + '.png'
@@ -234,30 +272,20 @@ class ScreenshotDirective(SphinxDirective):
234
272
 
235
273
  # Check if the file already exists. If not, take a screenshot
236
274
  if not os.path.exists(filepath):
237
- fut = self.pool.submit(ScreenshotDirective.take_screenshot, url, browser,
238
- width, height, filepath, screenshot_init_script,
275
+ fut = self.pool.submit(ScreenshotDirective.take_screenshot,
276
+ url_or_filepath, browser, viewport_width,
277
+ viewport_height, filepath, screenshot_init_script,
239
278
  interactions, pdf, color_scheme, full_page,
240
- context_builder, request_headers)
279
+ context_builder, request_headers, locale,
280
+ timezone)
241
281
  fut.result()
242
282
 
243
283
  # Create image and figure nodes
244
- docdir = os.path.dirname(self.env.doc2path(self.env.docname))
245
284
  rel_ss_dirpath = os.path.relpath(ss_dirpath, start=docdir)
246
285
  rel_filepath = os.path.join(rel_ss_dirpath, filename).replace(os.sep, '/')
247
- image_node = nodes.image(uri=rel_filepath)
248
- figure_node = nodes.figure('', image_node)
249
-
250
- if figclass:
251
- figure_node['classes'].append(figclass)
252
-
253
- if caption_text:
254
- parsed = nodes.Element()
255
- self.state.nested_parse(
256
- ViewList([caption_text], source=''), self.content_offset, parsed)
257
- figure_node += nodes.caption(parsed[0].source or '', '',
258
- *parsed[0].children)
259
286
 
260
- return [figure_node]
287
+ self.arguments[0] = rel_filepath
288
+ return super().run()
261
289
 
262
290
 
263
291
  app_threads = {}
@@ -298,12 +326,12 @@ def setup(app: Sphinx) -> Meta:
298
326
  app.add_directive('screenshot', ScreenshotDirective)
299
327
  app.add_config_value('screenshot_init_script', '', 'env')
300
328
  app.add_config_value(
301
- 'screenshot_default_width',
329
+ 'screenshot_default_viewport_width',
302
330
  1280,
303
331
  'env',
304
332
  description="The default width for screenshots")
305
333
  app.add_config_value(
306
- 'screenshot_default_height',
334
+ 'screenshot_default_viewport_height',
307
335
  960,
308
336
  'env',
309
337
  description="The default height for screenshots")
@@ -331,6 +359,16 @@ def setup(app: Sphinx) -> Meta:
331
359
  'screenshot_default_headers', {},
332
360
  'env',
333
361
  description="The default headers to pass in requests")
362
+ app.add_config_value(
363
+ 'screenshot_default_locale',
364
+ None,
365
+ 'env',
366
+ description="The default locale in requests")
367
+ app.add_config_value(
368
+ 'screenshot_default_timezone',
369
+ None,
370
+ 'env',
371
+ description="The default timezone in requests")
334
372
  app.add_config_value(
335
373
  'screenshot_apps', {},
336
374
  'env',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sphinxcontrib-screenshot
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: A Sphinx extension to embed webpage screenshots.
5
5
  Author-email: Shuhei Iitsuka <tushuhei@gmail.com>
6
6
  License: Apache-2.0
@@ -53,8 +53,8 @@ A Sphinx extension to embed website screenshots.
53
53
  ```rst
54
54
  .. screenshot:: http://www.example.com
55
55
  :browser: chromium
56
- :width: 1280
57
- :height: 960
56
+ :viewport-width: 1280
57
+ :viewport-height: 960
58
58
  :color-scheme: dark
59
59
  ```
60
60
 
@@ -0,0 +1,6 @@
1
+ sphinxcontrib/screenshot.py,sha256=xkhT956Abup3BeRe6JyIL_ZauhjFTdNh0Mf17CGN6iA,13419
2
+ sphinxcontrib_screenshot-0.2.1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
3
+ sphinxcontrib_screenshot-0.2.1.dist-info/METADATA,sha256=MvhMPcvnqB0sCgRJSx3tVAxeXShwlcJh-sbdUVYOgU0,2868
4
+ sphinxcontrib_screenshot-0.2.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
+ sphinxcontrib_screenshot-0.2.1.dist-info/top_level.txt,sha256=VJrV3_vaiKQVgVpR0I1iecxoO0drzGu-M0j40PVP2QQ,14
6
+ sphinxcontrib_screenshot-0.2.1.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- sphinxcontrib/screenshot.py,sha256=eJEF1qfGGo1uwyTovYHXx4Ewz2fXmrxDSsQSdLJ0O-0,11863
2
- sphinxcontrib_screenshot-0.1.4.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
3
- sphinxcontrib_screenshot-0.1.4.dist-info/METADATA,sha256=XpzmVDGTDfL-AxKUv7jIV3wQ_phEGc-OLxWU-wG7-o0,2850
4
- sphinxcontrib_screenshot-0.1.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
- sphinxcontrib_screenshot-0.1.4.dist-info/top_level.txt,sha256=VJrV3_vaiKQVgVpR0I1iecxoO0drzGu-M0j40PVP2QQ,14
6
- sphinxcontrib_screenshot-0.1.4.dist-info/RECORD,,