Giter Club home page Giter Club logo

handout's Introduction

Python Handout

PyPI

Turn Python scripts into handouts with Markdown comments and inline figures. An alternative to Jupyter notebooks without hidden state that supports any text editor.

Code Handout
Code Handout

Getting started

You use Python Handout as a library inside a normal Python program:

  1. Install via pip3 install -U handout.
  2. Run your script via python3 script.py. (You can start with examples/start.py from the repository.)
  3. Open output/index.html in your browser to view the result.
  4. Iterate and refresh your browser.

Features

Create the handout via doc = handout.Handout(outdir) to access these features:

Feature Example
Add Markdown text as triple-quote comments. """Markdown text"""
Add text via print() syntax. doc.add_text('text:', variable)
Add image from array or url. doc.add_image(image, 'png', width=1)
Add video from array or url. doc.add_video(video, 'gif', fps=30, width=1)
Add matplotlib figure. doc.add_figure(fig, width=1)
Add custom HTML. doc.add_html(string)
Insert added items and save to <outdir>/index.html. doc.show()

Questions

Feel free to create an issue on Github.

handout's People

Contributors

danijar avatar epogrebnyak avatar jvicentem avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

handout's Issues

Comparison to Jupyter notebooks

could you provide more clarification on without hidden state that supports any text editor as written in handout's README?

Add contributing instructions

Recommended by user unbalancedparen on Twitter. We should add a CONTRIBUTING.md to the repository and roughly states:

  • Contributions are welcome
  • Check out the Github issues and join the discussions
  • Comment on an issue with "help wanted" tag to discuss potential solutions
  • Implement the feature and send a PR
  • The is a discussion tag that can be used for discussion features or meta discussions (this acts as our forum/slack channel)

Anything else I should mention?

Possible to hide some code?

Use case:
I'm using Handout as an alternative to ShareLatex/Notebook for my homework reports. The reports consists many plots and a few comments.

What I want to be able to do
I want to hide some parts of my code that are not relevant to the reader of the report, but necessary to create my plots. For instance, I usually have several lines specifying formatting of my pyplots.

Thanks

doc.show() will execute _generate method and rewrites index.html?

Hi, all.
I want to make sure how handout renders the scripts. It looks like doc.show() will execute _generate method, append all the blocks, then render all of them, right? And then when doc.show() gets called again, it will re-render the whole blocks except with more lineno?

With this behavior, if someone writes more lines of script, maybe with more figures or videos, does it affect the time we need to run the script?

Provide a convenient way to add custom CSS styles

Adding custom CSS is possible in two ways:

doc.add_html('<style></style>')
doc.add_html('<link rel="stylesheet" href="path/to/style.css">')

We could add doc.add_style(filename) that copies the file into the output directory for the user.

Duplicated logging messages when importing module twice

I run example.py in IPython console in Spyder and it seems that console output gets proportional to the number of times I have run the script. On the first run in new kernel I get just single message, one per call of handout.Handout instance method.

This is what I get on the fifth run:

Iteration 0
Iteration 0
Iteration 0
Iteration 0
Iteration 0
Iteration 0
Iteration 1
Iteration 1
Iteration 1
Iteration 1
Iteration 1
Iteration 1
Iteration 2
Iteration 2
Iteration 2
Iteration 2
Iteration 2
Iteration 2
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Saved figure: output\figure-0.png
Saved figure: output\figure-0.png
Saved figure: output\figure-0.png
Saved figure: output\figure-0.png
Saved figure: output\figure-0.png
Saved figure: output\figure-0.png
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Saved figure: output\figure-1.png
Saved figure: output\figure-1.png
Saved figure: output\figure-1.png
Saved figure: output\figure-1.png
Saved figure: output\figure-1.png
Saved figure: output\figure-1.png
Saved figure: output\figure-2.png
Saved figure: output\figure-2.png
Saved figure: output\figure-2.png
Saved figure: output\figure-2.png
Saved figure: output\figure-2.png
Saved figure: output\figure-2.png
Saved figure: output\figure-3.png
Saved figure: output\figure-3.png
Saved figure: output\figure-3.png
Saved figure: output\figure-3.png
Saved figure: output\figure-3.png
Saved figure: output\figure-3.png
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html
Handout written to: output\index.html

Maybe not a bug, but it would have felt more confortable the handout.Handout instance made just a single print to the screen per call.

I run the script as runfile('D:/github/handout/example.py', wdir='D:/github/handout')

Exporting to LaTeX

Hi and thanks for this package, I just had a couple of questions if you don't mind me asking since I couldn't find any answers in the readme.

  1. Is it possible to export the document into latex?
  2. Will you be releasing a conda package?

Thanks!

User guide with more usage examples and tips

Let's collect key topics and then put together a user guide. Points that came up already:

  • Comparison to related projects (when (not) to use it)
  • Converting HTML via pandoc
  • Using custom text renderers (for flow charts etc)
  • Adding JS and CSS in general
  • Multiple handouts for static websites
  • Updating the doc while the script runs for training ML models

Direct export into more formats

The output format is currently HTML, which can then be printed as PDF from the browser. It could be nice to directly export to PDF, ipynb and other formats.

Inconsistent creation of output on Windows

Hi Dani!

1st issue!๐Ÿ˜„

Just tried your example and made it run by executing from the terminal. But I already struggled with setting up my Atom IDE so I can execute it from there. I used "atom-run-python" and "atom-python-virtualenv" so I can execute my script on the go in the related virtualenv. Executing it with this setting leads to some kind of bug. The plots are located in the same directory as "example.py" ("example.py-L48-0.png", etc.) while HTML, js, css are placed in the output directory.

Since it might be related to the executing directory I tried to execute "python example.py" in the terminal but in its parent directory (python repo/example.py). This even leads to an execution error:

(venv) C:\Users\Thomas\HPI> python .\MA\example.py
Traceback (most recent call last):
  File ".\MA\example.py", line 48, in <module>
    doc.display(fig)  # Display the figure below this line.
  File "C:\Users\Thomas\HPI\MA\venv\lib\site-packages\handout\handout.py", line 26, in display
    figure.savefig(filename)
  File "C:\Users\Thomas\HPI\MA\venv\lib\site-packages\matplotlib\figure.py", line 1834, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "C:\Users\Thomas\HPI\MA\venv\lib\site-packages\matplotlib\backend_bases.py", line 2267, in print_figure
    **kwargs)
  File "C:\Users\Thomas\HPI\MA\venv\lib\site-packages\matplotlib\backends\backend_agg.py", line 512, in print_png
    filename_or_obj = open(filename_or_obj, 'wb')
FileNotFoundError: [Errno 2] No such file or directory: 'output\\.\\MA\\example.py-L48-0.png'

An empty output directory is created next to my repository.

Environment

  • Windows 8
  • Python 3.6.0
  • handout==0.2.2

Hope this helps you tracking down this bug,
Thomas

Allow to hide ranges of code lines

We can already hide individual lines from the handout using # handout: exclude.

It would be great to allow excluding ranges via:

# handout: begin-exclude
<Python code here>
# handout: end-exclude

Media added inside such blocks will still be shown.

This will make it easy to create reports that only include text and media, but not code.

Name of an output html file can be {__file__}.html

Similar to #13 the name of an output html file can be {__file__}.html, instead of hardcoded index.html (if it is possible to track and pass source file name, but seems realistic).

This way model.py will have an output model.html. This feature should open the way to ensembles/collections of handouts.

filename = os.path.join(self._directory, 'index.html')

Pandas Dataframe Display Support

Hi, it would be great to have a handout that could generate/display a Dataframe table. Might be something like doc.add_dataframe(df)

Use AST module to parse script rather than processing text line by line

Branched from #10 (comment):

@danijar would you be open to a PR that uses the Python AST. Looking at this request and others, it might be worth to consider making the change to AST parsing, sooner rather then later. For instance one advantage could be, is that you choose to hide the doc.* code.

Hi @eiso, yes I think switching to AST could be good. I'd definitely look forward to a PR, although it'll likely take some back and forth until we converge on a design that works well for the library.

conda package

Hi would it be too much trouble to ask for a conda package?

inspect.stack() role in code

What is the purpose of look-through in Handout class:

for info in inspect.stack():
      if info.filename == __file__:
        continue
      break

My first impression is that nothing happens in the loop.

Comparison to Pweave

Just a quick note to ask if you are aware of pweave project, which, albeit without an active maintainer at the moment, does exactly the same. Supports markdown with python snippets, modeled after Rstudio Rmd format, or python with special comments as in this project. Supports matplotlib as well bokeh graphics (I have patches for altair, also web based and with interactions).

Reduce amount of logging messages

Instead of writing a message every time saved, there should be one message in the beginning that states the location of the handout.

ImportError: Imageio Pillow plugin requires Pillow, not PIL!

Hey,
I am facing this error:

python3 example.py
Iteration 0
Iteration 1
Iteration 2
Handout written to: output/index.html
Saved figure: output/figure-0.png
Handout written to: output/index.html
Saved figure: output/figure-1.png
Saved figure: output/figure-2.png
Saved figure: output/figure-3.png
Handout written to: output/index.html
Traceback (most recent call last):
File "example.py", line 69, in
doc.add_image(image_a, 'png', width=0.4)
File "~/handout/handout.py", line 52, in add_image
imageio.imsave(os.path.join(self._directory, filename), image)
File "/usr/local/lib/python3.5/dist-packages/imageio/core/functions.py", line 259, in imwrite
writer = get_writer(uri, format, "i", **kwargs)
File "/usr/local/lib/python3.5/dist-packages/imageio/core/functions.py", line 180, in get_writer
format = formats.search_write_format(request)
File "/usr/local/lib/python3.5/dist-packages/imageio/core/format.py", line 706, in search_write_format
if format.can_write(request):
File "/usr/local/lib/python3.5/dist-packages/imageio/core/format.py", line 192, in can_write
return self._can_write(request)
File "/usr/local/lib/python3.5/dist-packages/imageio/plugins/pillow.py", line 113, in _can_write
Image = self._init_pillow()
File "/usr/local/lib/python3.5/dist-packages/imageio/plugins/pillow.py", line 88, in _init_pillow
"Imageio Pillow plugin requires " "Pillow, not PIL!"
ImportError: Imageio Pillow plugin requires Pillow, not PIL!

Support interactive environment in PyCharm where there is no source file

For my workflow, the greatest problem with this package at the moment is that it throws an error when running handout.Handout() in an interactive shell:

handout.Handout('/tmp')
Traceback (most recent call last):
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3325, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-4-d909ee1709cf>", line 1, in <module>
    handout.Handout('/tmp')
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/site-packages/handout/handout.py", line 25, in __init__
    self._source_text = inspect.getsource(module)
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/inspect.py", line 973, in getsource
    lines, lnum = getsourcelines(object)
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/inspect.py", line 955, in getsourcelines
    lines, lnum = findsource(object)
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/inspect.py", line 768, in findsource
    file = getsourcefile(object)
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/inspect.py", line 684, in getsourcefile
    filename = getfile(object)
  File "/h/hannes/anaconda3/envs/microexon-code-tf2/lib/python3.6/inspect.py", line 666, in getfile
    'function, traceback, frame, or code object'.format(object))
TypeError: None is not a module, class, method, function, traceback, frame, or code object

This is a problem for my (Jupyter-less) workflow as I like to use #%% in PyCharm to create run-able cells and send them to a shell with Ctrl+Enter. This way I can create my figures and do my analysis interactively and simply run the script at the end to obtain a rendered report. However, the error above throws a wrench into that workflow.

I think a workable simple solution would be for handout to simply do nothing when it detects an interactive shell.

Generate handout every time the Python script is saved

I am just discovering this package but I wonder the feasibility of handout to support real time editing.

I was envisioning having integrations with editors such as Visual Studio Code, Sublime Text or Atom that would allow real time editing.

Your thoughts on this is much appreciated.

Making handout work with Jupyter

First of all, thanks for creating handout!

Is there any plan to integrate Jupyter and Handout files in the future?
I think the combination of both would help solve lots of issues current notebooks have, while keeping the practical approach jupyter notebooks have!

I think if we could have in Python something similar to how Rstudio implemented notebooks (where you can easily commit text files) while keeping the flexibility of working interactively it would be a game changer!

Thanks again for your work!

Custom html document title

Html file title is currently is hardcoded Handout. A user might want to override it with custom title, something like "Jane's awesome notebook"

handout/handout/handout.py

Lines 111 to 116 in 00d9c58

def _generate(self, source):
content = []
content.append(blocks.Html([
'<html>',
'<head>',
'<title>Handout</title>',

Implemetation would require small change in constructor as below:

class Handout(object):

  def __init__(self, directory, title="Handout"):

Support multiple HTML pages to generate small websites

In a case when you can have several handouts the output folder may get cluttered. This may be a case when one wants to render several files and link them to display in a static site generator, eg via Github Pages.

I propose the html components/dependecies can be stored in a subfolder filename.html.files, which will make output folder cleaner.

This behavior is similar to how a browser, eg Chrome will save an html page to a local disk.

Pathlib error when running setup.py on Linux

Hi, is pathlib really a necessary dependency ? since: after install it gives:

    AttributeError: 'PosixPath' object has no attribute 'read_text'

can it be builted withou longdescription or with another text parser
? (it seems that pathlib has to do with windows and .Net)

Opt-out of Markdown rendering for some multi-line comments

This would be useful for docstrings that should be rendered inside the code cell rather than interrupting the document with a Markdown cell. I'm not sure if there is a nice syntax for this so we might decide to not support it, but let's discuss!

steps for porting to Julia

I'm thinking about porting Handout to Julia, this is also an exercise in understanding how Handout currently works.

Julia does not have classes, but rather data structures and bounded methods that operate on these structures. This calls for greater unbundling of data components and operations on them, compared to python.

My question to @danijar is to discuss/validate user scenarios and underlying functionality below.

Here is a user scenario:

  • create Handout instance in script
  • add user blocks (eg custom html, image, video) to handout instance with add_* functions
  • make user blocks appear in a report with show() method or an optional show flag in add_* functions
  • disqualify out parts of script from appearing in a report with #handout: exclude (single line), #handout: start-exclude, #handout: end-exclude (block of lines)
  • view html report in browser with script contents and user-added blocks
  • use other formats of report (eg. latex) to create new documents

Handout appears to be a data structure which holds the following:

  • output directory path
  • document title
  • script path (may be useful to warn about calls to handout instance outside original script)
  • stack of user blocks (pending and accepted blocks)
  • counter for graphic files by type (image, video)

Methods that work with Handout:

  • add_*() method creates local files for images and videos and adds content to internal report representation
  • show() renders report with selected exporter(html, latex, markdow, ipynb) and saves it to output folder

In the background we need:

  • a function that identifies code, text as well as comments in script source, creates source blocks and merges script source blocks with user blocks to produce internal representatinon of report
  • functionality (a macro, in Julia) to trace line in script where a call was made
  • renderer functions that take internal representation of report as blocks and produce output in report format (eg html or latex)
  • possibly a writer that saves report content to local file

I think important design decision is saving local graphic files within add_*() functions. This can be taken away to a different layer (a queue of content by tupe of file), but would make things a bit less trasparent, unnecessary complicated.

Would be indebted to learn if I'm missing anything critical in a user scenario, data structures or background fucntions.

Need to install dependencies separately

While installing the package by pip, it does not install dependencies like 'matplotlib', 'imageio' etc. These have to be installed separately. We can make some changes to the 'setup.py' to include all dependencies so that it becomes very convenient to install the entire thing with just one command.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.