-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MarkdownAIO #82
MarkdownAIO #82
Conversation
� Conflicts: � dash_labs/plugins/pages.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking awesome! several small changes requested. once those are made, i'll take a deeper look at the docs 🙂
dash_labs/dashdown.py
Outdated
|
||
- `exec_code` (boolean; default False): | ||
If `True`, code blocks will be executed. This may also be set within the code block with the comment | ||
# exec-code-true or # exec-code-false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
describe where this comment should exist. perhaps include a full example with the triple backticks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can actually be anywhere in the code block on a comment line. It's just that the prop won't be won't be displayed if it's included on the first line with the back ticks. Since there are 7 props that this applies to, maybe it would be better to have the full example in the docs instead of here.
Co-authored-by: Chris Parmer <[email protected]>
Co-authored-by: Chris Parmer <[email protected]>
# Conflicts: # dash_labs/dashdown.py
fix clipboard id
side_by_side: True | ||
--- | ||
""" | ||
import frontmatter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was curious to see how this library parsed YAML, given my exec
/ eval
concerns when writing the code fence parser.
It looks like frontmatter depends on PyYAML's safe mode: https://github.com/eyeseast/python-frontmatter/blob/1c49958fdd504691fc842045425ea298316aa643/frontmatter/default_handlers.py#L224-L228
So then looking into PyYAML, I see some stuff like:
Note that the ability to construct an arbitrary Python object may be dangerous if you receive a YAML document from an untrusted source such as the Internet. The function yaml.safe_load limits this ability to simple Python objects like integers or lists.
from https://pyyaml.org/wiki/PyYAMLDocumentation
Then googled around yaml.safe_load
and came across yaml/pyyaml#420
They fixed the issue which is great but the fact that an issue happened in the first place makes me feel a little concerned that there could be more issues lurking in that library.
So I might consider supporting a smaller subset of the YAML library and doing our own parsing with JSON, similar to what we did with the code fences.
I'll keep thinking a bit about this
dash_labs/plugins/pages.py
Outdated
@@ -401,6 +438,7 @@ def interpolate_index(**kwargs): | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might want to put this in the stylesheet that we document
dash_labs/dashdown.py
Outdated
if "app.layout" in code: | ||
code = code.replace("app.layout", "layout") | ||
if "layout" in code: | ||
exec(code, scope) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm feeling like we should lock this down a bit more and exclude folks from using exec within callbacks.
for users, this means:
MarkdownAIO
can only be called outside of callbacks, meaning when the app starts up- All of the
MarkdownAIO
files would need to be written in advance of the app starting up
so this wouldn't be allowed:
pages/report.py
dash.register_page(__name__)
def layout():
return MarkdownAIO('report.md', exec_code=True)
But this would be allowed:
pages/report.py
dash.register_page(__name__)
layout = MarkdownAIO('report.md', exec_code=True)
I can't think of many examples where this would be insufficient and it would prevent users from seemingly innocent but very insecure code like:
template_report.md
# Report for {customer}
`` `python
dcc.Graph(figure=px.scatter(...))
`` `
app.py
app.layout = html.Div([
dcc.Dropdown(id='customer', options=['Acme', 'City']),
html.Div(id='content')
])
@callback(Output('content', 'children'), Input('customer', 'value'))
def update(customer):
with open('template_report.md', 'r') as f:
content = f.read()
customer_report = content.replace(customer=customer)
with open('customer_report.md', 'w') as f:
f.write(customer_report)
return MarkdownAIO('customer_report.md', exec_code=True)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way to prevent exec from running in a callback would be to do:
def _exec(*args, **kwargs):
# flask raises an error if flask.request.path is called outside of a request
try:
flask.request.path
except RuntimeError as e:
raise Exception('MarkdownAIO is being called with `exec_code=True` within a callback or flask request. This isn\'t supported. MarkdownAIO with exec can only be called when the app is starting')
return exec(*args, **kwargs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I tried this it prevented all exec
s in the app. Checking for flask.has_request_context()
worked though.
Will this be overly restrictive with a multi-page app using path variables and query strings? Also, many pages are functions even if there are no variables passed to the layout.
Update: This only works if it's called from a .py
file. If the MarkdownAIO
is inside a callback in a .md
file, then
the flask.has_request_context()
is False
new format for props in code blocks use ast to remove app instance
removed dbc dependency
Updated docs
…ownAIO � Conflicts: � dash_labs/__init__.py � dash_labs/plugins/pages.py � dash_labs/util.py � dash_labs/version.py � docs/demos/multi_page_basics/pages/path_variables.py
This was a cool project but did't make it across the finish line because there were concerns about executing the code securely. There are some other community project that are good for project that are a mix of code and markdown text. See: https://github.com/snehilvj/markdown2dash |
Adds the new component
MarkdownAIO
See the live demo
MarkdownAIO
is a Dash feature that allows you to write Dash Apps as Markdown files. Simply pass in a Markdown file andMarkdownAIO
will return a set of components with the option to display and/or execute code blocks. So it’s part:It's also compatible with the
pages/
api. The online docs for dash-labs is a multi-page app made withpages/
and each page is a Markdown file displayed usingMarkdownAIO
.Here is a summary of the TODOs and questions:
To further reduce security risk with
exec
, check for local files only. Ensure that the file is within a certain directory, and by default that should be the parent directory of the main app but maybe we could create a way to override that. Similar to /assets?Update - require full path from pages/
css:
Status: inprogress
see todos in
pages.py
in_register_page_from_markdown_file()
[x ] use UUID for clipboard ID?
add ability to change defaults "globally" so it doesn't have to be done for each
MarkdownAIO()
instance.add ability to embed another file within the Markdown file. Use case being, ability to keep the python app code in a separate file so you can run it individually. We could integrate jinja in here perhaps…: {% include code.py %}
Add Markdown files to hot reload in dash. That way users can have the same hot-reloading dev experience when working in markdown
if code block is not executed don't register callbacks and layout? Goal it to reduce the number of
id
clashes.Need to remove
if __name__ == "__main__": ...
from the code blocks?refactor
_update_props()
(It works, but it's kinda ugly)rewrite the
_remove_app_instance()
to use the AST module