diff options
-rw-r--r-- | .vulture_whitelist.py | 18 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | Pipfile | 3 | ||||
-rw-r--r-- | Pipfile.lock | 104 | ||||
-rw-r--r-- | README.rst | 32 | ||||
-rw-r--r-- | docs/source/configuration.rst | 25 | ||||
-rw-r--r-- | docs/source/index.rst | 23 | ||||
-rw-r--r-- | nncli/__init__.py | 4 | ||||
-rw-r--r-- | nncli/__main__.py | 6 | ||||
-rw-r--r-- | nncli/cli.py | 242 | ||||
-rw-r--r-- | nncli/clipboard.py | 2 | ||||
-rw-r--r-- | nncli/config.py | 8 | ||||
-rw-r--r-- | nncli/nextcloud_note.py | 32 | ||||
-rw-r--r-- | nncli/nncli.py | 257 | ||||
-rw-r--r-- | nncli/notes_db.py | 26 | ||||
-rw-r--r-- | nncli/temp.py | 2 | ||||
-rw-r--r-- | nncli/user_input.py | 2 | ||||
-rw-r--r-- | nncli/utils.py | 49 | ||||
-rw-r--r-- | nncli/view_help.py | 2 | ||||
-rw-r--r-- | nncli/view_log.py | 2 | ||||
-rw-r--r-- | nncli/view_note.py | 2 | ||||
-rw-r--r-- | nncli/view_titles.py | 2 | ||||
-rw-r--r-- | pyproject.toml | 7 | ||||
-rw-r--r-- | tests/test_config.py | 2 | ||||
-rw-r--r-- | tests/test_nncli.py | 16 |
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) @@ -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 @@ -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" } } } @@ -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') |