Skip to content

Commit f23ba8a

Browse files
authored
Merge pull request #10 from databio/refactor
Release 0.0.2
2 parents 8fb5119 + 731643b commit f23ba8a

88 files changed

Lines changed: 4933 additions & 2184 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/black.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: Lint
2+
3+
on: [pull_request]
4+
5+
jobs:
6+
lint:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v2
10+
- uses: actions/setup-python@v2
11+
- uses: psf/black@stable
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This workflows will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
name: Upload Python Package
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
deploy:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v2
19+
with:
20+
python-version: '3.x'
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install setuptools wheel twine
25+
- name: Build and publish
26+
env:
27+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29+
run: |
30+
python setup.py sdist bdist_wheel
31+
twine upload dist/*

.github/workflows/run-pytest.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Run pytests
2+
3+
on:
4+
push:
5+
branches: [dev]
6+
pull_request:
7+
branches: [master, dev]
8+
9+
jobs:
10+
pytest:
11+
runs-on: ${{ matrix.os }}
12+
strategy:
13+
matrix:
14+
python-version: ["3.7", "3.10", "3.11"]
15+
os: [ubuntu-latest]
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
20+
- name: Set up Python ${{ matrix.python-version }}
21+
uses: actions/setup-python@v2
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
25+
- name: Install dev dependencies
26+
run: if [ -f requirements/requirements-dev.txt ]; then pip install -r requirements/requirements-dev.txt; fi
27+
28+
- name: Install test dependencies
29+
run: if [ -f requirements/requirements-test.txt ]; then pip install -r requirements/requirements-test.txt; fi
30+
31+
- name: Install package
32+
run: python -m pip install .
33+
34+
- name: Run pytest tests
35+
run: pytest -x -vv

.gitignore

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# ignore test results
2+
oldtests/test/*
3+
4+
# toy/experimental files
5+
*.pkl
6+
7+
# ignore eggs
8+
.eggs/
9+
10+
# generic ignore list:
11+
*.lst
12+
13+
# Compiled source
14+
*.com
15+
*.class
16+
*.dll
17+
*.exe
18+
*.o
19+
*.so
20+
*.pyc
21+
22+
# Packages
23+
# it's better to unpack these files and commit the raw source
24+
# git has its own built in compression methods
25+
*.7z
26+
*.dmg
27+
*.gz
28+
*.iso
29+
*.jar
30+
*.rar
31+
*.tar
32+
*.zip
33+
34+
# Logs and databases
35+
*.log
36+
*.sql
37+
*.sqlite
38+
39+
# OS generated files
40+
.DS_Store
41+
.DS_Store?
42+
._*
43+
.Spotlight-V100
44+
.Trashes
45+
ehthumbs.db
46+
Thumbs.db
47+
48+
# Gedit temporary files
49+
*~
50+
51+
# libreoffice lock files:
52+
.~lock*
53+
54+
# Default-named test output
55+
microtest/
56+
open_pipelines/
57+
58+
# IDE-specific items
59+
.idea/
60+
61+
# pytest-related
62+
.cache/
63+
.coverage*
64+
.pytest_cache
65+
66+
# Reserved files for comparison
67+
*RESERVE*
68+
69+
doc/
70+
site/
71+
build/
72+
dist/
73+
markmeld.egg-info/
74+
__pycache__/
75+
76+
77+
*ipynb_checkpoints*
78+
hello_looper-master*

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2019 Nathan Sheffield
1+
Copyright 2022 Nathan Sheffield
22

33
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
44

README.md

Lines changed: 5 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,18 @@
1-
# markmeld
1+
# <img src="docs/img/markmeld_logo_long.svg" alt="markmeld logo" height="70">
22

3-
`markmeld` is a command-line tool for integrating structured data from `yaml` or `markdown` files into `markdown` output using `jinja2` templates. The name `markmeld` refers to it as a *markup* *melder*. It makes it easy to restructure your structured data into different output formats. It's a companion to pandoc that allows you to merge and shape various data, from yaml or markdown documents, and output them into markdown format that can then (optionally) be piped to pandoc.
3+
Read the complete documentation at [markmeld.databio.org](https://markmeld.databio.org).
44

5-
![demo](markmeld_abstract.svg)
6-
7-
8-
## Install
5+
## Testing
96

107
```
11-
pip install https://github.com/databio/markmeld/archive/refs/heads/master.zip
8+
pytest
129
```
1310

14-
Markmeld provides the `mm` executable:
11+
You can also just build the demos.
1512

1613
```
1714
cd demo
1815
mm default
1916
```
2017

21-
This will produce the output, automatically piping to pandoc. You can also get the raw output with `-p`, like this:
22-
23-
```
24-
mm default -p > rendered.md
25-
```
26-
27-
## Markmeld config file
28-
29-
You produce a file called `_markmeld.yaml` to configure your project. In the file you specify any variables you want, The `demo/_markmeld.yaml` looks like this:
30-
31-
```
32-
targets:
33-
default:
34-
md_template: md_template.jinja
35-
latex_template: pandoc_default.tex
36-
output_file: "{today}_demo_output.pdf"
37-
data_yaml:
38-
- some_data.yaml
39-
data_md:
40-
some_text_data: some_text.md
41-
```
42-
43-
The configurable attributes are:
44-
45-
- `targets`: a list of targets (outputs) to build. Each target can contain the other configurable attributes.
46-
- `data_yaml` - a list of yaml files to make available to the templates
47-
- `data_md` - a named list of markdown files, which will be made available to the templates
48-
- `data_variables` - direct yaml data made available to the templates.
49-
- `data_md_globs` - Globs, where each file will be read, and available at the key of the filename.
50-
Any other attributes will be made available to the build system, but not to the jinja templates.
51-
52-
In the demo, the only target you can build is `default`. You can see the list of targets with `mm -l`.
53-
54-
## md jinja template
55-
56-
Your markdown items will be available under the key you specify in the config. If you are using the `_globs` key, then they will be available under the filename. You can then access them in the jinja template as variables, like this:
57-
58-
```
59-
{{ variable.content }}
60-
```
61-
62-
The `.content` attribute will have the actual markdown -- this is probably what you want. But if you want metadata, you can also access that under `{{ variable.metadata }}`.
63-
64-
65-
## The jinja md array
66-
67-
See detailed instructions for how to access md content with variable names using the md array.
68-
69-
## Hooks
70-
71-
You can add a 'prebuild' hook, which runs a separate target them by adding:
72-
73-
```
74-
prebuild:
75-
- manuscript_supplement
76-
- manuscript
77-
postbuild:
78-
- split
79-
```
80-
81-
in `_markmeld.yaml`. This allows you to build another recipe before the current one. These recipes can be built-in recipes (which are in `mm_targets`), or can be recipes from your cfg file. I'm using built-in recipes to provide alternative commands, like building figures or splitting stuff. I guess I could make these command templates instead.
82-
83-
## Imports
84-
85-
It's super useful to define global config options, and then re-use them across projects. You can do this with `imports`.So I have a global config file, say `/_markmeld_config.yaml`:
86-
87-
```yaml
88-
sciquill: /home/nsheff/code/sciquill/
89-
figczar: /home/nsheff/code/sciquill/pandoc_filters/figczar/figczar.lua
90-
highlighter: /home/nsheff/code/sciquill/pandoc_filters/change_marker/change_marker.lua
91-
multirefs: /home/nsheff/code/sciquill/pandoc_filters/multi-refs/multi-refs.lua
92-
csl: /home/nsheff/code/sciquill/csl/biomed-central.csl
93-
bibdb: /home/nsheff/code/papers/sheffield.bib
94-
```
95-
96-
Now you use:
97-
```yaml
98-
imports:
99-
- /_markmeld_config.yaml
100-
```
101-
102-
And now I can use `{figczar}` and `{bibdb}` in `command` section of a `_markmeld.yaml` file. If you want to be really cool, maybe point to this config file with `$MARKMELD` and then use:
103-
104-
```yaml
105-
imports:
106-
- $MARKMELD
107-
```
108-
109-
It works! Imports are in priority order, and lower priority than whatever you have in the local file, like `css`. You can also define targets and import them.
110-
111-
## Raw commands
112-
113-
If in a command you use `type: raw`, then the command will run directly, and not pass the template render as stdin.
114-
115-
## Commands without pandoc
116-
117-
Usually, I want to run whatever my template is through pandoc, to produce the output. Markmeld first creates markdown using the jinja template, and then passes this to pandoc to convert to the final output.
118-
119-
But sometimes, the output I make from the jinja template is *not* markdown, and that's my end product. For example, I may want to produce a `csv` file representation of some data I had in yaml format. Markmeld can also do this. In this case, you would just change the `command`, and don't use pandoc.
120-
121-
```
122-
command: |
123-
cat > {output_file}
124-
```
125-
126-
Then, your jinja template would spit out a csv file. This command basically just writes that to an output file. You can use it to get the output from jinja directly.
127-
128-
## Rationale
129-
130-
Why is this better than just stringing stuff together using pandoc? Well, for one, the power of a jinja template is pretty nice... so I can just tell markmeld about all the data, which can be either markdown or yaml, and then using jinja I can restructure the output in whatever format I want. Furthermore, it allows me to intersperse yaml data in there. Without markmeld, I couldn't really find an easy way to integrate prose content (in markdown format) with structured content (in yaml format) into one output. This is useful for something like a CV/Biosketch, where I have some prose components, and then some lists, which I'd rather draw from a structured YAML file.
131-
132-
For simple documents like a manuscript that don't really use much structured content and are purely gluing together prose, you can get by with just straight-up pandoc. You'd just pass multiple markdown files directly to pandoc on the command line. But even in these situations, you gain something from going the route of the jinja template with markmeld: it formalizes the linking of documents into a separate file, instead of relying the on order and content of CLI arguments to pandoc. So you can more easily write a little recipe saying, "provide these pieces of content under these names, and then use this jinja template to produce the output". So, it makes that recipe reproducible.
133-
134-
## How to write mail-merge letters with markmeld
135-
136-
1. Data
137-
138-
You need a `data.yaml` file like this. This is a list of people you want to send the letter to:
139-
140-
```
141-
people:
142-
- first_name: Bob
143-
last_name: Jones
144-
email: bob.jones@gmail.com
145-
```
146-
147-
2. Letter
148-
149-
Write your letter in a jinja template like this `letter.jinja`:
150-
151-
```
152-
{% for person in people %}
153-
154-
<a href="mailto:{{ person.email }}?subject=SUBJECT&body=Hi {{person.first_name}},%0D%0A%0D%Letter contentt %0D%0A%0D%0AThanks, and we should catch up some time!%0D%0A%0D%0A-Nathan">{{ person.first_name }}</a>
155-
156-
{% endfor %}
157-
```
158-
159-
3. Markmeld config in `_markmeld.yaml`:
160-
161-
Which is something like:
162-
163-
```
164-
imports:
165-
- $MMDIR/$HOSTNAME.yaml
166-
targets:
167-
links:
168-
md_template: letter_template.jinja
169-
output_file: "{today}.html"
170-
data_yaml:
171-
- data.yaml
172-
command: |
173-
pandoc \
174-
-o {output_file}
175-
```
176-
177-
Now just `mm links`, open the file, and you have personalized click links for all your letters. Easy peasy!
178-
179-
180-
## Limitations and TODO
18118

182-
- [x] tab completion
183-
- [x] Config file should be a positional argument
184-
- [x] some kind of list functionality to show available recipes to build? `mm -l`
185-
- [x] the latex template is configurable, but nothing else with pandoc. Really, should pandoc just be something you pipe `mm` output to?
186-
- [x] CLI: `mm meldsource.yaml target`
187-
- [x] use `_markmeld.yaml` by default, so you configure by putting a `_markmeld.yaml` file in root.
188-
- [ ] `mm` without a target lists the targets.
189-
- [ ] Currently, paths are relative to the working directory. Instead, paths should be relative to the directory of the yaml file. (this will only matter when I start trying to build stuff using external `_markmeld.yaml` files in other folders.)
190-
- [ ] Might need better error handling in case some sections aren't present in the config file. All sections are optional. This has not been thoroughly tested.
191-
- [ ] Currently, config files can import one another with `imports`. This way I can keep common targets in common config files. Would this be a useful application for PEP?
192-
- [ ] Right now, if you want to provide markmeld with `md` data, you can either specify them explicitly, in which case you can define an identifier by which you can refer to that file, like `my_identifier: path/some_file.md`, which can then be referenced in a template with `{{ my_identifer.content }}`. But if you use `data_md_globs`, then you just give it file globs, and the identifier is the filename. I could build an alternative metadata key, like `mm_id: my_identifier`, and if you use the glob approach, it could become available under that label. Why might this be useful? 1) For a mix/match where I want swap out one possible version of `my_identifier` with another, this way I can do that with different file names; 2) if using hedgedoc, I may not control the filename. So if it's a remote file... I guess I'd just have to make it explicit...
193-
- `markmeld_templates: [ ]` - a priority list of folders to search for a named template file (in `md_template`, which must exist as a file). (maybe?)

demo/2022-10-02_demo_output.pdf

83.7 KB
Binary file not shown.

demo/_markmeld.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
targets:
22
default:
3-
md_template: md_template.jinja
3+
jinja_template: md_template.jinja
44
recursive_render: false
55
output_file: "{today}_demo_output.pdf"
66
data_yaml:

demo/null.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 1
2+
targets:
3+
default:
4+
jinja_template: null
5+
recursive_render: false
6+
output_file: "{today}_demo_output.pdf"
7+
data:
8+
yaml_globs_unkeyed:
9+
- some_data.yaml
10+
md_files:
11+
some_text_data: some_text.md

0 commit comments

Comments
 (0)