aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.vulture_whitelist.py18
-rw-r--r--Makefile3
-rw-r--r--Pipfile3
-rw-r--r--Pipfile.lock104
-rw-r--r--README.rst32
-rw-r--r--docs/source/configuration.rst25
-rw-r--r--docs/source/index.rst23
-rw-r--r--nncli/__init__.py4
-rw-r--r--nncli/__main__.py6
-rw-r--r--nncli/cli.py242
-rw-r--r--nncli/clipboard.py2
-rw-r--r--nncli/config.py8
-rw-r--r--nncli/nextcloud_note.py32
-rw-r--r--nncli/nncli.py257
-rw-r--r--nncli/notes_db.py26
-rw-r--r--nncli/temp.py2
-rw-r--r--nncli/user_input.py2
-rw-r--r--nncli/utils.py49
-rw-r--r--nncli/view_help.py2
-rw-r--r--nncli/view_log.py2
-rw-r--r--nncli/view_note.py2
-rw-r--r--nncli/view_titles.py2
-rw-r--r--pyproject.toml7
-rw-r--r--tests/test_config.py2
-rw-r--r--tests/test_nncli.py16
25 files changed, 381 insertions, 490 deletions
diff --git a/.vulture_whitelist.py b/.vulture_whitelist.py
new file mode 100644
index 0000000..a68dc1b
--- /dev/null
+++ b/.vulture_whitelist.py
@@ -0,0 +1,18 @@
+loop # unused variable (nncli/nncli.py:185)
+loop # unused variable (nncli/nncli.py:735)
+_.widget # unused attribute (nncli/nncli.py:746)
+_.widget # unused attribute (nncli/nncli.py:750)
+all_notes_cnt # unused variable (nncli/nncli.py:885)
+match_regex # unused variable (nncli/nncli.py:885)
+all_notes_cnt # unused variable (nncli/nncli.py:922)
+match_regex # unused variable (nncli/nncli.py:922)
+all_notes_cnt # unused variable (nncli/nncli.py:976)
+match_regex # unused variable (nncli/nncli.py:976)
+frame # unused variable (nncli/nncli.py:1057)
+signum # unused variable (nncli/nncli.py:1057)
+note_index # unused variable (nncli/notes_db.py:410)
+note_index # unused variable (nncli/notes_db.py:510)
+_.all_notes_cnt # unused attribute (nncli/view_titles.py:13)
+_.match_regex # unused attribute (nncli/view_titles.py:13)
+_.all_notes_cnt # unused attribute (nncli/view_titles.py:20)
+_.match_regex # unused attribute (nncli/view_titles.py:20)
diff --git a/Makefile b/Makefile
index f6c3472..64e61a6 100644
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,7 @@ clean-test: ## remove test and coverage artifacts
lint: ## check style with pylint
$(PIPRUN) pylint nncli tests --disable=parse-error
+ $(PIPRUN) vulture nncli .vulture_whitelist
test: ## run tests quickly with the default Python
$(PIPRUN) python -m pytest
@@ -83,6 +84,8 @@ dist: ## builds source and wheel package
docs: ## builds the sphinx documentation and opens in the browser
make -C docs html
+ make -C docs latexpdf
+ make -C docs man
$(BROWSER) docs/build/html/index.html
install: ## install the package to the active Python's site-packages
diff --git a/Pipfile b/Pipfile
index 34b7a5e..cecb0b2 100644
--- a/Pipfile
+++ b/Pipfile
@@ -7,12 +7,12 @@ name = "pypi"
appdirs = "*"
requests = "*"
urwid = "*"
+click = "*"
[dev-packages]
pytest = "*"
pytest-cov = "*"
pytest-mock = "*"
-pytest-runner = "*"
pylint = "*"
pudb = "*"
sphinx = "*"
@@ -22,3 +22,4 @@ mock = "*"
tox = "*"
pathlib2 = {version = "*", markers = "python_version < '3.5'"}
scandir = {version = "*", markers = "python_version < '3.5'"}
+vulture = "*"
diff --git a/Pipfile.lock b/Pipfile.lock
index a1d93f9..7b64a27 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "3dd4d429a27a82ab0f5daa11fb974392ab9f45ac6b20647762d79a1c4ab1bd55"
+ "sha256": "44a70f798cfaf69e97a5d6d1dfc9d4e7f19feb48ae8f32cbe55b2d34f3083731"
},
"pipfile-spec": 6,
"requires": {},
@@ -36,6 +36,14 @@
],
"version": "==3.0.4"
},
+ "click": {
+ "hashes": [
+ "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
+ "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
+ ],
+ "index": "pypi",
+ "version": "==6.7"
+ },
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
@@ -56,7 +64,7 @@
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
- "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version < '4' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.6'",
+ "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.2.*' and python_version < '4'",
"version": "==1.23"
},
"urwid": {
@@ -87,7 +95,7 @@
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version != '3.0.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.1.*'",
"version": "==1.2.1"
},
"attrs": {
@@ -152,7 +160,7 @@
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80"
],
- "markers": "python_version >= '2.6' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version < '4'",
+ "markers": "python_version < '4' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.6'",
"version": "==4.5.1"
},
"docutils": {
@@ -183,7 +191,7 @@
"sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8",
"sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*'",
"version": "==1.1.0"
},
"isort": {
@@ -192,7 +200,7 @@
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*'",
"version": "==4.3.4"
},
"jinja2": {
@@ -293,7 +301,7 @@
"sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1",
"sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.7'",
"version": "==0.7.1"
},
"pudb": {
@@ -308,7 +316,7 @@
"sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1",
"sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.1.*' and python_version >= '2.7'",
"version": "==1.6.0"
},
"pygments": {
@@ -343,11 +351,11 @@
},
"pytest-cov": {
"hashes": [
- "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d",
- "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec"
+ "sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7",
+ "sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"
],
"index": "pypi",
- "version": "==2.5.1"
+ "version": "==2.6.0"
},
"pytest-mock": {
"hashes": [
@@ -357,14 +365,6 @@
"index": "pypi",
"version": "==1.10.0"
},
- "pytest-runner": {
- "hashes": [
- "sha256:d23f117be39919f00dd91bffeb4f15e031ec797501b717a245e377aee0f577be",
- "sha256:d987fec1e31287592ffe1cb823a8c613c533db4c6aaca0ee1191dbc91e2fcc61"
- ],
- "index": "pypi",
- "version": "==4.2"
- },
"pytoml": {
"hashes": [
"sha256:dae3c4e31d09eb06a6076d671f2281ee5d2c43cbeae16599c3af20881bb818ac"
@@ -427,18 +427,18 @@
},
"sphinx": {
"hashes": [
- "sha256:a07050845cc9a2f4026a6035cc8ed795a5ce7be6528bbc82032385c10807dfe7",
- "sha256:d719de667218d763e8fd144b7fcfeefd8d434a6201f76bf9f0f0c1fa6f47fcdb"
+ "sha256:217a7705adcb573da5bbe1e0f5cab4fa0bd89fd9342c9159121746f593c2d5a4",
+ "sha256:a602513f385f1d5785ff1ca420d9c7eb1a1b63381733b2f0ea8188a391314a86"
],
"index": "pypi",
- "version": "==1.7.8"
+ "version": "==1.7.9"
},
"sphinxcontrib-websupport": {
"hashes": [
"sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd",
"sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9"
],
- "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.2.*'",
"version": "==1.1.0"
},
"tox": {
@@ -449,50 +449,12 @@
"index": "pypi",
"version": "==3.2.1"
},
- "typed-ast": {
- "hashes": [
- "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58",
- "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d",
- "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291",
- "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a",
- "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9",
- "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892",
- "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9",
- "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded",
- "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa",
- "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe",
- "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd",
- "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85",
- "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6",
- "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46",
- "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51",
- "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f",
- "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129",
- "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c",
- "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea",
- "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863",
- "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559",
- "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87",
- "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6"
- ],
- "markers": "python_version < '3.7' and implementation_name == 'cpython'",
- "version": "==1.1.0"
- },
- "typing": {
- "hashes": [
- "sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
- "sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
- "sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
- ],
- "markers": "python_version < '3.5'",
- "version": "==3.6.6"
- },
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
- "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version < '4' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.6'",
+ "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.2.*' and python_version < '4'",
"version": "==1.23"
},
"urwid": {
@@ -507,22 +469,22 @@
"sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
"sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
],
- "markers": "python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*'",
+ "markers": "python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*'",
"version": "==16.0.0"
},
- "wrapt": {
+ "vulture": {
"hashes": [
- "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
+ "sha256:79c89ef5e3f2365467bcf491f425f777ae8fd157584dcc550d4591920b00fe3f",
+ "sha256:e794345a19c76f93f48f4519653038df90ad468ddea7912e14b07a07f6412e32"
],
- "version": "==1.10.11"
+ "index": "pypi",
+ "version": "==0.29"
},
- "zipfile36": {
+ "wrapt": {
"hashes": [
- "sha256:a78a8dddf4fa114f7fe73df76ffcce7538e23433b7a6a96c1c904023f122aead",
- "sha256:f7e48adf627f75cd74cdb50e7d850623b465f4cf5de913809196e8f3aa57dc4b"
+ "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
],
- "markers": "python_version in '3.3 3.4 3.5'",
- "version": "==0.1.3"
+ "version": "==1.10.11"
}
}
}
diff --git a/README.rst b/README.rst
index 3638ea0..c572ca2 100644
--- a/README.rst
+++ b/README.rst
@@ -1,18 +1,3 @@
-.. image:: https://img.shields.io/pypi/l/nncli.svg
- :alt: PyPI - License
-.. image:: https://img.shields.io/travis/com/djmoch/nncli.svg
- :alt: Travis (.com)
- :target: https://travis-ci.com/djmoch/nncli
-.. image:: https://img.shields.io/pypi/v/nncli.svg
- :alt: PyPI
- :target: https://pypi.org/project/nncli
-.. image:: https://img.shields.io/coveralls/github/djmoch/nncli.svg
- :alt: Coveralls github
- :target: https://coveralls.io/github/djmoch/nncli
-.. image:: https://img.shields.io/readthedocs/nncli.svg
- :alt: Read the Docs
- :target: https://nncli.readthedocs.io
-
nncli is a Python application that gives you access to your NextCloud
Notes account via the command line. It's a "hard" fork of
sncli_. You can access your notes via
@@ -26,7 +11,7 @@ automatically sync'ed when nncli is brought online.
More detailed documentation can be found in the docs.
Requirements
-~~~~~~~~~~~~
+------------
- `Python 3`_
@@ -37,7 +22,7 @@ Requirements
- A love for the command line!
Installation
-~~~~~~~~~~~~
+------------
- Via pip (latest release):
@@ -45,21 +30,23 @@ Installation
- Manually:
+ - If you don't already have it, install Flit_: ``pip3 install flit``
+
- Clone this repository to your hard disk: ``git clone
https://github.com/djmoch/nncli.git``
- - Install nncli: ``python3 setup.py install``
+ - Install nncli: ``flit install --deps production``
- Development:
- Clone the repo
- - Install Pipenv: ``pip install pipenv``
+ - Install Pipenv: ``pip3 install pipenv``
- - Stand up development environment: ``pipenv install --dev``
+ - Stand up development virtualenv: ``pipenv install --dev``
Features
-~~~~~~~~
+--------
- Console GUI
@@ -118,7 +105,7 @@ Features
- view and edit note category
Acknowledgements
-~~~~~~~~~~~~~~~~
+----------------
nncli is a fork of sncli_ by Eric Davis. This application further pulls in
and uses modified versions of the simplenote.py_ module by Daniel Schauenberg and
@@ -130,3 +117,4 @@ the notes_db.py module from nvpy_ by Charl P. Botha.
.. _Requests: https://requests.readthedocs.org/en/master
.. _simplenote.py: https://github.com/mrtazz/simplenote.py
.. _nvpy: https://github.com/cpbotha/nvpy
+.. _Flit: https://flit.readthedocs.io
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
index fd6fa80..94571ad 100644
--- a/docs/source/configuration.rst
+++ b/docs/source/configuration.rst
@@ -5,8 +5,7 @@ Configuration
The current NextCloud Notes API does not support oauth authentication so
your NextCloud Notes account password must be stored someplace
-accessible to nncli. Use of the ``cfg_nn_password_eval`` option is
-recommended (see :ref:`config-file`).
+accessible to nncli.
.. index:: single: configuration file
@@ -16,7 +15,7 @@ Configuration File
------------------
nncli pulls in configuration from the ``config`` file located in the
-standard location for your platform.
+standard location for your platform:
- Windows: ``%USERPROFILE%\AppData\Local\djmoch\nncli``
@@ -51,6 +50,11 @@ General Options
Optional. Overrides :confval:`cfg_nn_password_eval` if both are
specified.
+ .. note::
+
+ For security reasons, use of the ``cfg_nn_password_eval`` option
+ is recommended
+
.. confval:: cfg_nn_password_eval
A command to run to retrieve the password. The command should return
@@ -68,7 +72,7 @@ General Options
- macOS: ``~/Library/Caches/nncli``
- - \*nix: ``~/.cache/nncli``
+ - \*nix: ``$XDG_CACHE_HOME/nncli`` or ``$HOME/.cache/nncli``
.. confval:: cfg_search_categories
@@ -154,10 +158,6 @@ General Options
Optional. Default value: ``$PAGER`` if defined in the user's
environment, else ``less -c``.
-.. confval:: cfg_diff
-
- .. todo:: Remove ``cfg_diff``
-
.. confval:: cfg_max_logs
Sets the number of log events to display together in the consule GUI
@@ -457,9 +457,12 @@ Colors
nncli utilizes the Python Urwid_ module to implement the console user
interface.
-At this time, nncli does not yet support 256-color terminals and is
-limited to just 16-colors. Color names that can be specified in the
-``config`` file are listed :ref:`here <urwid:16-standard-foreground>`.
+.. note::
+
+ At this time, nncli does not yet support 256-color terminals and is
+ limited to just 16-colors. Color names that can be specified in the
+ ``config`` file are listed :ref:`here
+ <urwid:16-standard-foreground>`.
The following pairs of configuration values represent the foreground and
background colors for different elements of the console GUI. In each
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6270e93..7b8a0cf 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -6,18 +6,37 @@
NextCloud Notes Command Line Interface
======================================
+.. only:: html
+
+ .. image:: https://img.shields.io/pypi/l/nncli.svg
+ :alt: PyPI - License
+ .. image:: https://img.shields.io/travis/com/djmoch/nncli.svg
+ :alt: Travis (.com)
+ :target: https://travis-ci.com/djmoch/nncli
+ .. image:: https://img.shields.io/pypi/v/nncli.svg
+ :alt: PyPI
+ :target: https://pypi.org/project/nncli
+ .. image:: https://img.shields.io/coveralls/github/djmoch/nncli.svg
+ :alt: Coveralls github
+ :target: https://coveralls.io/github/djmoch/nncli
+ .. image:: https://img.shields.io/readthedocs/nncli.svg
+ :alt: Read the Docs
+ :target: https://nncli.readthedocs.io
+
.. include:: ../../README.rst
+Contents
+--------
+
.. toctree::
:maxdepth: 2
- :caption: Contents:
configuration
usage
Indices and tables
-==================
+------------------
* :ref:`genindex`
* :ref:`search`
diff --git a/nncli/__init__.py b/nncli/__init__.py
index 83d46a5..1e36700 100644
--- a/nncli/__init__.py
+++ b/nncli/__init__.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""NextCloud Notes Command Line Interface"""
-__version__ = '0.2.0'
+__version__ = '0.3.0'
diff --git a/nncli/__main__.py b/nncli/__main__.py
index d96036a..f3ce514 100644
--- a/nncli/__main__.py
+++ b/nncli/__main__.py
@@ -1,6 +1,6 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""nncli main module"""
-import nncli.nncli
+import nncli.cli
if __name__ == '__main__':
- nncli.nncli.main()
+ nncli.cli.main()
diff --git a/nncli/cli.py b/nncli/cli.py
new file mode 100644
index 0000000..536aaf6
--- /dev/null
+++ b/nncli/cli.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+"""Command line interface module"""
+import click
+
+from . import __version__
+from .nncli import Nncli
+
+class StdinFlag(click.ParamType):
+ """StdinFlag Click Parameter Type"""
+ name = "stdin_flag"
+
+ def convert(self, value, param, ctx):
+ if value == '-':
+ return True
+ return self.fail('%s is not a valid stdin_flag')
+
+STDIN_FLAG = StdinFlag()
+
+@click.command()
+@click.pass_obj
+def rm_category(ctx_obj):
+ """Remove note category."""
+ nncli = ctx_obj['nncli']
+ key = ctx_obj['key']
+ nncli.cli_note_category_rm(key)
+
+@click.command()
+@click.argument('category', required=True)
+@click.pass_obj
+def set_category(ctx_obj, category):
+ """Set the note category."""
+ nncli = ctx_obj['nncli']
+ key = ctx_obj['key']
+ nncli.cli_note_category_set(key, category)
+
+@click.command(short_help="Print the note category.")
+@click.pass_obj
+def get_category(ctx_obj):
+ """Print the category for the given note on stdout."""
+ nncli = ctx_obj['nncli']
+ key = ctx_obj['key']
+ category = nncli.cli_note_category_get(key)
+ if category:
+ print(category)
+
+@click.group()
+@click.option(
+ '-k',
+ '--key',
+ required=True,
+ type=click.INT,
+ help="Specify the note key."
+ )
+@click.pass_context
+def cat(ctx, key):
+ """Operate on the note category."""
+ nncli = ctx.obj
+ ctx.obj = {}
+ ctx.obj['nncli'] = nncli
+ ctx.obj['key'] = key
+
+cat.add_command(get_category, 'get')
+cat.add_command(set_category, 'set')
+cat.add_command(rm_category, 'rm')
+
+@click.command()
+@click.option(
+ '-k',
+ '--key',
+ required=True,
+ type=click.INT,
+ help="Specify the note key.")
+@click.pass_obj
+def favorite(nncli, key):
+ """Mark as note as a favorite."""
+ nncli.cli_note_favorite(key, 1)
+
+@click.command()
+@click.option(
+ '-k',
+ '--key',
+ required=True,
+ type=click.INT,
+ help="Specify the note key."
+ )
+@click.pass_obj
+def unfavorite(nncli, key):
+ """Remove favorite flag from a note."""
+ nncli.cli_note_favorite(key, 0)
+
+@click.command(short_help="Print JSON-formatted note to stdout.")
+@click.option('-k', '--key', type=click.INT, help="Specify the note key.")
+@click.option(
+ '-r',
+ '--regex',
+ is_flag=True,
+ help="Treat search term(s) as regular expressions."
+ )
+@click.argument('search_terms', nargs=-1)
+@click.pass_obj
+def export(nncli, key, regex, search_terms):
+ """
+ Print JSON-formatted note to stdout. If a key is specified, then regex
+ and search_terms are ignored.
+ """
+ if key:
+ nncli.cli_note_export(key)
+ else:
+ nncli.cli_export_notes(regex, ' '.join(search_terms))
+
+@click.command(short_help="Print note contents to stdout.")
+@click.option('-k', '--key', type=click.INT, help="Specify the note key.")
+@click.option(
+ '-r',
+ '--regex',
+ is_flag=True,
+ help="Treat search term(s) as regular expressions."
+ )
+@click.argument('search_terms', nargs=-1)
+@click.pass_obj
+def dump(nncli, key, regex, search_terms):
+ """
+ Print note contents to stdout. If a key is specified, then regex
+ and search_terms are ignored.
+ """
+ if key:
+ nncli.cli_note_dump(key)
+ else:
+ nncli.cli_dump_notes(regex, ' '.join(search_terms))
+
+@click.command(short_help="List notes.")
+@click.option(
+ '-r',
+ '--regex',
+ is_flag=True,
+ help="Treat search term(s) as regular expressions."
+ )
+@click.argument('search_terms', nargs=-1)
+@click.pass_obj
+def list_notes(nncli, regex, search_terms):
+ """
+ List notes, optionally providing search terms to narrow the
+ results.
+ """
+ nncli.cli_list_notes(regex, ' '.join(search_terms))
+
+@click.command(short_help="Sync notes to server.")
+def sync():
+ """
+ Perform a full, bi-directional sync of your notes between the
+ server and the local cache.
+ """
+ pass
+
+@click.command()
+@click.option(
+ '-k',
+ '--key',
+ required=True,
+ type=click.INT,
+ help="Specify the note key."
+ )
+@click.pass_obj
+def delete(nncli, key):
+ """Delete an existing note."""
+ nncli.cli_note_delete(key, True)
+
+@click.command()
+@click.option(
+ '-k',
+ '--key',
+ required=True,
+ type=click.INT,
+ help="Specify the note key."
+ )
+@click.pass_obj
+def edit(nncli, key):
+ """Edit an existing note."""
+ nncli.cli_note_edit(key)
+
+@click.command(short_help="Import a JSON note.")
+@click.argument('from_stdin', metavar='[-]', type=STDIN_FLAG)
+@click.pass_obj
+def json_import(nncli, from_stdin):
+ """
+ Import a JSON-formatted note file into your account. The expected
+ JSON format is the same format used internally by nncli. If - is
+ specified, the note is read from stdin, otherwise the editor will
+ open.
+ """
+ nncli.cli_note_import(from_stdin)
+
+@click.command(short_help="Add a new note.")
+@click.option('-t', '--title', help="Specify the title of note for create.")
+@click.argument('from_stdin', metavar='[-]', type=STDIN_FLAG)
+@click.pass_obj
+def create(nncli, title, from_stdin):
+ """
+ Create a new note, either opening the editor or, if - is specified,
+ reading from stdin.
+ """
+ nncli.cli_note_create(from_stdin, title)
+
+@click.group(invoke_without_command=True)
+@click.option(
+ '-n',
+ '--nosync',
+ is_flag=True,
+ help="Don't perform a server sync."
+ )
+@click.option('-v', '--verbose', is_flag=True, help="Print verbose output.")
+@click.option(
+ '-c',
+ '--config',
+ type=click.Path(exists=True),
+ help="Specify the config file to read from."
+ )
+@click.option('-k', '--key', type=click.INT, help="Specify the note key.")
+@click.version_option(version=__version__, message='%(prog)s %(version)s')
+@click.pass_context
+def main(ctx, nosync, verbose, config, key):
+ """
+ Run the NextClound Note Command Line Interface. No COMMAND means
+ to open the console GUI.
+ """
+ ctx.obj = Nncli(not nosync, verbose, config)
+ if ctx.invoked_subcommand is None:
+ ctx.obj.gui(key)
+ elif not nosync:
+ ctx.obj.sync_notes()
+
+main.add_command(create)
+main.add_command(edit)
+main.add_command(delete)
+main.add_command(sync)
+main.add_command(json_import, name='import')
+main.add_command(list_notes, name='list')
+main.add_command(dump)
+main.add_command(export)
+main.add_command(favorite)
+main.add_command(unfavorite)
+main.add_command(cat)
diff --git a/nncli/clipboard.py b/nncli/clipboard.py
index 84ef1fa..091fc36 100644
--- a/nncli/clipboard.py
+++ b/nncli/clipboard.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os
from distutils import spawn
diff --git a/nncli/config.py b/nncli/config.py
index 4e8cc96..8070e4c 100644
--- a/nncli/config.py
+++ b/nncli/config.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os, sys, urwid, collections, configparser, subprocess
@@ -25,7 +25,6 @@ class Config:
'cfg_status_bar' : 'yes',
'cfg_editor' : os.environ['EDITOR'] if 'EDITOR' in os.environ else 'vim {fname} +{line}',
'cfg_pager' : os.environ['PAGER'] if 'PAGER' in os.environ else 'less -c',
- 'cfg_diff' : 'diff -b -U10',
'cfg_max_logs' : '5',
'cfg_log_timeout' : '5',
'cfg_log_reversed' : 'yes',
@@ -119,9 +118,9 @@ class Config:
cp = configparser.SafeConfigParser(defaults)
if custom_file is not None:
- self.configs_read = cp.read([custom_file])
+ cp.read([custom_file])
else:
- self.configs_read = cp.read([os.path.join(self.config_home, 'config')])
+ cp.read([os.path.join(self.config_home, 'config')])
cfg_sec = 'nncli'
@@ -159,7 +158,6 @@ class Config:
self.configs['status_bar'] = [ cp.get(cfg_sec, 'cfg_status_bar'), 'Show the status bar' ]
self.configs['editor'] = [ cp.get(cfg_sec, 'cfg_editor'), 'Editor command' ]
self.configs['pager'] = [ cp.get(cfg_sec, 'cfg_pager'), 'External pager command' ]
- self.configs['diff'] = [ cp.get(cfg_sec, 'cfg_diff'), 'External diff command' ]
self.configs['max_logs'] = [ cp.get(cfg_sec, 'cfg_max_logs'), 'Max logs in footer' ]
self.configs['log_timeout'] = [ cp.get(cfg_sec, 'cfg_log_timeout'), 'Log timeout' ]
self.configs['log_reversed'] = [ cp.get(cfg_sec, 'cfg_log_reversed'), 'Log file reversed' ]
diff --git a/nncli/nextcloud_note.py b/nncli/nextcloud_note.py
index 5232a49..d74f465 100644
--- a/nncli/nextcloud_note.py
+++ b/nncli/nextcloud_note.py
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
-import urllib.parse
from requests.exceptions import RequestException, ConnectionError
-import base64
import time
import datetime
import logging
@@ -18,11 +16,6 @@ except ImportError:
# For Google AppEngine
from django.utils import simplejson as json
-NOTE_FETCH_LENGTH = 100
-
-class NextcloudLoginFailed(Exception):
- pass
-
class NextcloudNote(object):
""" Class for interacting with the NextCloud Notes web service """
@@ -127,31 +120,6 @@ class NextcloudNote(object):
#logging.debug('RESPONSE OK: ' + str(note))
return note, 0
- def add_note(self, note):
- """wrapper function to add a note
-
- The function can be passed the note as a dict with the `content`
- property set, which is then directly send to the web service for
- creation. Alternatively, only the body as string can also be passed. In
- this case the parameter is used as `content` for the new note.
-
- Arguments:
- - note (dict or string): the note to add
-
- Returns:
- A tuple `(note, status)`
-
- - note (dict): the newly created note
- - status (int): 0 on sucesss and -1 otherwise
-
- """
- if type(note) == str:
- return self.update_note({"content": note})
- elif (type(note) == dict) and "content" in note:
- return self.update_note(note)
- else:
- return "No string or valid note.", -1
-
def get_note_list(self, category=None):
""" function to get the note list
diff --git a/nncli/nncli.py b/nncli/nncli.py
index 340d3c1..83fa714 100644
--- a/nncli/nncli.py
+++ b/nncli/nncli.py
@@ -1,17 +1,16 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os, sys, getopt, re, signal, time, datetime, shlex, hashlib
import subprocess, threading, logging
import copy, json, urwid, datetime
-import nncli
from . import view_titles, view_note, view_help, view_log, user_input
-from . import utils, temp
+from . import utils, temp, __version__
from .config import Config
from .nextcloud_note import NextcloudNote
from .notes_db import NotesDB, ReadError, WriteError
from logging.handlers import RotatingFileHandler
-class nncli:
+class Nncli:
def __init__(self, do_server_sync, verbose=False, config_file=None):
self.config = Config(config_file)
@@ -76,13 +75,6 @@ class nncli:
return None
return pager
- def get_diff(self):
- diff = self.config.get_config('diff')
- if not diff:
- self.log('No diff command configured!')
- return None
- return diff
-
def exec_cmd_on_note(self, note, cmd=None, raw=False):
if not cmd:
@@ -131,42 +123,12 @@ class nncli:
content = None
temp.tempfile_delete(tf)
- return content
-
- def exec_diff_on_note(self, note, old_note):
- diff = self.get_diff()
- if not diff:
- return None
-
- pager = self.get_pager()
- if not pager:
- return None
+ if self.do_gui:
+ self.nncli_loop.screen.clear()
+ self.nncli_loop.draw_screen()
- ltf = temp.tempfile_create(note, tempdir=self.tempdir)
- otf = temp.tempfile_create(old_note, tempdir=self.tempdir)
- out = temp.tempfile_create(None, tempdir=self.tempdir)
-
- try:
- subprocess.call(diff + ' ' +
- temp.tempfile_name(ltf) + ' ' +
- temp.tempfile_name(otf) + ' > ' +
- temp.tempfile_name(out),
- shell=True)
- subprocess.check_call(pager + ' ' +
- temp.tempfile_name(out),
- shell=True)
- except Exception as e:
- self.log('Command error: ' + str(e))
- temp.tempfile_delete(ltf)
- temp.tempfile_delete(otf)
- temp.tempfile_delete(out)
- return None
-
- temp.tempfile_delete(ltf)
- temp.tempfile_delete(otf)
- temp.tempfile_delete(out)
- return None
+ return content
def gui_header_clear(self):
self.master_frame.contents['header'] = ( None, None )
@@ -176,12 +138,6 @@ class nncli:
self.master_frame.contents['header'] = ( w, None )
self.nncli_loop.draw_screen()
- def gui_header_get(self):
- return self.master_frame.contents['header'][0]
-
- def gui_header_focus(self):
- self.master_frame.focus_position = 'header'
-
def gui_footer_log_clear(self):
ui = self.gui_footer_input_get()
self.master_frame.contents['footer'] = \
@@ -216,10 +172,6 @@ class nncli:
self.master_frame.focus_position = 'footer'
self.master_frame.contents['footer'][0].focus_position = 1
- def gui_body_clear(self):
- self.master_frame.contents['body'] = ( None, None )
- self.nncli_loop.draw_screen()
-
def gui_body_set(self, w):
self.master_frame.contents['body'] = ( w, None )
self.gui_update_status_bar()
@@ -1108,198 +1060,3 @@ def SIGINT_handler(signum, frame):
sys.exit(1)
signal.signal(signal.SIGINT, SIGINT_handler)
-
-def usage():
- print ('''
-Usage:
- nncli [OPTIONS] [COMMAND] [COMMAND_ARGS]
-
- OPTIONS:
- -h, --help - usage help
- -v, --verbose - verbose output
- -n, --nosync - don't perform a server sync
- -r, --regex - search string is a regular expression
- -k <key>, --key=<key> - note key
- -t <title>, --title=<title> - title of note for create (cli mode)
- -c <file>, --config=<file> - config file to read from
- -V, --version - version information
-
- COMMANDS:
- <none> - console gui mode when no command specified
- sync - perform a full sync with the server
- list [search_string] - list notes (refined with search string)
- export [search_string] - export notes in JSON (refined with search
- string)
- dump [search_string] - dump notes (refined with search string)
- create [-] - create a note ('-' content from stdin)
- import [-] - import a note in JSON format ('-' JSON from
- stdin)
- export - export a note in JSON format (specified by
- <key>)
- dump - dump a note (specified by <key>)
- edit - edit a note (specified by <key>)
- delete - delete a note (specified by <key>)
- < favorite | unfavorite > - favorite/unfavorite a note (specified by <key>)
- cat get - retrieve the category from a note (specified
- by <key>)
- cat set <category> - set the category for a note (specified by <key>)
- cat rm - remove category from a note (specified by <key>)
-''')
- sys.exit(0)
-
-def version():
- version_info = 'nncli {}'.format(nncli.__version__)
- print(version_info)
- exit(0)
-
-def main(argv=sys.argv[1:]):
- verbose = False
- sync = True
- regex = False
- key = None
- title = None
- config = None
-
- try:
- opts, args = getopt.getopt(argv,
- 'hvnrk:t:c:V',
- [ 'help', 'verbose', 'nosync', 'regex', 'key=', 'title=', \
- 'config=', 'version' ])
- except:
- usage()
-
- for opt, arg in opts:
- if opt in [ '-h', '--help']:
- usage()
- elif opt in ['-V', '--version' ]:
- version()
- elif opt in [ '-v', '--verbose']:
- verbose = True
- elif opt in [ '-n', '--nosync']:
- sync = False
- elif opt in [ '-r', '--regex']:
- regex = True
- elif opt in [ '-k', '--key']:
- try:
- key = int(arg)
- except:
- print('ERROR: Key specified with -k must be an integer')
- elif opt in [ '-t', '--title']:
- title = arg
- elif opt in [ '-c', '--config']:
- config = arg
- else:
- print('ERROR: Unhandled option')
- usage()
-
- if not args:
- nncli(sync, verbose, config).gui(key)
- return
-
- def nncli_start(sync=sync, verbose=verbose, config=config):
- sn = nncli(sync, verbose, config)
- if sync: sn.sync_notes()
- return sn
-
- if args[0] == 'sync':
- sn = nncli_start(True)
-
- elif args[0] == 'list':
-
- sn = nncli_start()
- sn.cli_list_notes(regex, ' '.join(args[1:]))
-
- elif args[0] == 'dump':
-
- sn = nncli_start()
- if key:
- sn.cli_note_dump(key)
- else:
- sn.cli_dump_notes(regex, ' '.join(args[1:]))
-
- elif args[0] == 'create':
-
- if len(args) == 1:
- sn = nncli_start()
- sn.cli_note_create(False, title)
- elif len(args) == 2 and args[1] == '-':
- sn = nncli_start()
- sn.cli_note_create(True, title)
- else:
- usage()
-
- elif args[0] == 'import':
-
- if len(args) == 1:
- sn = nncli_start()
- sn.cli_note_import(False)
- elif len(args) == 2 and args[1] == '-':
- sn = nncli_start()
- sn.cli_note_import(True)
- else:
- usage()
-
- elif args[0] == 'export':
-
- sn = nncli_start()
- if key:
- sn.cli_note_export(key)
- else:
- sn.cli_export_notes(regex, ' '.join(args[1:]))
-
- elif args[0] == 'edit':
-
- if not key:
- usage()
-
- sn = nncli_start()
- sn.cli_note_edit(key)
-
- elif args[0] == 'delete':
-
- if not key:
- usage()
-
- sn = nncli_start()
- sn.cli_note_delete(key, True)
-
- elif args[0] == 'favorite' or args[0] == 'unfavorite':
-
- if not key:
- usage()
-
- sn = nncli_start()
- sn.cli_note_favorite(key, 1 if args[0] == 'favorite' else 0)
-
- # Category API
- elif args[0] == 'cat':
-
- if not key:
- usage()
-
- nargs = len(args)
- correct_other = (args[1] in ['get', 'rm'] and nargs == 2)
- correct_set = (args[1] == 'set' and nargs == 3)
- if not (correct_set or correct_other):
- usage()
-
- if args[1] == 'get':
-
- sn = nncli_start()
- category = sn.cli_note_category_get(key)
- if category:
- print(category)
-
- elif args[1] == 'set':
-
- category = args[2]
- sn = nncli_start()
- sn.cli_note_category_set(key, category)
-
- elif args[1] == 'rm':
-
- sn = nncli_start()
- sn.cli_note_category_rm(key)
-
- else:
- usage()
diff --git a/nncli/notes_db.py b/nncli/notes_db.py
index 9c688eb..99aa058 100644
--- a/nncli/notes_db.py
+++ b/nncli/notes_db.py
@@ -1,9 +1,7 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os, time, re, glob, json, copy, threading
from . import utils
-from . import nextcloud_note
-nextcloud_note.NOTE_FETCH_LENGTH=100
from .nextcloud_note import NextcloudNote
import logging
@@ -64,11 +62,6 @@ class NotesDB():
self.config.get_config('nn_password'),
self.config.get_config('nn_host'))
- # we'll use this to store which notes are currently being synced by
- # the background thread, so we don't add them anew if they're still
- # in progress. This variable is only used by the background thread.
- self.threaded_syncing_keys = {}
-
def filtered_notes_sort(self, filtered_notes, sort_mode='date'):
if sort_mode == 'date':
if self.config.get_config('favorite_ontop') == 'yes':
@@ -321,15 +314,9 @@ class NotesDB():
def get_note(self, key):
return self.notes[key]
- def get_note_favorite(self, key):
- return self.notes[key].get('favorite')
-
def get_note_category(self, key):
return self.notes[key].get('category')
- def get_note_content(self, key):
- return self.notes[key].get('content')
-
def flag_what_changed(self, note, what_changed):
if 'what_changed' not in note:
note['what_changed'] = []
@@ -466,9 +453,6 @@ class NotesDB():
del cn['favorite']
del cn['what_changed']
- if 'favorite' in cn:
- cn['favorite'] = str.lower(str(cn['favorite']))
-
if n['deleted']:
uret = self.note.delete_note(cn)
else:
@@ -520,7 +504,6 @@ class NotesDB():
# a new note and key is not in local store
# retrieve note, update note with response
if not skip_remote_syncing:
- len_nl = len(nl)
for note_index, n in enumerate(nl):
k = n.get('id')
c = n.get('category') if n.get('category') is not None \
@@ -602,16 +585,9 @@ class NotesDB():
o = utils.KeyValueObject(saved=False, synced=False, modified=False)
modified = float(n['modified'])
savedate = float(n['savedate'])
- syncdate = float(n['syncdate'])
if savedate > modified:
o.saved = True
- else:
- o.modified = True
-
- if syncdate > modified:
- o.synced = True
-
return o
def verify_all_saved(self):
diff --git a/nncli/temp.py b/nncli/temp.py
index 5bebbe6..0bb3177 100644
--- a/nncli/temp.py
+++ b/nncli/temp.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os, json, tempfile
diff --git a/nncli/user_input.py b/nncli/user_input.py
index d956145..958cf8e 100644
--- a/nncli/user_input.py
+++ b/nncli/user_input.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import urwid
diff --git a/nncli/utils.py b/nncli/utils.py
index 0a83c96..3635c33 100644
--- a/nncli/utils.py
+++ b/nncli/utils.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import datetime, random, re
@@ -34,53 +34,6 @@ def get_note_title(note):
else:
return ''
-def get_note_title_file(note):
- mo = note_title_re.match(note.get('content', ''))
- if mo:
- fn = mo.groups()[0]
- fn = fn.replace(' ', '_')
- fn = fn.replace('/', '_')
- if not fn:
- return ''
-
- if isinstance(fn, str):
- fn = str(fn, 'utf-8')
- else:
- fn = str(fn)
-
- fn += '.mkdn'
- return fn
- else:
- return ''
-
-def human_date(timestamp):
- """
- Given a timestamp, return pretty human format representation.
-
- For example, if timestamp is:
- * today, then do "15:11"
- * else if it is this year, then do "Aug 4"
- * else do "Dec 11, 2011"
- """
-
- # this will also give us timestamp in the local timezone
- dt = datetime.datetime.fromtimestamp(timestamp)
- # this returns localtime
- now = datetime.datetime.now()
-
- if dt.date() == now.date():
- # today: 15:11
- return dt.strftime('%H:%M')
-
- elif dt.year == now.year:
- # this year: Aug 6
- # format code %d unfortunately 0-pads
- return dt.strftime('%b') + ' ' + str(dt.day)
-
- else:
- # not today or this year, so we do "Dec 11, 2011"
- return '%s %d, %d' % (dt.strftime('%b'), dt.day, dt.year)
-
def note_favorite(n):
if 'favorite' in n:
return n['favorite']
diff --git a/nncli/view_help.py b/nncli/view_help.py
index 4dc247e..cf9635f 100644
--- a/nncli/view_help.py
+++ b/nncli/view_help.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import re, urwid
diff --git a/nncli/view_log.py b/nncli/view_log.py
index a529bf7..924f557 100644
--- a/nncli/view_log.py
+++ b/nncli/view_log.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import urwid
diff --git a/nncli/view_note.py b/nncli/view_note.py
index 8732a50..ad90e85 100644
--- a/nncli/view_note.py
+++ b/nncli/view_note.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import time, urwid
from . import utils
diff --git a/nncli/view_titles.py b/nncli/view_titles.py
index 58ccebf..5d924a0 100644
--- a/nncli/view_titles.py
+++ b/nncli/view_titles.py
@@ -1,4 +1,4 @@
-# encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import re, time, datetime, urwid, subprocess
from . import utils, view_note
diff --git a/pyproject.toml b/pyproject.toml
index 0be3515..9fe6282 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,7 +8,7 @@ author = "Daniel Moch"
author-email = "daniel@danielmoch.com"
home-page = "https://github.com/djmoch/nncli"
description-file = "README.rst"
-requires = ["urwid", "requests", "appdirs"]
+requires = ["urwid", "requests", "appdirs", "click"]
classifiers = ["License :: OSI Approved :: MIT License",
"Development Status :: 4 - Beta",
"Environment :: Console :: Curses",
@@ -17,8 +17,11 @@ classifiers = ["License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only"]
requires-python = ">=3"
+[tool.flit.metadata.urls]
+Documentation = "https://nncli.readthedocs.io/en/latest"
+
[tool.flit.metadata.requires-extra]
dev = ["pipenv"]
[tool.flit.scripts]
-nncli = "nncli.nncli:main"
+nncli = "nncli.cli:main"
diff --git a/tests/test_config.py b/tests/test_config.py
index 0e6ffe1..c6f77a2 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os
import sys
diff --git a/tests/test_nncli.py b/tests/test_nncli.py
index 78d213b..f9c67d2 100644
--- a/tests/test_nncli.py
+++ b/tests/test_nncli.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
import logging
import os
@@ -30,14 +30,14 @@ def assert_initialized():
def test_init_no_tempdir(mocker, mock_nncli):
mock_get_config(mocker, ['what', '', 'duh', 'duh', 'duh'])
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
assert_initialized()
assert nn.tempdir == None
os.mkdir.assert_called_with('duh')
def test_init(mocker, mock_nncli):
mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh'])
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
assert_initialized()
assert nn.tempdir == 'blah'
@@ -47,25 +47,25 @@ def test_init_notesdb_fail(mocker, mock_nncli):
new=mocker.MagicMock(side_effect=SystemExit)
)
with pytest.raises(SystemExit):
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
def test_get_editor(mocker, mock_nncli):
mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'vim', ''])
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
assert_initialized()
assert nn.get_editor() == 'vim'
assert nn.get_editor() == None
def test_get_pager(mocker, mock_nncli):
mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'less', ''])
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
assert_initialized()
assert nn.get_editor() == 'less'
assert nn.get_editor() == None
def test_get_diff(mocker, mock_nncli):
mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'diff', ''])
- nn = nncli.nncli.nncli(False)
+ nn = nncli.nncli.Nncli(False)
assert_initialized()
assert nn.get_editor() == 'diff'
assert nn.get_editor() == None
@@ -73,7 +73,7 @@ def test_get_diff(mocker, mock_nncli):
@pytest.mark.skip
def test_exec_cmd_on_note(mocker, mock_nncli):
mocker.patch.object(
- 'nncli.nncli.nncli',
+ 'nncli.nncli.Nncli',
get_editor,
new=mocker.MagicMock(return_value='vim'))
mocker.patch('nncli.temp.tempfile_create')