11#!/usr/bin/env python3
22
3+ import json
34import os
45import re
5- import json
6- import shutil
7- from itertools import chain
8- from pathlib import Path , PurePosixPath
96from base64 import b64decode
10- from typing import Dict , List , Union , Optional
7+ from pathlib import Path
8+ from typing import Dict , List , Optional , Union
119
1210import pypandoc
1311
1412CWD = Path (os .path .dirname (os .path .realpath (__file__ )))
1513REPO_ROOT = CWD .parent
1614
17- MATCH_AUTHOR_FILE = re .compile (r"\.{2} +bio:{2} +(?P<name>[\w '\-]+)\n+ *(:photo:)? *(?P<profile_picture>.*\.[a-zA-Z0-9]+)?\n+ *(?P<bio>.*)" ,
18- flags = re .M | re .S )
1915
20- AUTHORS = {
21- "link-dir " : PurePosixPath ( "../ _static/authors" ) ,
22- "save-dir " : REPO_ROOT / "_static" / "authors "
16+ DIRS = {
17+ "demo_images " : REPO_ROOT / " _static" / "demonstration_assets" ,
18+ "demo " : REPO_ROOT / "demonstrations_v2 "
2319}
24- DEMO = {
25- "link-dir" : PurePosixPath ("../demonstrations" ),
26- "save-dir" : REPO_ROOT / "demonstrations"
27- }
28-
29-
30- def format_author_name (name : str ) -> str :
31- return re .sub (r"[ \-'\u0080-\uFFFF]+" , "_" , name ).lower ()
32-
33- def parse_author_file (author_file_path : Union [Path , str ]) -> Optional [Dict ]:
34- author_file_loc = Path (author_file_path )
35- author_file_name = author_file_loc .stem
36- with author_file_loc .open () as fh :
37- content = fh .read ()
38-
39- m = MATCH_AUTHOR_FILE .match (content )
40- if not m :
41- return None
42-
43- profile_picture_path = m .group ("profile_picture" )
44- if profile_picture_path :
45- profile_picture_path = Path (profile_picture_path )
46- if not profile_picture_path .is_absolute ():
47- if profile_picture_path .is_relative_to (AUTHORS ["link-dir" ]):
48- profile_picture_path = (REPO_ROOT / "_static" / profile_picture_path ).resolve ()
49- else :
50- profile_picture_path = (author_file_loc .parent / profile_picture_path ).resolve ()
51- else :
52- profile_picture_path = None
53- return {
54- "name" : m .group ("name" ),
55- "bio" : m .group ("bio" ),
56- "profile_picture" : profile_picture_path ,
57- "formatted_name" : format_author_name (author_file_name )
58- }
59-
60-
61- def set_author_info (author : Dict ) -> Path :
62- """
63-
64- :param author: A dictionary of author info with the following syntax
65- {
66- "name": Author Name,
67- "bio": Author Info,
68- "profile_picture": /path/to/profile_picture.png,
69- "formatted_name": "<Optional> Author name"
70- }
71- :return: Path object of the file that was saved and author info txt
72- """
73- name = author ["name" ]
74- bio = author .get ("bio" , "" ).strip ()
75- profile_picture_loc = author .get ("profile_picture" )
76- if profile_picture_loc :
77- profile_picture_loc = Path (profile_picture_loc )
78- name_formatted = author .get ("name_formatted" , profile_picture_loc .stem if profile_picture_loc else format_author_name (name )).lower ()
79-
80- if profile_picture_loc :
81- new_profile_picture_save_loc = AUTHORS ["save-dir" ] / profile_picture_loc .name
82- else :
83- new_profile_picture_save_loc = None
84-
85- info_file_name = f"{ name_formatted } .txt"
86- info_file_save_loc = AUTHORS ["save-dir" ] / info_file_name
87-
88- if profile_picture_loc :
89- try :
90- shutil .copy (profile_picture_loc , new_profile_picture_save_loc )
91- except shutil .SameFileError :
92- pass
93-
94- if profile_picture_loc :
95- author_link = (AUTHORS ["link-dir" ] / profile_picture_loc .name ).as_posix ()
96- photo_text = f":photo: { author_link } "
97- else :
98- photo_text = ""
99- author_txts = [f".. bio:: { name } " ]
100- if photo_text :
101- author_txts .append (f" { photo_text } " )
102- if bio :
103- if photo_text :
104- author_txts .append ("" )
105- author_txts .append (f" { bio } " )
106- author_txt = "\n " .join (author_txts )
107-
108- with info_file_save_loc .open ("w" ) as fh :
109- fh .write (author_txt )
110-
111- return info_file_save_loc
112-
113- def set_authors (* authors : Dict ) -> str :
114- """
115- :param authors: An unpacked list of dictionaries, each one having the following schema:
116- {
117- "name": Author Name,
118- "bio": Author Info,
119- "profile_picture": /path/to/profile_picture.png,
120- "formatted_name": "<Optional> Author name"
121- }
122- :return:
123- """
124- author_files = [
125- AUTHORS ['link-dir' ] / set_author_info (author ).name
126- for author in authors
127- ]
128-
129- header = [
130- "About the author" ,
131- "----------------"
132- ]
133- author_txts = [
134- f"# .. include:: { author_txt_link } \n "
135- for author_txt_link in author_files
136- ]
137-
138- author_sphinx_txt = "\n " .join ([f"# { line } " for line in chain (header , author_txts )])
139- return f"\n \n { '#' * 70 } \n { author_sphinx_txt } "
14020
14121def str_to_bool (s : str ) -> Optional [bool ]:
14222 if isinstance (s , bool ):
@@ -177,7 +57,7 @@ def add_property_newline(rst: str) -> str:
17757 return re .sub (r"(\w+) (:property=)" , r"\1\n \2" , rst )
17858
17959
180- def generate_code_output_block (output_source : List [str ] = None , only_header : bool = False ) -> str :
60+ def generate_code_output_block (output_source : Optional [ List [str ] ] = None , only_header : bool = False ) -> str :
18161 output_header = "\n " .join (
18262 [
18363 f"# { line } "
@@ -215,6 +95,7 @@ def fix_image_alt_tag_as_text(rst: str) -> str:
21595def convert_notebook_to_python (
21696 notebook : Dict ,
21797 notebook_name : str ,
98+ assets_folder_name : str ,
21899 is_executable : bool
219100) -> str :
220101 # Initial validations
@@ -259,7 +140,7 @@ def convert_notebook_to_python(
259140 output_data ["text/plain" ], only_header = j != 0
260141 )
261142 elif output ["output_type" ] == "display_data" :
262- cell_id = cell [ "id" ]
143+ cell_id = cell . get ( "id" , f"c_ { i } " )
263144 if "text/plain" in output_data and "image/png" not in output_data :
264145 if j == 0 :
265146 ret_python_str += generate_code_output_block ()
@@ -272,11 +153,11 @@ def convert_notebook_to_python(
272153 ret_python_str += f"\n \n { '#' * 70 } "
273154 num_images += 1
274155 image_filename = f"{ notebook_name } _{ cell_id } _{ num_images } .png"
275- image_file_dir = DEMO [ "save-dir " ] / notebook_assets_folder_name
156+ image_file_dir = DIRS [ "demo_images " ] / assets_folder_name
276157 image_file_path = (
277158 image_file_dir / image_filename
278159 )
279- image_file_link_path = DEMO [ "link-dir" ] / notebook_assets_folder_name / image_filename
160+ image_file_link_path = Path ( "../_static/demonstration_assets" ) / assets_folder_name / image_filename
280161 role_text = generate_sphinx_role_comment (
281162 "figure" , image_file_link_path .as_posix (), align = "center" , width = "80%"
282163 )
@@ -315,14 +196,6 @@ def convert_notebook_to_python(
315196 default = None
316197 )
317198
318- parser .add_argument ("--author" ,
319- help = "Information about Demo Author, must be in format \" Name\" \" Bio\" \" /path/to/profile_picture.png\" " ,
320- action = "append" ,
321- nargs = 3 )
322- parser .add_argument ("--author-file" ,
323- help = "Path to an existing author file that is formatted with sphinx roles" ,
324- action = "append" )
325-
326199 results = parser .parse_args ()
327200
328201 notebook_file = Path (results .notebook )
@@ -337,36 +210,17 @@ def convert_notebook_to_python(
337210 with notebook_file .open () as fh :
338211 nb = json .load (fh )
339212
340- authors = []
341- cli_authors = results .author or []
342- cli_authors_files = results .author_file or []
343- for author_file in cli_authors_files :
344- author_info = parse_author_file (author_file )
345- if author_info is None :
346- raise ValueError (f"Unable to parse author file { author_file } " )
347- authors .append (author_info )
348- for author_info in cli_authors :
349- name = author_info [0 ]
350- bio = author_info [1 ]
351- profile_picture = author_info [2 ]
352- formatted_name = format_author_name (name )
353- authors .append ({
354- "name" : name ,
355- "bio" : bio ,
356- "profile_picture" : profile_picture ,
357- "formatted_name" : formatted_name
358- })
359-
360213 nb_py = convert_notebook_to_python (
361214 nb ,
362215 notebook_file_name ,
216+ notebook_assets_folder_name ,
363217 notebook_is_executable
364218 )
219+
220+ demo_dir = DIRS ["demo" ] / notebook_file_name
221+ if not demo_dir .exists ():
222+ demo_dir .mkdir (parents = True )
365223
366- if authors :
367- author_sphinx = set_authors (* authors )
368- nb_py += author_sphinx
369-
370- with (DEMO ["save-dir" ] / f"{ notebook_file_name } .py" ).open ("w" ) as fh :
224+ with (demo_dir / "demo.py" ).open ("w" ) as fh :
371225 fh .write (nb_py )
372226
0 commit comments