Skip to content

Commit 100711b

Browse files
authored
Merge pull request #7 from apiad/develop
v0.3.0
2 parents cb51bfa + a846325 commit 100711b

File tree

7 files changed

+195
-12
lines changed

7 files changed

+195
-12
lines changed

README.md

+50-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ For example, you can generate an interactive graph that can be modified by movin
1919

2020
**And all of this without writing a single line of HTML or JavaScript.**
2121

22+
Alternatively, if you need little to no Python code, you can author your slideshow in pure Markdown and add some Python sprinkless here and there when necessary.
23+
2224
## Installation
2325

2426
Simply run:
@@ -31,7 +33,7 @@ To see a quick demo run:
3133

3234
And point your browser at [localhost:6789](http://localhost:6789).
3335

34-
## Quick start
36+
## Quick Start - Python First
3537

3638
In `auditorium` you create a presentation via the `Show` class:
3739

@@ -110,6 +112,48 @@ def pyplot():
110112
show.pyplot(plt, fmt='png', height=350)
111113
```
112114

115+
## Quick Start - Markdown First
116+
117+
Alternatively, if you need little to no Python, you can author your slideshow in pure Markdown. Every level-2 header (`##`) becomes a slide.
118+
119+
```markdown
120+
## Static content
121+
122+
Static content can be added with pure markdown.
123+
124+
* Some _markdown_ content.
125+
* More **markdown** content.
126+
```
127+
128+
Pure Markdown can be used as long as all you need is static content. If you need more advanced features, you can add a Python code section anywhere in your slideshow and it will be executed.
129+
130+
```markdown
131+
## Python content
132+
133+
If you need interaction or advanced `auditorium` features,
134+
simply add a code section.
135+
136+
\```python
137+
with show.columns(2) as cl:
138+
text = show.text_input("World")
139+
140+
cl.tab()
141+
142+
with show.success("Message"):
143+
show.markdown(f"Hello {text}")
144+
\```
145+
```
146+
147+
An instance named `show` will be magically available in every Python code section. Beware that **local variables are not persisted** between different code sections. This is a by-design decision to save you a bunch of headaches, believe me.
148+
149+
Once you finished authoring you slideshow, simply run it just like before:
150+
151+
```bash
152+
auditorium run <file.md>
153+
```
154+
155+
If you want to see and example, check [auditorium/static/md/demo.md](auditorium/static/md/demo.md)
156+
113157
## What's the catch
114158

115159
Auditorium covers a fairly simple use case that I haven't seen solved for a long time.
@@ -162,7 +206,11 @@ Staying away from `eval` and `exec` should keep you safe in most scenarios, but
162206

163207
## History
164208

165-
### v0.2.0 (latest release and branch `master`)
209+
### v0.3.0 (latest release and branch `master`)
210+
211+
* Added support for running directly from Markdown files with `auditorium run <file.md>`.
212+
213+
### v0.2.0
166214

167215
* Added command `auditorium run <file.py>` for running a specific slideshow. This is now the preferred method.
168216
* Added command `auditorium demo` for running the demo.

auditorium/__main__.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@
33
import fire
44
import runpy
55

6+
from auditorium.markdown import MarkdownLoader
7+
68

79
class Auditorium:
810
@staticmethod
911
def run(path, host='localhost', port=6789, debug=False, instance_name='show'):
1012
"Runs a custom Python script as a slideshow."
1113

12-
ns = runpy.run_path(path)
13-
show = ns[instance_name]
14+
if path.endswith('.py'):
15+
ns = runpy.run_path(path)
16+
show = ns[instance_name]
17+
elif path.endswith('.md'):
18+
loader = MarkdownLoader(path, instance_name=instance_name)
19+
show = loader.parse()
20+
1421
show.run(host=host, port=port, debug=debug)
1522

1623
@staticmethod

auditorium/markdown.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# coding: utf8
2+
3+
from auditorium import Show
4+
5+
6+
class MarkdownLoader:
7+
def __init__(self, path, instance_name='show'):
8+
self.path = path
9+
self.instance_name = instance_name
10+
11+
def parse(self):
12+
slides = []
13+
current_slide = []
14+
15+
with open(self.path) as fp:
16+
for line in fp:
17+
line = line.strip("\n")
18+
19+
if line.startswith("## ") and current_slide:
20+
slides.append(current_slide)
21+
current_slide = []
22+
23+
current_slide.append(line)
24+
25+
if current_slide:
26+
slides.append(current_slide)
27+
28+
show = Show()
29+
30+
for i, slide in enumerate(slides):
31+
show.slide(func=MarkdownSlide(show, slide), id='slide-%i' % (i+1))
32+
33+
return show
34+
35+
36+
class MarkdownSlide:
37+
def __init__(self, show: Show, content):
38+
self.show = show
39+
self.content = []
40+
41+
state = 'markdown' # or 'code'
42+
split = []
43+
44+
for line in content:
45+
if state == 'markdown':
46+
if line.startswith('```python'):
47+
if split:
48+
self.content.append(MarkdownContent(split))
49+
50+
split = []
51+
state = 'code'
52+
else:
53+
split.append(line)
54+
55+
elif state == 'code':
56+
if line.startswith('```'):
57+
if split:
58+
self.content.append(PythonContent(split))
59+
60+
split = []
61+
state = 'markdown'
62+
else:
63+
split.append(line)
64+
65+
if split:
66+
if state == 'markdown':
67+
self.content.append(MarkdownContent(split))
68+
else:
69+
raise ValueError("Didn't closed a Python line...")
70+
71+
def __call__(self):
72+
for content in self.content:
73+
content(self.show)
74+
75+
76+
class MarkdownContent:
77+
def __init__(self, lines):
78+
self.lines = "\n".join(lines)
79+
80+
def __call__(self, show):
81+
show.markdown(self.lines)
82+
83+
84+
class PythonContent:
85+
def __init__(self, lines):
86+
self.lines = "\n".join(lines)
87+
88+
def __call__(self, show):
89+
exec(self.lines, dict(show=show), dict())

auditorium/show.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,21 @@ def show_title(self):
4646

4747
## @slide decorator
4848

49-
def slide(self, func):
50-
self.slide_ids.append(func.__name__)
51-
self.slides[func.__name__] = func
52-
return func
49+
def slide(self, func=None, id=None):
50+
if func is not None:
51+
slide_id = id or func.__name__
52+
self.slide_ids.append(slide_id)
53+
self.slides[slide_id] = func
54+
return func
55+
56+
elif id is not None:
57+
def wrapper(func):
58+
slide_id = id or func.__name__
59+
self.slide_ids.append(slide_id)
60+
self.slides[slide_id] = func
61+
return func
62+
63+
return wrapper
5364

5465
## Binding methods
5566

auditorium/static/md/demo.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Auditorium
2+
3+
### A demo for the "pure markdown" mode
4+
5+
## Static content
6+
7+
Static content can be added with pure markdown.
8+
9+
* Some _markdown_ content.
10+
* More **markdown** content.
11+
12+
## And some Python
13+
14+
If you need interaction or advanced `auditorium` features,
15+
simply add a code section.
16+
17+
```python
18+
with show.columns(2) as cl:
19+
text = show.text_input("World")
20+
21+
cl.tab()
22+
23+
with show.success("Message"):
24+
show.markdown(f"Hello {text}")
25+
```
26+
27+
An instance named `show` will be magically available.

auditorium/utils.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
def fix_indent(content, tab_size=0):
55
lines = content.split("\n")
6-
min_indent = 1e50
6+
min_indent = 1000
77

88
for l in lines:
99
if not l or l.isspace():
@@ -19,9 +19,10 @@ def fix_indent(content, tab_size=0):
1919

2020
min_indent = min(indent_size, min_indent)
2121

22-
lines = [" " * tab_size + l[min_indent:] for l in lines]
22+
if min_indent < 10000:
23+
lines = [" " * tab_size + l[min_indent:] for l in lines]
2324

24-
while lines and not lines[0] or lines[0].isspace():
25+
while lines and (not lines[0] or lines[0].isspace()):
2526
lines.pop(0)
2627

2728
return "\n".join(lines)

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
# TODO: Update version whenever changes
8-
VERSION = '0.2.0'
8+
VERSION = '0.3.0'
99

1010

1111
def get_install_requirements():

0 commit comments

Comments
 (0)