Merge pull request #869 from jrnl-org/develop

Merge develop into master for v2.3 beta
This commit is contained in:
Jonathan Wren 2020-03-07 14:50:54 -08:00 committed by GitHub
commit b3793fbb7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1258 additions and 319 deletions

View file

@ -1,5 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
# Check if branch has been updated since this build started
# This tends to happen if multiple things have been merged in at the same time.
if [[ -z $TRAVIS_TAG ]]; then
git fetch origin
if [[ $(git rev-parse "origin/${BRANCH}") != $TRAVIS_COMMIT ]]; then
echo "${BRANCH} has been updated since build started. Aborting changelog."
exit 0
fi
fi
FILENAME='CHANGELOG.md' FILENAME='CHANGELOG.md'
# get the latest git tags # get the latest git tags
@ -40,11 +55,6 @@ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app ferrarimarco/github-chan
# Put back our link (instead of the broken one) # Put back our link (instead of the broken one)
sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME" sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME"
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
git config --global user.email "jrnl.bot@gmail.com" git config --global user.email "jrnl.bot@gmail.com"
git config --global user.name "Jrnl Bot" git config --global user.name "Jrnl Bot"
git checkout $BRANCH git checkout $BRANCH

4
.github/stale.yml vendored
View file

@ -4,8 +4,8 @@ daysUntilStale: 60
daysUntilClose: 7 daysUntilClose: 7
# Issues with these labels will never be considered stale # Issues with these labels will never be considered stale
exemptLabels: exemptLabels:
- ':star:' - ':pushpin:'
- security - critical
# Label to use when marking an issue as stale # Label to use when marking an issue as stale
staleLabel: stale staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable # Comment to post when marking an issue as stale. Set to `false` to disable

View file

@ -13,7 +13,7 @@ before_install:
- date - date
install: install:
- pip install poetry - pip install --upgrade poetry
- poetry install - poetry install
- poetry run python --version - poetry run python --version
@ -51,7 +51,6 @@ jobs:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- python: nightly - python: nightly
- os: windows
include: include:
- name: Lint, via Black - name: Lint, via Black
@ -74,6 +73,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.6.8 - JRNL_PYTHON_VERSION=3.6.8
- PATH=/c/Python36:/c/Python36/Scripts:$PATH - PATH=/c/Python36:/c/Python36/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.7 Tests # Python 3.7 Tests
- name: Python 3.7 on Linux - name: Python 3.7 on Linux
@ -89,6 +89,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.7.5 - JRNL_PYTHON_VERSION=3.7.5
- PATH=/c/Python37:/c/Python37/Scripts:$PATH - PATH=/c/Python37:/c/Python37/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.8 Tests # Python 3.8 Tests
- name: Python 3.8 on Linux - name: Python 3.8 on Linux
@ -104,6 +105,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.8.0 - JRNL_PYTHON_VERSION=3.8.0
- PATH=/c/Python38:/c/Python38/Scripts:$PATH - PATH=/c/Python38:/c/Python38/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# ... and beyond! # ... and beyond!
- name: Python nightly on Linux - name: Python nightly on Linux
@ -129,6 +131,8 @@ jobs:
- poetry version "$TRAVIS_TAG" - poetry version "$TRAVIS_TAG"
- echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py - echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py
- poetry build - poetry build
script:
- echo "Deployment starting..."
deploy: deploy:
- provider: script - provider: script
script: poetry publish script: poetry publish

View file

@ -8,18 +8,32 @@
- Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb)) - Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb))
**Fixed bugs:**
- Listing all entries in DayOne Classic journal throws IndexError [\#786](https://github.com/jrnl-org/jrnl/pull/786) ([MinchinWeb](https://github.com/MinchinWeb))
- Add UTC support for failing DayOne tests [\#785](https://github.com/jrnl-org/jrnl/pull/785) ([MinchinWeb](https://github.com/MinchinWeb))
**Build:** **Build:**
- Stop multiple changelog generators from crashing into each other [\#845](https://github.com/jrnl-org/jrnl/pull/845) ([wren](https://github.com/wren))
- Don't re-run tests on deployment [\#839](https://github.com/jrnl-org/jrnl/pull/839) ([wren](https://github.com/wren))
- Put back build lines in Poetry config [\#838](https://github.com/jrnl-org/jrnl/pull/838) ([wren](https://github.com/wren))
- Restore emoji test [\#837](https://github.com/jrnl-org/jrnl/pull/837) ([micahellison](https://github.com/micahellison))
- Fix crashing unicode Travis tests on Windows and fail build if Windows tests fail [\#836](https://github.com/jrnl-org/jrnl/pull/836) ([micahellison](https://github.com/micahellison))
- Remove poetry from build system in pyproject config to fix `brew install` [\#830](https://github.com/jrnl-org/jrnl/pull/830) ([wren](https://github.com/wren))
- Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison)) - Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison))
**Updated documentation:** **Updated documentation:**
- Docs: Fix broken links in recipes.md [\#854](https://github.com/jrnl-org/jrnl/pull/854) ([lrvl](https://github.com/lrvl))
- Fix fish history instructions. [\#846](https://github.com/jrnl-org/jrnl/pull/846) ([aureooms](https://github.com/aureooms))
- Update site description [\#841](https://github.com/jrnl-org/jrnl/pull/841) ([wren](https://github.com/wren))
- Get rid of dumb sex joke [\#840](https://github.com/jrnl-org/jrnl/pull/840) ([wren](https://github.com/wren))
- Updating/clarifying template explanation [\#829](https://github.com/jrnl-org/jrnl/pull/829) ([heymajor](https://github.com/heymajor)) - Updating/clarifying template explanation [\#829](https://github.com/jrnl-org/jrnl/pull/829) ([heymajor](https://github.com/heymajor))
## [v2.2](https://pypi.org/project/jrnl/v2.2/) (2020-02-01) ## [v2.2](https://pypi.org/project/jrnl/v2.2/) (2020-02-01)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.2-beta2...v2.2) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1...v2.2)
**Implemented enhancements:** **Implemented enhancements:**
@ -59,7 +73,7 @@
## [v2.1.1](https://pypi.org/project/jrnl/v2.1.1/) (2019-11-26) ## [v2.1.1](https://pypi.org/project/jrnl/v2.1.1/) (2019-11-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1-beta...v2.1.1) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.post2...v2.1.1)
**Implemented enhancements:** **Implemented enhancements:**
@ -82,7 +96,7 @@
## [v2.1.post2](https://pypi.org/project/jrnl/v2.1.post2/) (2019-11-11) ## [v2.1.post2](https://pypi.org/project/jrnl/v2.1.post2/) (2019-11-11)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1-beta6...v2.1.post2) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1...v2.1.post2)
**Fixed bugs:** **Fixed bugs:**
@ -100,7 +114,7 @@
## [v2.0.1](https://pypi.org/project/jrnl/v2.0.1/) (2019-09-26) ## [v2.0.1](https://pypi.org/project/jrnl/v2.0.1/) (2019-09-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1-beta...v2.0.1) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.0...v2.0.1)
**Implemented enhancements:** **Implemented enhancements:**
@ -118,7 +132,9 @@
## [v2.0.0](https://pypi.org/project/jrnl/v2.0.0/) (2019-08-24) ## [v2.0.0](https://pypi.org/project/jrnl/v2.0.0/) (2019-08-24)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0-rc4...v2.0.0) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/1.9.8...v2.0.0)
🚨 **BREAKING CHANGES** 🚨
**Implemented enhancements:** **Implemented enhancements:**
- Change cryptographic backend from PyCrypto to cryptography.io - Change cryptographic backend from PyCrypto to cryptography.io

View file

@ -35,8 +35,9 @@ and can be edited with a plain text editor.
- `highlight` - `highlight`
if `true`, tags will be highlighted in cyan. if `true`, tags will be highlighted in cyan.
- `linewrap` - `linewrap`
controls the width of the output. Set to `false` if you don't controls the width of the output. Set to `false` if you don't want to wrap long lines.
want to wrap long lines. - `colors`
dictionary that controls the colors used to display journal entries. It has two subkeys, which are: `date` and `title`. Current valid values are: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, and `WHITE`. `colorama.Fore` is used for colorization, and you can find the [docs here](https://github.com/tartley/colorama#colored-output). To disable colored output, set the value to `NONE`. If you set the value of any color subkey to an invalid color, no color will be used.
!!! note !!! note
Although it seems intuitive to use the `#` Although it seems intuitive to use the `#`

View file

@ -60,7 +60,7 @@ If you are using `fish` instead of `bash` or `zsh`, you can get the same behavio
adding this to your `fish` configuration: adding this to your `fish` configuration:
``` sh ``` sh
abbr jrnl=" jrnl" abbr --add jrnl " jrnl"
``` ```
To delete existing `jrnl` commands from `fish`s history, run To delete existing `jrnl` commands from `fish`s history, run

View file

@ -71,7 +71,7 @@ jrnlimport () {
### Using templates ### Using templates
!!! note !!! note
Templates require an [external editor](../advanced) be configured. Templates require an [external editor](./advanced.md) be configured.
A template is a code snippet that makes it easier to enter use repeated text A template is a code snippet that makes it easier to enter use repeated text
each time a new journal entry is started. There are two ways you can utilize each time a new journal entry is started. There are two ways you can utilize
@ -113,7 +113,7 @@ logged as a new entry in the journal you specified in the original argument.
!!! tip !!! tip
To read your journal entry or to verify the entry saved, you can use this To read your journal entry or to verify the entry saved, you can use this
command: `jrnl -n 1` (Check out [Import and Export](../export/#export-to-files) for more export options). command: `jrnl -n 1` (Check out [Import and Export](./export.md) for more export options).
```sh ```sh
jrnl -n 1 jrnl -n 1
@ -155,7 +155,7 @@ jrnl -on "$(jrnl --short | shuf -n 1 | cut -d' ' -f1,2)"
## External editors ## External editors
Configure your preferred external editor by updating the `editor` option Configure your preferred external editor by updating the `editor` option
in your `jrnl.yaml` file. (See [advanced usage](../advanced) for details). in your `jrnl.yaml` file. (See [advanced usage](./advanced.md) for details).
!!! note !!! note
To save and log any entry edits, save and close the file. To save and log any entry edits, save and close the file.

View file

@ -34,7 +34,7 @@
"operatingSystem": ["macOS", "Windows", "Linux"], "operatingSystem": ["macOS", "Windows", "Linux"],
"thumbnailUrl": "https://jrnl.sh/img/banner_og.png", "thumbnailUrl": "https://jrnl.sh/img/banner_og.png",
"installUrl": "https://jrnl.sh/installation", "installUrl": "https://jrnl.sh/installation",
"softwareVersion": "2.0.0rc2" "softwareVersion": "2.2"
} }
</script> </script>
</head> </head>
@ -42,7 +42,7 @@
<body> <body>
<header> <header>
<aside> <aside>
<a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert"><i class="icon twitter"></i>Tell your friends</a> <a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh"><i class="icon twitter"></i>Tell your friends</a>
</aside> </aside>
<div id="title"> <div id="title">
<img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" /> <img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" />
@ -58,7 +58,7 @@
<nav> <nav>
<a href="overview">Documentation</a> <a href="overview">Documentation</a>
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a> <a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a>
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert">Tell your friends on twitter</a> <a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh">Tell your friends on twitter</a>
<a href="installation" class="cta">Download</a> <a href="installation" class="cta">Download</a>
</nav> </nav>
<div class="flex"> <div class="flex">

View file

@ -119,10 +119,10 @@ Will print all entries in which either `@pinkie` or `@WorldDomination`
occurred. occurred.
```sh ```sh
jrnl -n 5 -and @pineapple @lubricant jrnl -n 5 -and @pinkie @WorldDomination
``` ```
the last five entries containing both `@pineapple` **and** `@lubricant`. the last five entries containing both `@pinkie` **and** `@worldDomination`.
You can change which symbols you'd like to use for tagging in the You can change which symbols you'd like to use for tagging in the
configuration. configuration.
@ -154,7 +154,7 @@ encrypt) your edited journal after you save and exit the editor.
You can also use this feature for deleting entries from your journal You can also use this feature for deleting entries from your journal
```sh ```sh
jrnl @girlfriend -until 'june 2012' --edit jrnl @texas -until 'june 2012' --edit
``` ```
Just select all text, press delete, and everything is gone... Just select all text, press delete, and everything is gone...

View file

@ -14,7 +14,7 @@ Feature: Contains
Given we use the config "tags.yaml" Given we use the config "tags.yaml"
When we run "jrnl @idea -contains software" When we run "jrnl @idea -contains software"
Then we should get no error Then we should get no error
and the output should contain "software" And the output should contain "software"
Scenario: Searching for a string within AND tag results Scenario: Searching for a string within AND tag results
Given we use the config "tags.yaml" Given we use the config "tags.yaml"

View file

@ -13,6 +13,19 @@ Feature: Basic reading and writing to a journal
| But I'm better. | But I'm better.
""" """
Scenario: Printing a journal that has multiline entries
Given we use the config "multiline.yaml"
When we run "jrnl -n 1"
Then we should get no error
and the output should be
"""
2013-06-09 15:39 Multiple line entry.
| This is the first line.
| This line doesn't have any ending punctuation
|
| There is a blank line above this.
"""
Scenario: Writing an entry from command line Scenario: Writing an entry from command line
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
@ -23,12 +36,12 @@ Feature: Basic reading and writing to a journal
@skip_win @skip_win
Scenario: Writing an empty entry from the editor Scenario: Writing an empty entry from the editor
Given we use the config "editor.yaml" Given we use the config "editor.yaml"
When we open the editor and enter "" When we open the editor and enter nothing
Then we should see the message "[Nothing saved to file]" Then we should see the message "[Nothing saved to file]"
Scenario: Writing an empty entry from the command line Scenario: Writing an empty entry from the command line
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl" and enter "" When we run "jrnl" and enter nothing
Then the output should be Then the output should be
""" """
@ -41,6 +54,14 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -on 'june 6 2013' --short" When we run "jrnl -on 'june 6 2013' --short"
Then the output should be "2013-06-10 15:40 Life is good." Then the output should be "2013-06-10 15:40 Life is good."
Scenario: Emoji support
Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘"
Then we should see the message "Entry added"
When we run "jrnl -n 1"
Then the output should contain "🌞"
and the output should contain "🐘"
Scenario: Writing an entry at the prompt Scenario: Writing an entry at the prompt
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive." When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive."
@ -64,3 +85,11 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -on 2013-06-10 -s" When we run "jrnl -on 2013-06-10 -s"
Then the output should be "2013-06-10 15:40 Life is good." Then the output should be "2013-06-10 15:40 Life is good."
Scenario: Invalid color configuration
Given we use the config "invalid_color.yaml"
When we run "jrnl -on 2013-06-10 -s"
Then the output should be
"""
2013-06-10 15:40 Life is good.
"""
And we should get no error

View file

@ -10,3 +10,8 @@ tagsymbols: "@"
template: false template: false
timeformat: "%Y-%m-%d %H:%M" timeformat: "%Y-%m-%d %H:%M"
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -10,3 +10,8 @@ tagsymbols: '@'
template: false template: false
timeformat: '%Y-%m-%d %H:%M' timeformat: '%Y-%m-%d %H:%M'
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
journals:
default: features/journals/bug780.dayone
linewrap: 80
tagsymbols: '@'
template: false
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,17 @@
default_hour: 9
default_minute: 0
editor: ""
encrypt: false
highlight: true
journals:
default: features/journals/simple.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"
colors:
date: not-a-color
title: also-not-a-color
body: still-no-color
tags: me-too

View file

@ -10,3 +10,8 @@ linewrap: 80
tagsymbols: '@' tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M' timeformat: '%Y-%m-%d %H:%M'
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -0,0 +1,17 @@
default_hour: 9
default_minute: 0
editor: ""
encrypt: false
highlight: true
journals:
default: features/journals/multiline-tags.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -0,0 +1,17 @@
default_hour: 9
default_minute: 0
editor: ""
encrypt: false
highlight: true
journals:
default: features/journals/multiline.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: ""
encrypt: false
highlight: true
journals:
default: features/journals/simple.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

@ -10,3 +10,8 @@ linewrap: 80
tagsymbols: '@' tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M' timeformat: '%Y-%m-%d %H:%M'
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -10,3 +10,8 @@ linewrap: 80
tagsymbols: '@' tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M' timeformat: '%Y-%m-%d %H:%M'
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -10,3 +10,8 @@ linewrap: 80
tagsymbols: '@' tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M' timeformat: '%Y-%m-%d %H:%M'
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -10,3 +10,8 @@ tagsymbols: "@"
template: false template: false
timeformat: "%Y-%m-%d %H:%M" timeformat: "%Y-%m-%d %H:%M"
indent_character: "|" indent_character: "|"
colors:
date: none
title: none
body: none
tags: none

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Activity</key>
<string>Stationary</string>
<key>Creation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Entry Text</key>
<string></string>
<key>Starred</key>
<false />
<key>UUID</key>
<string>48A25033B34047C591160A4480197D8B</string>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>PC</string>
<key>Generation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Host Name</key>
<string>LE-TREPORT</string>
<key>OS Agent</key>
<string>Microsoft Windows/10 Home</string>
<key>Software Agent</key>
<string>Journaley/2.1</string>
</dict>
<key>Tags</key>
<array>
<string>i_have_no_body</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,7 @@
[2013-06-09 15:39] Multiple @line entry with @tags.
Tag with @punctuation. afterwards
@TagOnLineAloneWithOutPunctuation
@TagOnLineAloneWithPunctuation.
Text before @tag. And After.
@hi. Hello
hi Hello

View file

@ -0,0 +1,5 @@
[2013-06-09 15:39] Multiple line entry.
This is the first line.
This line doesn't have any ending punctuation
There is a blank line above this.

View file

@ -1,7 +1,5 @@
Feature: Dayone specific implementation details. Feature: Dayone specific implementation details.
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading a DayOne Journal Scenario: Loading a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl -from 'feb 2013'" When we run "jrnl -from 'feb 2013'"
@ -15,7 +13,7 @@ Feature: Dayone specific implementation details.
2013-07-17 11:38 This entry is starred! 2013-07-17 11:38 This entry is starred!
""" """
# fails when system time is UTC (as on Travis-CI) # broken still
@skip @skip
Scenario: Entries without timezone information will be interpreted as in the current timezone Scenario: Entries without timezone information will be interpreted as in the current timezone
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
@ -23,7 +21,6 @@ Feature: Dayone specific implementation details.
Then we should get no error Then we should get no error
and the output should contain "2013-01-17T18:37Z" in the local time and the output should contain "2013-01-17T18:37Z" in the local time
@skip
Scenario: Writing into Dayone Scenario: Writing into Dayone
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl 01 may 1979: Being born hurts." When we run "jrnl 01 may 1979: Being born hurts."
@ -33,8 +30,6 @@ Feature: Dayone specific implementation details.
1979-05-01 09:00 Being born hurts. 1979-05-01 09:00 Being born hurts.
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading tags from a DayOne Journal Scenario: Loading tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl --tags" When we run "jrnl --tags"
@ -44,8 +39,6 @@ Feature: Dayone specific implementation details.
@play : 1 @play : 1
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Saving tags from a DayOne Journal Scenario: Saving tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl A hard day at @work" When we run "jrnl A hard day at @work"
@ -56,8 +49,6 @@ Feature: Dayone specific implementation details.
@play : 1 @play : 1
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Filtering by tags from a DayOne Journal Scenario: Filtering by tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl @work" When we run "jrnl @work"
@ -66,8 +57,6 @@ Feature: Dayone specific implementation details.
2013-05-17 11:39 This entry has tags! 2013-05-17 11:39 This entry has tags!
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Exporting dayone to json Scenario: Exporting dayone to json
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl --export json" When we run "jrnl --export json"

View file

@ -23,9 +23,3 @@ Feature: Zapped Dayone bugs stay dead!
2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03.
| I'm feeling sore because I forgot to stretch. | I'm feeling sore because I forgot to stretch.
""" """
Scenario: Opening an folder that's not a DayOne folder gives a nice error message
Given we use the config "empty_folder.yaml"
When we run "jrnl Herro"
Then we should get an error
Then we should see the message "is a directory, but doesn't seem to be a DayOne journal either"

View file

@ -4,21 +4,20 @@ Feature: Exporting a Journal
Given we use the config "tags.yaml" Given we use the config "tags.yaml"
When we run "jrnl --export json" When we run "jrnl --export json"
Then we should get no error Then we should get no error
and the output should be parsable as json And the output should be parsable as json
and "entries" in the json output should have 2 elements And "entries" in the json output should have 2 elements
and "tags" in the json output should contain "@idea" And "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal" And "tags" in the json output should contain "@journal"
and "tags" in the json output should contain "@dan" And "tags" in the json output should contain "@dan"
Scenario: Exporting using filters should only export parts of the journal Scenario: Exporting using filters should only export parts of the journal
Given we use the config "tags.yaml" Given we use the config "tags.yaml"
When we run "jrnl -until 'may 2013' --export json" When we run "jrnl -until 'may 2013' --export json"
# Then we should get no error
Then the output should be parsable as json Then the output should be parsable as json
and "entries" in the json output should have 1 element And "entries" in the json output should have 1 element
and "tags" in the json output should contain "@idea" And "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal" And "tags" in the json output should contain "@journal"
and "tags" in the json output should not contain "@dan" And "tags" in the json output should not contain "@dan"
Scenario: Exporting using custom templates Scenario: Exporting using custom templates
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
@ -83,3 +82,57 @@ Feature: Exporting a Journal
More stuff More stuff
more stuff again more stuff again
""" """
Scenario: Exporting to XML
Given we use the config "tags.yaml"
When we run "jrnl --export xml"
Then the output should be a valid XML string
And "entries" node in the xml output should have 2 elements
And "tags" in the xml output should contain ["@idea", "@journal", "@dan"]
Scenario: Exporting tags
Given we use the config "tags.yaml"
When we run "jrnl --export tags"
Then the output should be
"""
@idea : 2
@journal : 1
@dan : 1
"""
Scenario: Exporting fancy
Given we use the config "tags.yaml"
When we run "jrnl --export fancy"
Then the output should be
"""
2013-04-09 15:39
I have an @idea:
(1) write a command line @journal software
(2) ???
(3) PROFIT!
2013-06-10 15:40
I met with @dan.
As alway's he shared his latest @idea on how to rule the world with me.
inst
"""
Scenario: Export to yaml
Given we use the config "tags.yaml"
And we created a directory named "exported_journal"
When we run "jrnl --export yaml -o exported_journal"
Then "exported_journal" should contain the files ["2013-04-09_i-have-an-idea.md", "2013-06-10_i-met-with-dan.md"]
And the content of exported yaml "exported_journal/2013-04-09_i-have-an-idea.md" should be
"""
title: I have an @idea:
date: 2013-04-09 15:39
stared: False
tags: idea, journal
(1) write a command line @journal software
(2) ???
(3) PROFIT!
"""

42
features/folder.feature Normal file
View file

@ -0,0 +1,42 @@
Feature: Testing a journal with a root directory and multiple files in the format of yyyy/mm/dd.txt
Scenario: Opening an folder that's not a DayOne folder should treat as folder journal
Given we use the config "empty_folder.yaml"
When we run "jrnl 23 july 2013: Testing folder journal."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should be
"""
2013-07-23 09:00 Testing folder journal.
"""
Scenario: Adding entries to a Folder journal should generate date files
Given we use the config "empty_folder.yaml"
When we run "jrnl 23 July 2013: Testing folder journal."
Then we should see the message "Entry added"
When the journal directory is listed
Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
Given we use the config "empty_folder.yaml"
When we run "jrnl 23 July 2013: Testing folder journal."
And we run "jrnl 3/7/2014: Second entry of journal."
Then we should see the message "Entry added"
When the journal directory is listed
Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
Then the output should contain "2014/03/07.txt" or "2014\03\07.txt"
Scenario: Out of order entries to a Folder journal should be listed in date order
Given we use the config "empty_folder.yaml"
When we run "jrnl 3/7/2014 4:37pm: Second entry of journal."
Then we should see the message "Entry added"
When we run "jrnl 23 July 2013: Testing folder journal."
Then we should see the message "Entry added"
When we run "jrnl -2"
Then the output should be
"""
2013-07-23 09:00 Testing folder journal.
2014-03-07 16:37 Second entry of journal.
"""

View file

@ -1,7 +1,7 @@
Feature: Zapped bugs should stay dead. Feature: Zapped bugs should stay dead.
Scenario: Writing an entry does not print the entire journal Scenario: Writing an entry does not print the entire journal
# https://github.com/maebert/jrnl/issues/87 # https://github.com/jrnl-org/jrnl/issues/87
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
Then we should see the message "Entry added" Then we should see the message "Entry added"
@ -9,21 +9,14 @@ Feature: Zapped bugs should stay dead.
Then the output should not contain "Life is good" Then the output should not contain "Life is good"
Scenario: Date with time should be parsed correctly Scenario: Date with time should be parsed correctly
# https://github.com/maebert/jrnl/issues/117 # https://github.com/jrnl-org/jrnl/issues/117
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 2013-11-30 15:42: Project Started." When we run "jrnl 2013-11-30 15:42: Project Started."
Then we should see the message "Entry added" Then we should see the message "Entry added"
and the journal should contain "[2013-11-30 15:42] Project Started." and the journal should contain "[2013-11-30 15:42] Project Started."
Scenario: Date in the future should be parsed correctly
# https://github.com/maebert/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Loading entry with ambiguous time stamp Scenario: Loading entry with ambiguous time stamp
#https://github.com/maebert/jrnl/issues/153 #https://github.com/jrnl-org/jrnl/issues/153
Given we use the config "bug153.yaml" Given we use the config "bug153.yaml"
When we run "jrnl -1" When we run "jrnl -1"
Then we should get no error Then we should get no error
@ -32,6 +25,19 @@ Feature: Zapped bugs should stay dead.
2013-10-27 03:27 Some text. 2013-10-27 03:27 Some text.
""" """
Scenario: Date in the future should be parsed correctly
# https://github.com/jrnl-org/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Empty DayOne entry bodies should not error
# https://github.com/jrnl-org/jrnl/issues/780
Given we use the config "bug780.yaml"
When we run "jrnl --short"
Then we should get no error
Scenario: Title with an embedded period. Scenario: Title with an embedded period.
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic." When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic."

View file

@ -3,7 +3,6 @@ from unittest.mock import patch
from behave import given, when, then from behave import given, when, then
from jrnl import cli, install, Journal, util, plugins from jrnl import cli, install, Journal, util, plugins
from jrnl import __version__ from jrnl import __version__
from dateutil import parser as date_parser
from collections import defaultdict from collections import defaultdict
try: try:
@ -11,7 +10,9 @@ try:
except ImportError: except ImportError:
import parsedatetime as pdt import parsedatetime as pdt
import time import time
from codecs import encode, decode
import os import os
import ast
import json import json
import yaml import yaml
import keyring import keyring
@ -81,18 +82,15 @@ def set_config(context, config_file):
cf.write("version: {}".format(__version__)) cf.write("version: {}".format(__version__))
@when('we open the editor and enter ""')
@when('we open the editor and enter "{text}"') @when('we open the editor and enter "{text}"')
@when("we open the editor and enter nothing")
def open_editor_and_enter(context, text=""): def open_editor_and_enter(context, text=""):
text = text or context.text text = text or context.text or ""
def _mock_editor_function(command): def _mock_editor_function(command):
tmpfile = command[-1] tmpfile = command[-1]
with open(tmpfile, "w+") as f: with open(tmpfile, "w+") as f:
if text is not None:
f.write(text) f.write(text)
else:
f.write("")
return tmpfile return tmpfile
@ -118,7 +116,7 @@ def _mock_input(inputs):
@when('we run "{command}" and enter') @when('we run "{command}" and enter')
@when('we run "{command}" and enter ""') @when('we run "{command}" and enter nothing')
@when('we run "{command}" and enter "{inputs}"') @when('we run "{command}" and enter "{inputs}"')
def run_with_input(context, command, inputs=""): def run_with_input(context, command, inputs=""):
# create an iterator through all inputs. These inputs will be fed one by one # create an iterator through all inputs. These inputs will be fed one by one
@ -185,53 +183,6 @@ def no_error(context):
assert context.exit_status == 0, context.exit_status assert context.exit_status == 0, context.exit_status
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be") @then("the output should be")
@then('the output should be "{text}"') @then('the output should be "{text}"')
def check_output(context, text=None): def check_output(context, text=None):
@ -258,10 +209,11 @@ def check_output_time_inline(context, text):
@then("the output should contain") @then("the output should contain")
@then('the output should contain "{text}"') @then('the output should contain "{text}"')
def check_output_inline(context, text=None): @then('the output should contain "{text}" or "{text2}"')
def check_output_inline(context, text=None, text2=None):
text = text or context.text text = text or context.text
out = context.stdout_capture.getvalue() out = context.stdout_capture.getvalue()
assert text in out, text assert text in out or text2 in out, text or text2
@then('the output should not contain "{text}"') @then('the output should not contain "{text}"')
@ -300,8 +252,15 @@ def journal_doesnt_exist(context, journal_name="default"):
@then('the config should have "{key}" set to "{value}"') @then('the config should have "{key}" set to "{value}"')
@then('the config for journal "{journal}" should have "{key}" set to "{value}"') @then('the config for journal "{journal}" should have "{key}" set to "{value}"')
def config_var(context, key, value, journal=None): def config_var(context, key, value, journal=None):
if not value[0] == "{":
t, value = value.split(":") t, value = value.split(":")
value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](value) value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](
value
)
else:
# Handle value being a dictionary
value = ast.literal_eval(value)
config = util.load_config(install.CONFIG_FILE_PATH) config = util.load_config(install.CONFIG_FILE_PATH)
if journal: if journal:
config = config["journals"][journal] config = config["journals"][journal]
@ -318,6 +277,17 @@ def check_journal_entries(context, number, journal_name="default"):
assert len(journal.entries) == number assert len(journal.entries) == number
@when("the journal directory is listed")
def list_journal_directory(context, journal="default"):
files = []
with open(install.CONFIG_FILE_PATH) as config_file:
config = yaml.load(config_file, Loader=yaml.FullLoader)
journal_path = config["journals"][journal]
for root, dirnames, f in os.walk(journal_path):
for file in f:
print(os.path.join(root, file))
@then("fail") @then("fail")
def debug_fail(context): def debug_fail(context):
assert False assert False

View file

@ -0,0 +1,124 @@
import json
import os
import shutil
from xml.etree import ElementTree
from behave import then, given
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be a valid XML string")
def assert_valid_xml_string(context):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
assert xml_tree, output
@then('"entries" node in the xml output should have {number:d} elements')
def assert_xml_output_entries_count(context, number):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "entries" in xml_tags, str(list(xml_tags))
actual_entry_count = len(xml_tree.find("entries"))
assert actual_entry_count == number, actual_entry_count
@then('"tags" in the xml output should contain {expected_tags_json_list}')
def assert_xml_output_tags(context, expected_tags_json_list):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "tags" in xml_tags, str(list(xml_tags))
expected_tags = json.loads(expected_tags_json_list)
actual_tags = set(t.attrib["name"] for t in xml_tree.find("tags"))
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
@given('we created a directory named "{dir_name}"')
def create_directory(context, dir_name):
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
os.mkdir(dir_name)
@then('"{dir_name}" should contain the files {expected_files_json_list}')
def assert_dir_contains_files(context, dir_name, expected_files_json_list):
actual_files = os.listdir(dir_name)
expected_files = json.loads(expected_files_json_list)
assert actual_files == expected_files, [actual_files, expected_files]
@then('the content of exported yaml "{file_path}" should be')
def assert_exported_yaml_file_content(context, file_path):
expected_content = context.text.strip().splitlines()
with open(file_path, "r") as f:
actual_content = f.read().strip().splitlines()
for actual_line, expected_line in zip(actual_content, expected_content):
if actual_line.startswith("tags: ") and expected_line.startswith("tags: "):
assert_equal_tags_ignoring_order(actual_line, expected_line)
else:
assert actual_line.strip() == expected_line.strip(), [
actual_line.strip(),
expected_line.strip(),
]
def assert_equal_tags_ignoring_order(actual_line, expected_line):
actual_tags = set(tag.strip() for tag in actual_line[len("tags: ") :].split(","))
expected_tags = set(
tag.strip() for tag in expected_line[len("tags: ") :].split(",")
)
assert actual_tags == expected_tags, [actual_tags, expected_tags]

View file

@ -82,3 +82,19 @@ Feature: Tagging
""" """
@thought : 2 @thought : 2
""" """
Scenario: Printing a journal that has multiline entries with tags
Given we use the config "multiline-tags.yaml"
When we run "jrnl -n 1"
Then we should get no error
and the output should be
"""
2013-06-09 15:39 Multiple @line entry with @tags.
| Tag with @punctuation. afterwards
| @TagOnLineAloneWithOutPunctuation
| @TagOnLineAloneWithPunctuation.
| Text before @tag. And After.
| @hi. Hello
| hi Hello
"""

View file

@ -22,6 +22,11 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
Then the output should contain "Password" Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good" and the output should contain "2013-06-10 15:40 Life is good"
Scenario: Upgrading a config without colors to colors
Given we use the config "no_colors.yaml"
When we run "jrnl -n 1"
Then the config should have "colors" set to "{'date':'none', 'title':'none', 'body':'none', 'tags':'none'}"
Scenario: Upgrade and parse journals with little endian date format Scenario: Upgrade and parse journals with little endian date format
Given we use the config "upgrade_from_195_little_endian_dates.json" Given we use the config "upgrade_from_195_little_endian_dates.json"
When we run "jrnl -9" and enter "Y" When we run "jrnl -9" and enter "Y"
@ -32,3 +37,4 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
10.06.2013 15:40 He said "[this] is the best time to be alive". 10.06.2013 15:40 He said "[this] is the best time to be alive".
""" """
Then the journal should have 2 entries Then the journal should have 2 entries

View file

@ -52,7 +52,11 @@ class DayOne(Journal.Journal):
except (KeyError, pytz.exceptions.UnknownTimeZoneError): except (KeyError, pytz.exceptions.UnknownTimeZoneError):
timezone = tzlocal.get_localzone() timezone = tzlocal.get_localzone()
date = dict_entry["Creation Date"] date = dict_entry["Creation Date"]
# convert the date to UTC rather than keep messing with
# timezones
if timezone.zone != "UTC":
date = date + timezone.utcoffset(date, is_dst=False) date = date + timezone.utcoffset(date, is_dst=False)
entry = Entry.Entry( entry = Entry.Entry(
self, self,
date, date,

View file

@ -23,7 +23,7 @@ def make_key(password):
length=32, length=32,
# Salt is hard-coded # Salt is hard-coded
salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8", salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8",
iterations=100000, iterations=100_000,
backend=default_backend(), backend=default_backend(),
) )
key = kdf.derive(password) key = kdf.derive(password)

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
import re import re
import textwrap import ansiwrap
from datetime import datetime from datetime import datetime
from .util import split_title from .util import split_title, colorize, highlight_tags_with_background_color
class Entry: class Entry:
@ -22,7 +22,7 @@ class Entry:
def _parse_text(self): def _parse_text(self):
raw_text = self.text raw_text = self.text
lines = raw_text.splitlines() lines = raw_text.splitlines()
if lines[0].strip().endswith("*"): if lines and lines[0].strip().endswith("*"):
self.starred = True self.starred = True
raw_text = lines[0].strip("\n *") + "\n" + "\n".join(lines[1:]) raw_text = lines[0].strip("\n *") + "\n" + "\n".join(lines[1:])
self._title, self._body = split_title(raw_text) self._title, self._body = split_title(raw_text)
@ -49,7 +49,7 @@ class Entry:
@staticmethod @staticmethod
def tag_regex(tagsymbols): def tag_regex(tagsymbols):
pattern = fr"(?u)(?:^|\s)([{tagsymbols}][-+*#/\w]+)" pattern = fr"(?<!\S)([{tagsymbols}][-+*#/\w]+)"
return re.compile(pattern) return re.compile(pattern)
def _parse_tags(self): def _parse_tags(self):
@ -73,31 +73,77 @@ class Entry:
def pprint(self, short=False): def pprint(self, short=False):
"""Returns a pretty-printed version of the entry. """Returns a pretty-printed version of the entry.
If short is true, only print the title.""" If short is true, only print the title."""
date_str = self.date.strftime(self.journal.config["timeformat"]) # Handle indentation
if self.journal.config["indent_character"]: if self.journal.config["indent_character"]:
indent = self.journal.config["indent_character"].rstrip() + " " indent = self.journal.config["indent_character"].rstrip() + " "
else: else:
indent = "" indent = ""
if not short and self.journal.config["linewrap"]:
title = textwrap.fill( date_str = colorize(
date_str + " " + self.title, self.journal.config["linewrap"] self.date.strftime(self.journal.config["timeformat"]),
self.journal.config["colors"]["date"],
bold=True,
) )
body = "\n".join(
[ if not short and self.journal.config["linewrap"]:
textwrap.fill( # Color date / title and bold title
title = ansiwrap.fill(
date_str
+ " "
+ highlight_tags_with_background_color(
self,
self.title,
self.journal.config["colors"]["title"],
is_title=True,
),
self.journal.config["linewrap"],
)
body = highlight_tags_with_background_color(
self, self.body.rstrip(" \n"), self.journal.config["colors"]["body"]
)
body_text = [
colorize(
ansiwrap.fill(
line, line,
self.journal.config["linewrap"], self.journal.config["linewrap"],
initial_indent=indent, initial_indent=indent,
subsequent_indent=indent, subsequent_indent=indent,
drop_whitespace=True, drop_whitespace=True,
),
self.journal.config["colors"]["body"],
) )
or indent or indent
for line in self.body.rstrip(" \n").splitlines() for line in body.rstrip(" \n").splitlines()
]
# ansiwrap doesn't handle lines with only the "\n" character and some
# ANSI escapes properly, so we have this hack here to make sure the
# beginning of each line has the indent character and it's colored
# properly. textwrap doesn't have this issue, however, it doesn't wrap
# the strings properly as it counts ANSI escapes as literal characters.
# TL;DR: I'm sorry.
body = "\n".join(
[
colorize(indent, self.journal.config["colors"]["body"]) + line
if not ansiwrap.strip_color(line).startswith(indent)
else line
for line in body_text
] ]
) )
else: else:
title = date_str + " " + self.title.rstrip("\n ") title = (
body = self.body.rstrip("\n ") date_str
+ " "
+ highlight_tags_with_background_color(
self,
self.title.rstrip("\n"),
self.journal.config["colors"]["title"],
is_title=True,
)
)
body = highlight_tags_with_background_color(
self, self.body.rstrip("\n "), self.journal.config["colors"]["body"]
)
# Suppress bodies that are just blanks and new lines. # Suppress bodies that are just blanks and new lines.
has_body = len(self.body) > 20 or not all( has_body = len(self.body) > 20 or not all(

93
jrnl/FolderJournal.py Normal file
View file

@ -0,0 +1,93 @@
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import, unicode_literals
from . import Entry
from . import Journal
import codecs
import os
import fnmatch
def get_files(journal_config):
"""Searches through sub directories starting with journal_config and find all text files"""
filenames = []
for root, dirnames, f in os.walk(journal_config):
for filename in fnmatch.filter(f, "*.txt"):
filenames.append(os.path.join(root, filename))
return filenames
class Folder(Journal.Journal):
"""A Journal handling multiple files in a folder"""
def __init__(self, **kwargs):
self.entries = []
self._diff_entry_dates = []
super(Folder, self).__init__(**kwargs)
def open(self):
filenames = []
self.entries = []
filenames = get_files(self.config["journal"])
for filename in filenames:
with codecs.open(filename, "r", "utf-8") as f:
journal = f.read()
self.entries.extend(self._parse(journal))
self.sort()
return self
def write(self):
"""Writes only the entries that have been modified into proper files."""
# Create a list of dates of modified entries. Start with diff_entry_dates
modified_dates = self._diff_entry_dates
seen_dates = set(self._diff_entry_dates)
for e in self.entries:
if e.modified:
if e.date not in seen_dates:
modified_dates.append(e.date)
seen_dates.add(e.date)
# For every date that had a modified entry, write to a file
for d in modified_dates:
write_entries = []
filename = os.path.join(
self.config["journal"],
d.strftime("%Y"),
d.strftime("%m"),
d.strftime("%d") + ".txt",
)
dirname = os.path.dirname(filename)
# create directory if it doesn't exist
if not os.path.exists(dirname):
os.makedirs(dirname)
for e in self.entries:
if (
e.date.year == d.year
and e.date.month == d.month
and e.date.day == d.day
):
write_entries.append(e)
journal = "\n".join([e.__str__() for e in write_entries])
with codecs.open(filename, "w", "utf-8") as journal_file:
journal_file.write(journal)
# look for and delete empty files
filenames = []
filenames = get_files(self.config["journal"])
for filename in filenames:
if os.stat(filename).st_size <= 0:
# print("empty file: {}".format(filename))
os.remove(filename)
def parse_editable_str(self, edited):
"""Parses the output of self.editable_str and updates it's entries."""
mod_entries = self._parse(edited)
diff_entries = set(self.entries) - set(mod_entries)
for e in diff_entries:
self._diff_entry_dates.append(e.date)
# Match those entries that can be found in self.entries and set
# these to modified, so we can get a count of how many entries got
# modified and how many got deleted later.
for entry in mod_entries:
entry.modified = not any(entry == old_entry for old_entry in self.entries)
self.entries = mod_entries

View file

@ -153,20 +153,7 @@ class Journal:
def pprint(self, short=False): def pprint(self, short=False):
"""Prettyprints the journal's entries""" """Prettyprints the journal's entries"""
sep = "\n" return "\n".join([e.pprint(short=short) for e in self.entries])
pp = sep.join([e.pprint(short=short) for e in self.entries])
if self.config["highlight"]: # highlight tags
if self.search_tags:
for tag in self.search_tags:
tagre = re.compile(re.escape(tag), re.IGNORECASE)
pp = re.sub(tagre, lambda match: util.colorize(match.group(0)), pp)
else:
pp = re.sub(
Entry.Entry.tag_regex(self.config["tagsymbols"]),
lambda match: util.colorize(match.group(0)),
pp,
)
return pp
def __str__(self): def __str__(self):
return self.pprint() return self.pprint()
@ -378,12 +365,9 @@ def open_journal(name, config, legacy=False):
return DayOneJournal.DayOne(**config).open() return DayOneJournal.DayOne(**config).open()
else: else:
print( from . import FolderJournal
f"[Error: {config['journal']} is a directory, but doesn't seem to be a DayOne journal either.",
file=sys.stderr,
)
sys.exit(1) return FolderJournal.Folder(**config).open()
if not config["encrypt"]: if not config["encrypt"]:
if legacy: if legacy:

View file

@ -15,6 +15,7 @@ from .util import ERROR_COLOR, RESET_COLOR, UserAbort
import jrnl import jrnl
import argparse import argparse
import sys import sys
import re
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -173,7 +174,11 @@ def parse_args(args=None):
action="store_true", action="store_true",
) )
return parser.parse_args(args) # Handle '-123' as a shortcut for '-n 123'
num = re.compile(r"^-(\d+)$")
if args is None:
args = sys.argv[1:]
return parser.parse_args([num.sub(r"-n \1", a) for a in args])
def guess_mode(args, config): def guess_mode(args, config):
@ -309,14 +314,6 @@ def run(manual_args=None):
config = util.scope_config(config, journal_name) config = util.scope_config(config, journal_name)
# If the first remaining argument looks like e.g. '-3', interpret that as a limiter
if not args.limit and args.text and args.text[0].startswith("-"):
try:
args.limit = int(args.text[0].lstrip("-"))
args.text = args.text[1:]
except ValueError:
pass
log.debug('Using journal "%s"', journal_name) log.debug('Using journal "%s"', journal_name)
mode_compose, mode_export, mode_import = guess_mode(args, config) mode_compose, mode_export, mode_import = guess_mode(args, config)

View file

@ -1,62 +0,0 @@
#!/usr/bin/env python
from .util import ERROR_COLOR, RESET_COLOR
from .util import slugify
from .plugins.template import Template
import os
class Exporter:
"""This Exporter can convert entries and journals into text files."""
def __init__(self, format):
with open("jrnl/templates/" + format + ".template") as f:
front_matter, body = f.read().strip("-\n").split("---", 2)
self.template = Template(body)
def export_entry(self, entry):
"""Returns a string representation of a single entry."""
return str(entry)
def _get_vars(self, journal):
return {"journal": journal, "entries": journal.entries, "tags": journal.tags}
def export_journal(self, journal):
"""Returns a string representation of an entire journal."""
return self.template.render_block("journal", **self._get_vars(journal))
def write_file(self, journal, path):
"""Exports a journal into a single file."""
try:
with open(path, "w", encoding="utf-8") as f:
f.write(self.export_journal(journal))
return f"[Journal exported to {path}]"
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
def make_filename(self, entry):
return entry.date.strftime(
"%Y-%m-%d_{}.{}".format(slugify(entry.title), self.extension)
)
def write_files(self, journal, path):
"""Exports a journal into individual files for each entry."""
for entry in journal.entries:
try:
full_path = os.path.join(path, self.make_filename(entry))
with open(full_path, "w", encoding="utf-8") as f:
f.write(self.export_entry(entry))
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
return f"[Journal exported to {path}]"
def export(self, journal, format="text", output=None):
"""Exports to individual files if output is an existing path, or into
a single file if output is a file name, or returns the exporter's
representation as string if output is None."""
if output and os.path.isdir(output): # multiple files
return self.write_files(journal, output)
elif output: # single file
return self.write_file(journal, output)
else:
return self.export_journal(journal)

View file

@ -9,7 +9,7 @@ from . import upgrade
from . import __version__ from . import __version__
from .Journal import PlainJournal from .Journal import PlainJournal
from .EncryptedJournal import EncryptedJournal from .EncryptedJournal import EncryptedJournal
from .util import UserAbort from .util import UserAbort, verify_config
import yaml import yaml
import logging import logging
import sys import sys
@ -47,7 +47,7 @@ def module_exists(module_name):
default_config = { default_config = {
"version": __version__, "version": __version__,
"journals": {DEFAULT_JOURNAL_KEY: JOURNAL_FILE_PATH}, "journals": {"default": JOURNAL_FILE_PATH},
"editor": os.getenv("VISUAL") or os.getenv("EDITOR") or "", "editor": os.getenv("VISUAL") or os.getenv("EDITOR") or "",
"encrypt": False, "encrypt": False,
"template": False, "template": False,
@ -58,6 +58,7 @@ default_config = {
"highlight": True, "highlight": True,
"linewrap": 79, "linewrap": 79,
"indent_character": "|", "indent_character": "|",
"colors": {"date": "none", "title": "none", "body": "none", "tags": "none",},
} }
@ -114,6 +115,7 @@ def load_or_install_jrnl():
sys.exit(1) sys.exit(1)
upgrade_config(config) upgrade_config(config)
verify_config(config)
return config return config
else: else:

View file

@ -4,24 +4,24 @@ import sys
import os import os
import getpass as gp import getpass as gp
import yaml import yaml
import colorama
if "win32" in sys.platform: if "win32" in sys.platform:
import colorama
colorama.init() colorama.init()
import re import re
import tempfile import tempfile
import subprocess import subprocess
import unicodedata import unicodedata
import shlex import shlex
from string import punctuation, whitespace
import logging import logging
from typing import Optional, Callable from typing import Optional, Callable
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
WARNING_COLOR = "\033[33m" WARNING_COLOR = colorama.Fore.YELLOW
ERROR_COLOR = "\033[31m" ERROR_COLOR = colorama.Fore.RED
RESET_COLOR = "\033[0m" RESET_COLOR = colorama.Fore.RESET
# Based on Segtok by Florian Leitner # Based on Segtok by Florian Leitner
# https://github.com/fnl/segtok # https://github.com/fnl/segtok
@ -140,6 +140,27 @@ def scope_config(config, journal_name):
return config return config
def verify_config(config):
"""
Ensures the keys set for colors are valid colorama.Fore attributes, or "None"
:return: True if all keys are set correctly, False otherwise
"""
all_valid_colors = True
for key, color in config["colors"].items():
upper_color = color.upper()
if upper_color == "NONE":
continue
if not getattr(colorama.Fore, upper_color, None):
print(
"[{2}ERROR{3}: {0} set to invalid color: {1}]".format(
key, color, ERROR_COLOR, RESET_COLOR
),
file=sys.stderr,
)
all_valid_colors = False
return all_valid_colors
def get_text_from_editor(config, template=""): def get_text_from_editor(config, template=""):
filehandle, tmpfile = tempfile.mkstemp(prefix="jrnl", text=True, suffix=".txt") filehandle, tmpfile = tempfile.mkstemp(prefix="jrnl", text=True, suffix=".txt")
os.close(filehandle) os.close(filehandle)
@ -165,9 +186,75 @@ def get_text_from_editor(config, template=""):
return raw return raw
def colorize(string): def colorize(string, color, bold=False):
"""Returns the string wrapped in cyan ANSI escape""" """Returns the string colored with colorama.Fore.color. If the color set by
return f"\033[36m{string}\033[39m" the user is "NONE" or the color doesn't exist in the colorama.Fore attributes,
it returns the string without any modification."""
color_escape = getattr(colorama.Fore, color.upper(), None)
if not color_escape:
return string
elif not bold:
return color_escape + string + colorama.Fore.RESET
else:
return colorama.Style.BRIGHT + color_escape + string + colorama.Style.RESET_ALL
def highlight_tags_with_background_color(entry, text, color, is_title=False):
"""
Takes a string and colorizes the tags in it based upon the config value for
color.tags, while colorizing the rest of the text based on `color`.
:param entry: Entry object, for access to journal config
:param text: Text to be colorized
:param color: Color for non-tag text, passed to colorize()
:param is_title: Boolean flag indicating if the text is a title or not
:return: Colorized str
"""
def colorized_text_generator(fragments):
"""Efficiently generate colorized tags / text from text fragments.
Taken from @shobrook. Thanks, buddy :)
:param fragments: List of strings representing parts of entry (tag or word).
:rtype: List of tuples
:returns [(colorized_str, original_str)]"""
for part in fragments:
if part and part[0] not in config["tagsymbols"]:
yield (colorize(part, color, bold=is_title), part)
elif part:
yield (colorize(part, config["colors"]["tags"], bold=True), part)
config = entry.journal.config
if config["highlight"]: # highlight tags
if entry.journal.search_tags:
text_fragments = []
for tag in entry.journal.search_tags:
text_fragments.extend(
re.split(re.compile(re.escape(tag), re.IGNORECASE), text)
)
else:
text_fragments = re.split(entry.tag_regex(config["tagsymbols"]), text)
# Colorizing tags inside of other blocks of text
final_text = ""
previous_piece = ""
for colorized_piece, piece in colorized_text_generator(text_fragments):
# If this piece is entirely punctuation or whitespace or the start
# of a line or the previous piece was a tag or this piece is a tag,
# then add it to the final text without a leading space.
if (
all(char in punctuation + whitespace for char in piece)
or previous_piece.endswith("\n")
or (previous_piece and previous_piece[0] in config["tagsymbols"])
or piece[0] in config["tagsymbols"]
):
final_text += colorized_piece
else:
# Otherwise add a leading space and then append the piece.
final_text += " " + colorized_piece
previous_piece = piece
return final_text.lstrip()
else:
return text
def slugify(string): def slugify(string):

View file

@ -12,7 +12,7 @@ markdown_extensions:
- admonition - admonition
repo_url: https://github.com/jrnl-org/jrnl/ repo_url: https://github.com/jrnl-org/jrnl/
site_author: Manuel Ebert site_author: Manuel Ebert
site_description: Never Worry about Money Again. site_description: Collect your thoughts and notes without leaving the command line.
nav: nav:
- Overview: overview.md - Overview: overview.md
- Quickstart: installation.md - Quickstart: installation.md

514
poetry.lock generated
View file

@ -1,3 +1,14 @@
[[package]]
category = "main"
description = "textwrap, but savvy to ANSI colors and styles"
name = "ansiwrap"
optional = false
python-versions = "*"
version = "0.8.4"
[package.dependencies]
textwrap3 = ">=0.9.2"
[[package]] [[package]]
category = "dev" category = "dev"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
@ -22,6 +33,12 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.3.0" version = "19.3.0"
[package.extras]
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "behave is behaviour-driven development, Python style" description = "behave is behaviour-driven development, Python style"
@ -35,6 +52,10 @@ parse = ">=1.8.2"
parse-type = ">=0.4.2" parse-type = ">=0.4.2"
six = ">=1.11" six = ">=1.11"
[package.extras]
develop = ["coverage", "pytest (>=3.0)", "pytest-cov", "tox", "invoke (>=0.21.0)", "path.py (>=8.1.2)", "pycmd", "pathlib", "modernize (>=0.5)", "pylint"]
docs = ["sphinx (>=1.6)", "sphinx-bootstrap-theme (>=0.6)"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
@ -52,13 +73,16 @@ regex = "*"
toml = ">=0.9.4" toml = ">=0.9.4"
typed-ast = ">=1.4.0" typed-ast = ">=1.4.0"
[package.extras]
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
[[package]] [[package]]
category = "main" category = "main"
description = "Foreign Function Interface for Python calling C code." description = "Foreign Function Interface for Python calling C code."
name = "cffi" name = "cffi"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.13.2" version = "1.14.0"
[package.dependencies] [package.dependencies]
pycparser = "*" pycparser = "*"
@ -74,7 +98,6 @@ version = "7.0"
[[package]] [[package]]
category = "main" category = "main"
description = "Cross-platform colored terminal text." description = "Cross-platform colored terminal text."
marker = "sys_platform == \"win32\""
name = "colorama" name = "colorama"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
@ -92,6 +115,13 @@ version = "2.8"
cffi = ">=1.8,<1.11.3 || >1.11.3" cffi = ">=1.8,<1.11.3 || >1.11.3"
six = ">=1.4.1" six = ">=1.4.1"
[package.extras]
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"]
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
idna = ["idna (>=2.1)"]
pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Discover and load entry points from installed packages." description = "Discover and load entry points from installed packages."
@ -114,6 +144,14 @@ mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.5.0,<2.6.0" pycodestyle = ">=2.5.0,<2.6.0"
pyflakes = ">=2.1.0,<2.2.0" pyflakes = ">=2.1.0,<2.2.0"
[[package]]
category = "dev"
description = "Clean single-source support for Python 3 and 2"
name = "future"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "0.18.2"
[[package]] [[package]]
category = "main" category = "main"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
@ -121,11 +159,15 @@ marker = "python_version < \"3.8\""
name = "importlib-metadata" name = "importlib-metadata"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.3.0" version = "1.5.0"
[package.dependencies] [package.dependencies]
zipp = ">=0.5" zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
[[package]] [[package]]
category = "main" category = "main"
description = "Low-level, pure Python DBus protocol wrapper." description = "Low-level, pure Python DBus protocol wrapper."
@ -135,17 +177,23 @@ optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
version = "0.4.2" version = "0.4.2"
[package.extras]
dev = ["testpath"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "A very fast and expressive template engine." description = "A very fast and expressive template engine."
name = "jinja2" name = "jinja2"
optional = false optional = false
python-versions = "*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.10.3" version = "2.11.1"
[package.dependencies] [package.dependencies]
MarkupSafe = ">=0.23" MarkupSafe = ">=0.23"
[package.extras]
i18n = ["Babel (>=0.8)"]
[[package]] [[package]]
category = "main" category = "main"
description = "Store and access your passwords safely." description = "Store and access your passwords safely."
@ -162,6 +210,10 @@ secretstorage = "*"
python = "<3.8" python = "<3.8"
version = "*" version = "*"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-black-multipy", "pytest-cov"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Python LiveReload is an awesome tool for web developers" description = "Python LiveReload is an awesome tool for web developers"
@ -174,17 +226,39 @@ version = "2.6.1"
six = "*" six = "*"
tornado = "*" tornado = "*"
[[package]]
category = "dev"
description = "A Python implementation of Lunr.js"
name = "lunr"
optional = false
python-versions = "*"
version = "0.5.6"
[package.dependencies]
future = ">=0.16.0"
six = ">=1.11.0"
[package.dependencies.nltk]
optional = true
version = ">=3.2.5"
[package.extras]
languages = ["nltk (>=3.2.5)"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Python implementation of Markdown." description = "Python implementation of Markdown."
name = "markdown" name = "markdown"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" python-versions = ">=3.5"
version = "3.1.1" version = "3.2.1"
[package.dependencies] [package.dependencies]
setuptools = ">=36" setuptools = ">=36"
[package.extras]
testing = ["coverage", "pyyaml"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Safely add untrusted strings to HTML/XML markup." description = "Safely add untrusted strings to HTML/XML markup."
@ -206,25 +280,39 @@ category = "dev"
description = "Project documentation with Markdown." description = "Project documentation with Markdown."
name = "mkdocs" name = "mkdocs"
optional = false optional = false
python-versions = ">=2.7.9,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" python-versions = ">=3.5"
version = "1.0.4" version = "1.1"
[package.dependencies] [package.dependencies]
Jinja2 = ">=2.7.1" Jinja2 = ">=2.10.1"
Markdown = ">=2.3.1" Markdown = ">=3.2.1"
PyYAML = ">=3.10" PyYAML = ">=3.10"
click = ">=3.3" click = ">=3.3"
livereload = ">=2.5.1" livereload = ">=2.5.1"
tornado = ">=5.0" tornado = ">=5.0"
[package.dependencies.lunr]
extras = ["languages"]
version = "0.5.6"
[[package]] [[package]]
category = "main" category = "dev"
description = "More routines for operating on iterables, beyond itertools" description = "Natural Language Toolkit"
marker = "python_version < \"3.8\"" name = "nltk"
name = "more-itertools"
optional = false optional = false
python-versions = ">=3.5" python-versions = "*"
version = "8.0.2" version = "3.4.5"
[package.dependencies]
six = "*"
[package.extras]
all = ["pyparsing", "scikit-learn", "python-crfsuite", "matplotlib", "scipy", "gensim", "requests", "twython", "numpy"]
corenlp = ["requests"]
machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"]
plot = ["matplotlib"]
tgrep = ["pyparsing"]
twitter = ["twython"]
[[package]] [[package]]
category = "dev" category = "dev"
@ -246,6 +334,10 @@ version = "0.5.2"
parse = ">=1.8.4" parse = ">=1.8.4"
six = ">=1.11" six = ">=1.11"
[package.extras]
develop = ["coverage (>=4.4)", "pytest (>=3.2)", "pytest-cov", "tox (>=2.8)"]
docs = ["sphinx (>=1.2)"]
[[package]] [[package]]
category = "main" category = "main"
description = "Parse human-readable date/time text." description = "Parse human-readable date/time text."
@ -262,6 +354,12 @@ optional = false
python-versions = "*" python-versions = "*"
version = "1.7.2" version = "1.7.2"
[package.extras]
argon2 = ["argon2-cffi (>=18.2.0)"]
bcrypt = ["bcrypt (>=3.1.0)"]
build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-sptheme (>=1.10.0)"]
totp = ["cryptography"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
@ -335,8 +433,8 @@ category = "main"
description = "YAML parser and emitter for Python" description = "YAML parser and emitter for Python"
name = "pyyaml" name = "pyyaml"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "5.2" version = "5.3"
[[package]] [[package]]
category = "dev" category = "dev"
@ -344,7 +442,7 @@ description = "Alternative regular expression module, to replace re."
name = "regex" name = "regex"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "2019.12.20" version = "2020.2.20"
[[package]] [[package]]
category = "main" category = "main"
@ -353,19 +451,27 @@ marker = "sys_platform == \"linux\""
name = "secretstorage" name = "secretstorage"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
version = "3.1.1" version = "3.1.2"
[package.dependencies] [package.dependencies]
cryptography = "*" cryptography = "*"
jeepney = "*" jeepney = ">=0.4.2"
[[package]] [[package]]
category = "main" category = "main"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
name = "six" name = "six"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.13.0" version = "1.14.0"
[[package]]
category = "main"
description = "textwrap from Python 3.6 backport (plus a few tweaks)"
name = "textwrap3"
optional = false
python-versions = "*"
version = "0.9.2"
[[package]] [[package]]
category = "dev" category = "dev"
@ -389,7 +495,7 @@ description = "a fork of Python 2 and 3 ast modules with type comment support"
name = "typed-ast" name = "typed-ast"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.4.0" version = "1.4.1"
[[package]] [[package]]
category = "main" category = "main"
@ -408,56 +514,318 @@ description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\"" marker = "python_version < \"3.8\""
name = "zipp" name = "zipp"
optional = false optional = false
python-versions = ">=2.7" python-versions = ">=3.6"
version = "0.6.0" version = "3.0.0"
[package.dependencies] [package.extras]
more-itertools = "*" docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata] [metadata]
content-hash = "98e23837423d5d8621f14cbe592d209ef98e1926b7a3f94e0f88bb6be908aae8" content-hash = "98c4d0d25bb309075ca86c1ed3ed0d46b0fd1dad66510f8fe95b0ad350065df5"
python-versions = ">=3.6.0, <3.9.0" python-versions = ">=3.6.0, <3.9.0"
[metadata.hashes] [metadata.files]
appdirs = ["9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"] ansiwrap = [
asteval = ["5d64e18b8a72c2c7ae8f9b70d1f80b68bbcaa98c1c0d7047c35489d03209bc86"] {file = "ansiwrap-0.8.4-py2.py3-none-any.whl", hash = "sha256:7b053567c88e1ad9eed030d3ac41b722125e4c1271c8a99ade797faff1f49fb1"},
attrs = ["08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"] {file = "ansiwrap-0.8.4.zip", hash = "sha256:ca0c740734cde59bf919f8ff2c386f74f9a369818cdc60efe94893d01ea8d9b7"},
behave = ["b9662327aa53294c1351b0a9c369093ccec1d21026f050c3bd9b3e5cccf81a86", "ebda1a6c9e5bfe95c5f9f0a2794e01c7098b3dde86c10a95d8621c5907ff6f1c"] ]
black = ["1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", "c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"] appdirs = [
cffi = ["0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42", "0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04", "135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5", "19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54", "2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba", "291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57", "2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396", "2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12", "32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97", "3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43", "415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db", "42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3", "4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b", "4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579", "599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346", "5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159", "5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652", "62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e", "6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a", "6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506", "71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f", "74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d", "7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c", "7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20", "7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858", "8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc", "aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a", "ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3", "d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e", "d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410", "dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25", "e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b", "fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"] {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"] {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
colorama = ["7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", "e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"] ]
cryptography = ["02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c", "1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595", "369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad", "3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651", "44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2", "4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff", "58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d", "6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42", "7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d", "73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e", "7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912", "90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793", "971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13", "a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7", "b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0", "b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879", "d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f", "de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9", "df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2", "ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf", "fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"] asteval = [
entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] {file = "asteval-0.9.18.tar.gz", hash = "sha256:5d64e18b8a72c2c7ae8f9b70d1f80b68bbcaa98c1c0d7047c35489d03209bc86"},
flake8 = ["45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb", "49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"] ]
importlib-metadata = ["073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", "d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"] attrs = [
jeepney = ["0ba6d8c597e9bef1ebd18aaec595f942a264e25c1a48f164d46120eacaa2e9bb", "6f45dce1125cf6c58a1c88123d3831f36a789f9204fbad3172eac15f8ccd08d0"] {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
jinja2 = ["74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f", "9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"] {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
keyring = ["9b80469783d3f6106bce1d389c6b8b20c8d4d739943b1b8cd0ddc2a45d065f9d", "ee3d35b7f1ac3cb69e9a1e4323534649d3ab2fea402738a77e4250c152970fed"] ]
livereload = ["78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b", "89254f78d7529d7ea0a3417d224c34287ebfe266b05e67e51facaf82c27f0f66"] behave = [
markdown = ["2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a", "56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c"] {file = "behave-1.2.6-py2.py3-none-any.whl", hash = "sha256:ebda1a6c9e5bfe95c5f9f0a2794e01c7098b3dde86c10a95d8621c5907ff6f1c"},
markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] {file = "behave-1.2.6.tar.gz", hash = "sha256:b9662327aa53294c1351b0a9c369093ccec1d21026f050c3bd9b3e5cccf81a86"},
mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] ]
mkdocs = ["17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", "8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a"] black = [
more-itertools = ["b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", "c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564"] {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
parse = ["95a4f4469e37c57b5e924629ac99926f28bee7da59515dc5b8078c4c3e779249"] {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
parse-type = ["089a471b06327103865dfec2dd844230c3c658a4a1b5b4c8b6c16c8f77577f9e", "7f690b18d35048c15438d6d0571f9045cffbec5907e0b1ccf006f889e3a38c0b"] ]
parsedatetime = ["3b835fc54e472c17ef447be37458b400e3fefdf14bb1ffdedb5d2c853acf4ba1", "d2e9ddb1e463de871d32088a3f3cea3dc8282b1b2800e081bd0ef86900451667"] cffi = [
passlib = ["68c35c98a7968850e17f1b6892720764cc7eed0ef2b7cb3116a89a28e43fe177", "8d666cef936198bc2ab47ee9b0410c94adf2ba798e5a84bf220be079ae7ab6a8"] {file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
pathspec = ["163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424", "562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"] {file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] {file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
pycparser = ["a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"] {file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] {file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
python-dateutil = ["73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", "75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"] {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
pytz = ["1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", "b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"] {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
pywin32-ctypes = ["24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942", "9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"] {file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
pyxdg = ["1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e", "fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"] {file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
pyyaml = ["0e7f69397d53155e55d10ff68fdfb2cf630a35e6daf65cf0bdeaf04f127c09dc", "2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803", "35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc", "38a4f0d114101c58c0f3a88aeaa44d63efd588845c5a2df5290b73db8f246d15", "483eb6a33b671408c8529106df3707270bfacb2447bf8ad856a4b4f57f6e3075", "4b6be5edb9f6bb73680f5bf4ee08ff25416d1400fbd4535fe0069b2994da07cd", "7f38e35c00e160db592091751d385cd7b3046d6d51f578b29943225178257b31", "8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f", "c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c", "e4c015484ff0ff197564917b4b4246ca03f411b9bd7f16e02a2f586eb48b6d04", "ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4"] {file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
regex = ["032fdcc03406e1a6485ec09b826eac78732943840c4b29e503b789716f051d8d", "0e6cf1e747f383f52a0964452658c04300a9a01e8a89c55ea22813931b580aa8", "106e25a841921d8259dcef2a42786caae35bc750fb996f830065b3dfaa67b77e", "1768cf42a78a11dae63152685e7a1d90af7a8d71d2d4f6d2387edea53a9e0588", "27d1bd20d334f50b7ef078eba0f0756a640fd25f5f1708d3b5bed18a5d6bced9", "29b20f66f2e044aafba86ecf10a84e611b4667643c42baa004247f5dfef4f90b", "4850c78b53acf664a6578bba0e9ebeaf2807bb476c14ec7e0f936f2015133cae", "57eacd38a5ec40ed7b19a968a9d01c0d977bda55664210be713e750dd7b33540", "724eb24b92fc5fdc1501a1b4df44a68b9c1dda171c8ef8736799e903fb100f63", "77ae8d926f38700432807ba293d768ba9e7652df0cbe76df2843b12f80f68885", "78b3712ec529b2a71731fbb10b907b54d9c53a17ca589b42a578bc1e9a2c82ea", "7bbbdbada3078dc360d4692a9b28479f569db7fc7f304b668787afc9feb38ec8", "8d9ef7f6c403e35e73b7fc3cde9f6decdc43b1cb2ff8d058c53b9084bfcb553e", "a83049eb717ae828ced9cf607845929efcb086a001fc8af93ff15c50012a5716", "adc35d38952e688535980ae2109cad3a109520033642e759f987cf47fe278aa1", "c29a77ad4463f71a506515d9ec3a899ed026b4b015bf43245c919ff36275444b", "cfd31b3300fefa5eecb2fe596c6dee1b91b3a05ece9d5cfd2631afebf6c6fadd", "d3ee0b035816e0520fac928de31b6572106f0d75597f6fa3206969a02baba06f", "d508875793efdf6bab3d47850df8f40d4040ae9928d9d80864c1768d6aeaf8e3", "ef0b828a7e22e58e06a1cceddba7b4665c6af8afeb22a0d8083001330572c147", "faad39fdbe2c2ccda9846cd21581063086330efafa47d87afea4073a08128656"] {file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
secretstorage = ["20c797ae48a4419f66f8d28fc221623f11fc45b6828f96bdb1ad9990acb59f92", "7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a"] {file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
six = ["1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", "30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"] {file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] {file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
tornado = ["349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c", "398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60", "4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281", "559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5", "abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7", "c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9", "c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"] {file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
typed-ast = ["1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", "838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"] {file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
tzlocal = ["4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"] {file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"] {file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
]
click = [
{file = "Click-7.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"},
{file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"},
]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
cryptography = [
{file = "cryptography-2.8-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"},
{file = "cryptography-2.8-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2"},
{file = "cryptography-2.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad"},
{file = "cryptography-2.8-cp27-cp27m-win32.whl", hash = "sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2"},
{file = "cryptography-2.8-cp27-cp27m-win_amd64.whl", hash = "sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912"},
{file = "cryptography-2.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d"},
{file = "cryptography-2.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42"},
{file = "cryptography-2.8-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879"},
{file = "cryptography-2.8-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d"},
{file = "cryptography-2.8-cp34-abi3-manylinux2010_x86_64.whl", hash = "sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9"},
{file = "cryptography-2.8-cp34-cp34m-win32.whl", hash = "sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c"},
{file = "cryptography-2.8-cp34-cp34m-win_amd64.whl", hash = "sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0"},
{file = "cryptography-2.8-cp35-cp35m-win32.whl", hash = "sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf"},
{file = "cryptography-2.8-cp35-cp35m-win_amd64.whl", hash = "sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793"},
{file = "cryptography-2.8-cp36-cp36m-win32.whl", hash = "sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595"},
{file = "cryptography-2.8-cp36-cp36m-win_amd64.whl", hash = "sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7"},
{file = "cryptography-2.8-cp37-cp37m-win32.whl", hash = "sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff"},
{file = "cryptography-2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f"},
{file = "cryptography-2.8-cp38-cp38-win32.whl", hash = "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e"},
{file = "cryptography-2.8-cp38-cp38-win_amd64.whl", hash = "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13"},
{file = "cryptography-2.8.tar.gz", hash = "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651"},
]
entrypoints = [
{file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"},
{file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"},
]
flake8 = [
{file = "flake8-3.7.9-py2.py3-none-any.whl", hash = "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"},
{file = "flake8-3.7.9.tar.gz", hash = "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb"},
]
future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
importlib-metadata = [
{file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"},
{file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"},
]
jeepney = [
{file = "jeepney-0.4.2-py3-none-any.whl", hash = "sha256:6f45dce1125cf6c58a1c88123d3831f36a789f9204fbad3172eac15f8ccd08d0"},
{file = "jeepney-0.4.2.tar.gz", hash = "sha256:0ba6d8c597e9bef1ebd18aaec595f942a264e25c1a48f164d46120eacaa2e9bb"},
]
jinja2 = [
{file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"},
{file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"},
]
keyring = [
{file = "keyring-19.3.0-py2.py3-none-any.whl", hash = "sha256:9b80469783d3f6106bce1d389c6b8b20c8d4d739943b1b8cd0ddc2a45d065f9d"},
{file = "keyring-19.3.0.tar.gz", hash = "sha256:ee3d35b7f1ac3cb69e9a1e4323534649d3ab2fea402738a77e4250c152970fed"},
]
livereload = [
{file = "livereload-2.6.1-py2.py3-none-any.whl", hash = "sha256:78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b"},
{file = "livereload-2.6.1.tar.gz", hash = "sha256:89254f78d7529d7ea0a3417d224c34287ebfe266b05e67e51facaf82c27f0f66"},
]
lunr = [
{file = "lunr-0.5.6-py2.py3-none-any.whl", hash = "sha256:1208622930c915a07e6f8e8640474357826bad48534c0f57969b6fca9bffc88e"},
{file = "lunr-0.5.6.tar.gz", hash = "sha256:7be69d7186f65784a4f2adf81e5c58efd6a9921aa95966babcb1f2f2ada75c20"},
]
markdown = [
{file = "Markdown-3.2.1-py2.py3-none-any.whl", hash = "sha256:e4795399163109457d4c5af2183fbe6b60326c17cfdf25ce6e7474c6624f725d"},
{file = "Markdown-3.2.1.tar.gz", hash = "sha256:90fee683eeabe1a92e149f7ba74e5ccdc81cd397bd6c516d93a8da0ef90b6902"},
]
markupsafe = [
{file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mkdocs = [
{file = "mkdocs-1.1-py2.py3-none-any.whl", hash = "sha256:1e385a70aea8a9dedb731aea4fd5f3704b2074801c4f96f06b2920999babda8a"},
{file = "mkdocs-1.1.tar.gz", hash = "sha256:9243291392f59e20b655e4e46210233453faf97787c2cf72176510e868143174"},
]
nltk = [
{file = "nltk-3.4.5.win32.exe", hash = "sha256:a08bdb4b8a1c13de16743068d9eb61c8c71c2e5d642e8e08205c528035843f82"},
{file = "nltk-3.4.5.zip", hash = "sha256:bed45551259aa2101381bbdd5df37d44ca2669c5c3dad72439fa459b29137d94"},
]
parse = [
{file = "parse-1.14.0.tar.gz", hash = "sha256:95a4f4469e37c57b5e924629ac99926f28bee7da59515dc5b8078c4c3e779249"},
]
parse-type = [
{file = "parse_type-0.5.2-py2.py3-none-any.whl", hash = "sha256:089a471b06327103865dfec2dd844230c3c658a4a1b5b4c8b6c16c8f77577f9e"},
{file = "parse_type-0.5.2.tar.gz", hash = "sha256:7f690b18d35048c15438d6d0571f9045cffbec5907e0b1ccf006f889e3a38c0b"},
]
parsedatetime = [
{file = "parsedatetime-2.5-py2-none-any.whl", hash = "sha256:3b835fc54e472c17ef447be37458b400e3fefdf14bb1ffdedb5d2c853acf4ba1"},
{file = "parsedatetime-2.5.tar.gz", hash = "sha256:d2e9ddb1e463de871d32088a3f3cea3dc8282b1b2800e081bd0ef86900451667"},
]
passlib = [
{file = "passlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:68c35c98a7968850e17f1b6892720764cc7eed0ef2b7cb3116a89a28e43fe177"},
{file = "passlib-1.7.2.tar.gz", hash = "sha256:8d666cef936198bc2ab47ee9b0410c94adf2ba798e5a84bf220be079ae7ab6a8"},
]
pathspec = [
{file = "pathspec-0.7.0-py2.py3-none-any.whl", hash = "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424"},
{file = "pathspec-0.7.0.tar.gz", hash = "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"},
]
pycodestyle = [
{file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"},
{file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"},
]
pycparser = [
{file = "pycparser-2.19.tar.gz", hash = "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"},
]
pyflakes = [
{file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"},
{file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"},
]
python-dateutil = [
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
]
pytz = [
{file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"},
{file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"},
]
pywin32-ctypes = [
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
{file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
]
pyxdg = [
{file = "pyxdg-0.26-py2.py3-none-any.whl", hash = "sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e"},
{file = "pyxdg-0.26.tar.gz", hash = "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"},
]
pyyaml = [
{file = "PyYAML-5.3-cp27-cp27m-win32.whl", hash = "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d"},
{file = "PyYAML-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6"},
{file = "PyYAML-5.3-cp35-cp35m-win32.whl", hash = "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e"},
{file = "PyYAML-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689"},
{file = "PyYAML-5.3-cp36-cp36m-win32.whl", hash = "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994"},
{file = "PyYAML-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e"},
{file = "PyYAML-5.3-cp37-cp37m-win32.whl", hash = "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5"},
{file = "PyYAML-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf"},
{file = "PyYAML-5.3-cp38-cp38-win32.whl", hash = "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811"},
{file = "PyYAML-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20"},
{file = "PyYAML-5.3.tar.gz", hash = "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"},
]
regex = [
{file = "regex-2020.2.20-cp27-cp27m-win32.whl", hash = "sha256:99272d6b6a68c7ae4391908fc15f6b8c9a6c345a46b632d7fdb7ef6c883a2bbb"},
{file = "regex-2020.2.20-cp27-cp27m-win_amd64.whl", hash = "sha256:974535648f31c2b712a6b2595969f8ab370834080e00ab24e5dbb9d19b8bfb74"},
{file = "regex-2020.2.20-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5de40649d4f88a15c9489ed37f88f053c15400257eeb18425ac7ed0a4e119400"},
{file = "regex-2020.2.20-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:82469a0c1330a4beb3d42568f82dffa32226ced006e0b063719468dcd40ffdf0"},
{file = "regex-2020.2.20-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d58a4fa7910102500722defbde6e2816b0372a4fcc85c7e239323767c74f5cbc"},
{file = "regex-2020.2.20-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f1ac2dc65105a53c1c2d72b1d3e98c2464a133b4067a51a3d2477b28449709a0"},
{file = "regex-2020.2.20-cp36-cp36m-win32.whl", hash = "sha256:8c2b7fa4d72781577ac45ab658da44c7518e6d96e2a50d04ecb0fd8f28b21d69"},
{file = "regex-2020.2.20-cp36-cp36m-win_amd64.whl", hash = "sha256:269f0c5ff23639316b29f31df199f401e4cb87529eafff0c76828071635d417b"},
{file = "regex-2020.2.20-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bed7986547ce54d230fd8721aba6fd19459cdc6d315497b98686d0416efaff4e"},
{file = "regex-2020.2.20-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:046e83a8b160aff37e7034139a336b660b01dbfe58706f9d73f5cdc6b3460242"},
{file = "regex-2020.2.20-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b33ebcd0222c1d77e61dbcd04a9fd139359bded86803063d3d2d197b796c63ce"},
{file = "regex-2020.2.20-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bba52d72e16a554d1894a0cc74041da50eea99a8483e591a9edf1025a66843ab"},
{file = "regex-2020.2.20-cp37-cp37m-win32.whl", hash = "sha256:01b2d70cbaed11f72e57c1cfbaca71b02e3b98f739ce33f5f26f71859ad90431"},
{file = "regex-2020.2.20-cp37-cp37m-win_amd64.whl", hash = "sha256:113309e819634f499d0006f6200700c8209a2a8bf6bd1bdc863a4d9d6776a5d1"},
{file = "regex-2020.2.20-cp38-cp38-manylinux1_i686.whl", hash = "sha256:25f4ce26b68425b80a233ce7b6218743c71cf7297dbe02feab1d711a2bf90045"},
{file = "regex-2020.2.20-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9b64a4cc825ec4df262050c17e18f60252cdd94742b4ba1286bcfe481f1c0f26"},
{file = "regex-2020.2.20-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:9ff16d994309b26a1cdf666a6309c1ef51ad4f72f99d3392bcd7b7139577a1f2"},
{file = "regex-2020.2.20-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c7f58a0e0e13fb44623b65b01052dae8e820ed9b8b654bb6296bc9c41f571b70"},
{file = "regex-2020.2.20-cp38-cp38-win32.whl", hash = "sha256:200539b5124bc4721247a823a47d116a7a23e62cc6695744e3eb5454a8888e6d"},
{file = "regex-2020.2.20-cp38-cp38-win_amd64.whl", hash = "sha256:7f78f963e62a61e294adb6ff5db901b629ef78cb2a1cfce3cf4eeba80c1c67aa"},
{file = "regex-2020.2.20.tar.gz", hash = "sha256:9e9624440d754733eddbcd4614378c18713d2d9d0dc647cf9c72f64e39671be5"},
]
secretstorage = [
{file = "SecretStorage-3.1.2-py3-none-any.whl", hash = "sha256:b5ec909dde94d4ae2fa26af7c089036997030f0cf0a5cb372b4cccabd81c143b"},
{file = "SecretStorage-3.1.2.tar.gz", hash = "sha256:15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6"},
]
six = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
]
textwrap3 = [
{file = "textwrap3-0.9.2-py2.py3-none-any.whl", hash = "sha256:bf5f4c40faf2a9ff00a9e0791fed5da7415481054cef45bb4a3cfb1f69044ae0"},
{file = "textwrap3-0.9.2.zip", hash = "sha256:5008eeebdb236f6303dcd68f18b856d355f6197511d952ba74bc75e40e0c3414"},
]
toml = [
{file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"},
{file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"},
{file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
]
tornado = [
{file = "tornado-6.0.3-cp35-cp35m-win32.whl", hash = "sha256:c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"},
{file = "tornado-6.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60"},
{file = "tornado-6.0.3-cp36-cp36m-win32.whl", hash = "sha256:4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281"},
{file = "tornado-6.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c"},
{file = "tornado-6.0.3-cp37-cp37m-win32.whl", hash = "sha256:559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5"},
{file = "tornado-6.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7"},
{file = "tornado-6.0.3.tar.gz", hash = "sha256:c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9"},
]
typed-ast = [
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"},
{file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"},
{file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"},
{file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"},
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"},
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"},
{file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"},
{file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"},
{file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"},
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"},
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"},
{file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"},
{file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"},
{file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"},
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"},
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"},
{file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"},
{file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"},
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
]
tzlocal = [
{file = "tzlocal-1.5.1.tar.gz", hash = "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"},
]
zipp = [
{file = "zipp-3.0.0-py3-none-any.whl", hash = "sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2"},
{file = "zipp-3.0.0.tar.gz", hash = "sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"},
]

View file

@ -25,9 +25,10 @@ keyring = "^19.0"
pytz = "^2019.1" pytz = "^2019.1"
tzlocal = "^1.5" tzlocal = "^1.5"
asteval = "^0.9.14" asteval = "^0.9.14"
colorama = {version = "^0.4.1",platform = "win32"} colorama = "^0.4.1"
python-dateutil = "^2.8" python-dateutil = "^2.8"
pyyaml = "^5.1" pyyaml = "^5.1"
ansiwrap = "^0.8.4"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
behave = "^1.2" behave = "^1.2"
@ -38,3 +39,7 @@ black = {version = "^19.10b0",allow-prereleases = true}
[tool.poetry.scripts] [tool.poetry.scripts]
jrnl = 'jrnl.cli:run' jrnl = 'jrnl.cli:run'
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"