[
  {
    "path": ".bumpversion.cfg",
    "content": "[bumpversion]\ncurrent_version = 1.0.1\ncommit = True\ntag = True\n\n[bumpversion:file:google_keep_tasks/__init__.py]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "* django-code-generator version:\n* Python version:\n* Operating System:\n\n### Description\n\nDescribe what you were trying to get done.\nTell us what happened, what went wrong, and what you expected to happen.\n\n### What I Did\n\n```\nPaste the command(s) you ran and the output.\nIf there was a crash, please include the traceback here.\n```\n"
  },
  {
    "path": ".github/workflows/pip-rating.yml",
    "content": "name: Pip-rating\n\non:\n  push:\n    branches:\n      - develop\n  schedule:\n    - cron: '0 0 * * SUN'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    permissions: write-all\n    steps:\n      - uses: actions/checkout@v2\n      - name: Run pip-rating\n        uses: Nekmo/pip-rating@master\n        with:\n          create_badge: true\n          badge_style: flat-square\n          badge_branch: pip-rating-badge\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\n\non: [push]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python 3.9\n        uses: actions/setup-python@v2\n        with:\n          python-version: '3.9'\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install tox-gh-actions wheel twine\n          if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi\n      - name: Create packages\n        run: |\n          python setup.py sdist bdist_wheel\n      - name: Check packages\n        run: |\n          twine check dist/*\n      - name: Publish package\n        if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')\n        uses: pypa/gh-action-pypi-publish@master\n        with:\n          user: __token__\n          password: ${{ secrets.PYPI_API_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "/.idea\n/auth.txt\n__pycache__\n/dist\n/*.egg-info\n"
  },
  {
    "path": "AUTHORS.rst",
    "content": "=======\nCredits\n=======\n\nDevelopment Lead\n----------------\n\n* Nekmo <contacto@nekmo.com>\n\nContributors\n------------\n\nNone yet. Why not be the first?\n"
  },
  {
    "path": "CONTRIBUTING.rst",
    "content": ".. highlight:: shell\n\n============\nContributing\n============\n\nContributions are welcome, and they are greatly appreciated! Every\nlittle bit helps, and credit will always be given.\n\nYou can contribute in many ways:\n\nTypes of Contributions\n----------------------\n\nReport Bugs\n~~~~~~~~~~~\n\nReport bugs at https://github.com/Nekmo/gkeep/issues.\n\nIf you are reporting a bug, please include:\n\n* Your operating system name and version.\n* Any details about your local setup that might be helpful in troubleshooting.\n* Detailed steps to reproduce the bug.\n\nFix Bugs\n~~~~~~~~\n\nLook through the GitHub issues for bugs. Anything tagged with \"bug\"\nand \"help wanted\" is open to whoever wants to implement it.\n\nImplement Features\n~~~~~~~~~~~~~~~~~~\n\nLook through the GitHub issues for features. Anything tagged with \"enhancement\"\nand \"help wanted\" is open to whoever wants to implement it.\n\nWrite Documentation\n~~~~~~~~~~~~~~~~~~~\n\ngkeep could always use more documentation, whether as part of the\nofficial gkeep docs, in docstrings, or even on the web in blog posts,\narticles, and such.\n\nSubmit Feedback\n~~~~~~~~~~~~~~~\n\nThe best way to send feedback is to file an issue at https://github.com/Nekmo/gkeep/issues.\n\nIf you are proposing a feature:\n\n* Explain in detail how it would work.\n* Keep the scope as narrow as possible, to make it easier to implement.\n* Remember that this is a volunteer-driven project, and that contributions\n  are welcome :)\n\nGet Started!\n------------\n\nReady to contribute? Here's how to set up `gkeep` for local development.\n\n1. Fork the `gkeep` repo on GitHub.\n2. Clone your fork locally::\n\n    $ git clone git@github.com:your_name_here/gkeep.git\n\n3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::\n\n    $ mkvirtualenv gkeep\n    $ cd gkeep/\n    $ python setup.py develop\n\n4. Create a branch for local development::\n\n    $ git checkout -b name-of-your-bugfix-or-feature\n\n   Now you can make your changes locally.\n\n5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox::\n\n    $ flake8 gkeep tests\n    $ python setup.py test or py.test\n    $ tox\n\n   To get flake8 and tox, just pip install them into your virtualenv.\n\n6. Commit your changes and push your branch to GitHub::\n\n    $ git add .\n    $ git commit -m \"Your detailed description of your changes.\"\n    $ git push origin name-of-your-bugfix-or-feature\n\n7. Submit a pull request through the GitHub website.\n\nPull Request Guidelines\n-----------------------\n\nBefore you submit a pull request, check that it meets these guidelines:\n\n1. The pull request should include tests.\n2. If the pull request adds functionality, the docs should be updated. Put\n   your new functionality into a function with a docstring, and add the\n   feature to the list in README.rst.\n3. The pull request should work for Python 2.6, 2.7, 3.3, 3.4 and 3.5, and for PyPy. Check\n   https://travis-ci.org/Nekmo/gkeep/pull_requests\n   and make sure that the tests pass for all supported Python versions.\n\nTips\n----\n\nTo run a subset of tests::\n\n\n    $ python -m unittest tests.test_gkeep\n"
  },
  {
    "path": "HISTORY.rst",
    "content": "=======\nHistory\n=======\n\n1.0.0 (2020-10-23)\n------------------\n\n* Issue #32: Use entrypoints in setup\n* Issue #31: AttributeError: 'ColorValue' object has no attribute 'title'\n* Issue #7: Archived & Pinned options\n* Issue #6: Labels commands\n* Issue #27: Remove auth argument\n* Issue #25: Authentication cli assistant\n* Issue #28: Create docs\n* Issue #30: Refactor notes query params\n\n\n0.2.1 (2020-05-09)\n------------------\n\n* Issue #26: Do not use the pip's internal api as it isn't working anymore\n\n\n0.2.0 (2020-04-25)\n------------------\n\n* Issue #23: Create changelog\n* Issue #22: Upload to Pypi using Travis CI\n* Issue #21: Document note commands\n* Issue #5: Notes commands\n\n0.1.1 (2018-05-07)\n------------------\n\n* Issue #9: How to install gkeep ( gkeep --auth ~/.gkeepauth FAILS)\n\n\n0.1.1 (2018-04-16)\n------------------\n\n* Pip 10.0 support\n\n0.1.0 (2018-01-02)\n------------------\n\n* Initial release (item commands).\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include common-requirements.txt\ninclude py2-requirements.txt\ninclude py3-requirements.txt\ninclude README.rst"
  },
  {
    "path": "Makefile",
    "content": ".PHONY: clean clean-test clean-pyc clean-build docs help\n.DEFAULT_GOAL := help\ndefine BROWSER_PYSCRIPT\nimport os, webbrowser, sys\ntry:\n\tfrom urllib import pathname2url\nexcept:\n\tfrom urllib.request import pathname2url\n\nwebbrowser.open(\"file://\" + pathname2url(os.path.abspath(sys.argv[1])))\nendef\nexport BROWSER_PYSCRIPT\n\ndefine PRINT_HELP_PYSCRIPT\nimport re, sys\n\nfor line in sys.stdin:\n\tmatch = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)\n\tif match:\n\t\ttarget, help = match.groups()\n\t\tprint(\"%-20s %s\" % (target, help))\nendef\nexport PRINT_HELP_PYSCRIPT\nBROWSER := python -c \"$$BROWSER_PYSCRIPT\"\n\nhelp:\n\t@python -c \"$$PRINT_HELP_PYSCRIPT\" < $(MAKEFILE_LIST)\n\nclean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts\n\n\nclean-build: ## remove build artifacts\n\trm -fr build/\n\trm -fr dist/\n\trm -fr .eggs/\n\tfind . -name '*.egg-info' -exec rm -fr {} +\n\tfind . -name '*.egg' -exec rm -f {} +\n\nclean-pyc: ## remove Python file artifacts\n\tfind . -name '*.pyc' -exec rm -f {} +\n\tfind . -name '*.pyo' -exec rm -f {} +\n\tfind . -name '*~' -exec rm -f {} +\n\tfind . -name '__pycache__' -exec rm -fr {} +\n\nclean-test: ## remove test and coverage artifacts\n\trm -fr .tox/\n\trm -f .coverage\n\trm -fr htmlcov/\n\nlint: ## check style with flake8\n\tflake8 business_theme tests\n\ntest: ## run tests quickly with the default Python\n\tpython setup.py test\n\ntest-all: ## run tests on every Python version with tox\n\ttox\n\ncoverage: ## check code coverage quickly with the default Python\n\tcoverage run --source business_theme setup.py test\n\tcoverage report -m\n\tcoverage html\n\t$(BROWSER) htmlcov/index.html\n\ndocs: ## generate Sphinx HTML documentation, including API docs\n\tcd docs/; make pdf\n\nservedocs: docs ## compile the docs watching for changes\n\twatchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .\n\nrelease: clean ## package and upload a release\n\tpython setup.py sdist upload\n\tpython setup.py bdist_wheel upload\n\ndist: build-sdist build-wheel\n\tls -l dist\n\ninstall: clean ## install the package to the active Python's site-packages\n\tpython setup.py install\n\nbuild-sdist:\n\tpython setup.py sdist\n\t@echo\n\t@echo \"Build tar.gz package finished.\"\n\nbuild-wheel:\n\tpython setup.py bdist_wheel\n\t@echo\n\t@echo \"Build wheel package\"\n"
  },
  {
    "path": "README.rst",
    "content": ".. image:: https://raw.githubusercontent.com/Nekmo/gkeep/master/logo.jpg\n    :width: 100%\n\n|\n\n.. image:: https://raw.githubusercontent.com/Nekmo/gkeep/pip-rating-badge/pip-rating-badge.svg\n  :target: https://github.com/Nekmo/gkeep/actions/workflows/pip-rating.yml\n  :alt: pip-rating badge\n\n.. image:: https://img.shields.io/pypi/v/gkeep.svg?style=flat-square\n  :target: https://pypi.org/project/gkeep/\n  :alt: Latest PyPI version\n\n.. image:: https://img.shields.io/pypi/pyversions/gkeep.svg?style=flat-square\n  :target: https://pypi.org/project/gkeep/\n  :alt: Python versions\n\n.. image:: https://img.shields.io/github/stars/Nekmo/gkeep?style=flat-square\n     :target: https://github.com/Nekmo/gkeep\n     :alt: Github stars\n\n**DEVELOPMENT BRANCH**: The current branch is a development version. Go to the stable release by clicking\non `the master branch <https://github.com/Nekmo/gkeep/tree/master>`_.\n\n\nGoogle Keep Cli\n###############\nWork with Google Keep on your terminal. To install this module\n(`more options in the documentation <https://docs.nekmo.org/gkeep/installation.html>`_)::\n\n    $ pip install -U gkeep\n\n\nTo get the available options use the ``--help`` parameter or\n`see the documentation <https://docs.nekmo.org/gkeep/usage.html>`_::\n\n    $ gkeep --help\n\nFor example **to search for notes**::\n\n    $ gkeep notes search \"Shopping list\"\n\nGkeep allows you to use Google Keep **in your scripts**. For example to remember to buy milk::\n\n    $ gkeep items edit --uncheck 150ad84b557.97eb8e3bffcb03e1 \"Milk\"\n\n\nThanks\n======\nThis module is a command-line interface of the module `gkeepapi <https://github.com/kiwiz/gkeepapi/>`_.\nThanks to Kiwiz for maintaining the module.\n\nThis module does not use an official Google API to work with Google Keep. As this module does not use an official\nAPI, its operation is not guaranteed for a production environment.\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nSPHINXAPIDOC  = sphinx-apidoc\nPAPER         =\nBUILDDIR      = _build\nPROJECT_NAME  = Google Keep CLI\nDRIVE_FOLDER  = \n\n# User-friendly check for sphinx-build\nifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)\n$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)\nendif\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n# the i18n builder cannot share the environment and doctrees with the others\nI18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n\n.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext\n\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  pdf       to make standalone PDF files\"\n\t@echo \"  html       to make standalone HTML files\"\n\t@echo \"  watch      Browser Sync watcher for build HTML files on real time\"\n\t@echo \"  dirhtml    to make HTML files named index.html in directories\"\n\t@echo \"  singlehtml to make a single large HTML file\"\n\t@echo \"  pickle     to make pickle files\"\n\t@echo \"  json       to make JSON files\"\n\t@echo \"  htmlhelp   to make HTML files and a HTML help project\"\n\t@echo \"  qthelp     to make HTML files and a qthelp project\"\n\t@echo \"  devhelp    to make HTML files and a Devhelp project\"\n\t@echo \"  epub       to make an epub\"\n\t@echo \"  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  latexpdf   to make LaTeX files and run them through pdflatex\"\n\t@echo \"  latexpdfja to make LaTeX files and run them through platex/dvipdfmx\"\n\t@echo \"  text       to make text files\"\n\t@echo \"  man        to make manual pages\"\n\t@echo \"  texinfo    to make Texinfo files\"\n\t@echo \"  info       to make Texinfo files and run them through makeinfo\"\n\t@echo \"  gettext    to make PO message catalogs\"\n\t@echo \"  changes    to make an overview of all changed/added/deprecated items\"\n\t@echo \"  xml        to make Docutils-native XML files\"\n\t@echo \"  pseudoxml  to make pseudoxml-XML files for display purposes\"\n\t@echo \"  linkcheck  to check all external links for integrity\"\n\t@echo \"  doctest    to run all doctests embedded in the documentation (if enabled)\"\n\nclean:\n\trm -rf $(BUILDDIR)/*\n\nrinohpdf:\n\t$(SPHINXAPIDOC) -o . ../\n\t$(SPHINXBUILD) -b rinoh . $(BUILDDIR)/pdf\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\npdf:\n\tHTML_THEME=business_theme make singlehtml\n\tweasyprint _build/singlehtml/index.html \"$(PROJECT_NAME).pdf\"\n\trm -rf _build\n\tpython -m business_theme upload \"$(PROJECT_NAME).pdf\" \"$(PROJECT_NAME).pdf\" \"$(DRIVE_FOLDER)\"\n\t@echo\n\t@echo \"Build finished. The PDF file is in $(BUILDDIR)/.\"\n\nhtml:\n\trm -rf $(BUILDDIR)\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/dirhtml.\"\n\nsinglehtml:\n\t$(SPHINXAPIDOC) -o . ../\n\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml\n\t@echo\n\t@echo \"Build finished. The HTML page is in $(BUILDDIR)/singlehtml.\"\n\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in $(BUILDDIR)/htmlhelp.\"\n\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in $(BUILDDIR)/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator $(BUILDDIR)/qthelp/delfos.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile $(BUILDDIR)/qthelp/delfos.qhc\"\n\ndevhelp:\n\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp\n\t@echo\n\t@echo \"Build finished.\"\n\t@echo \"To view the help file:\"\n\t@echo \"# mkdir -p $$HOME/.local/share/devhelp/delfos\"\n\t@echo \"# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/delfos\"\n\t@echo \"# devhelp\"\n\nepub:\n\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub\n\t@echo\n\t@echo \"Build finished. The epub file is in $(BUILDDIR)/epub.\"\n\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in $(BUILDDIR)/latex.\"\n\t@echo \"Run \\`make' in that directory to run these through (pdf)latex\" \\\n\t      \"(use \\`make latexpdf' here to do that automatically).\"\n\nlatexpdf:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through pdflatex...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\nlatexpdfja:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through platex and dvipdfmx...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\ntext:\n\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text\n\t@echo\n\t@echo \"Build finished. The text files are in $(BUILDDIR)/text.\"\n\nman:\n\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man\n\t@echo\n\t@echo \"Build finished. The manual pages are in $(BUILDDIR)/man.\"\n\ntexinfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo\n\t@echo \"Build finished. The Texinfo files are in $(BUILDDIR)/texinfo.\"\n\t@echo \"Run \\`make' in that directory to run these through makeinfo\" \\\n\t      \"(use \\`make info' here to do that automatically).\"\n\ninfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo \"Running Texinfo files through makeinfo...\"\n\tmake -C $(BUILDDIR)/texinfo info\n\t@echo \"makeinfo finished; the Info files are in $(BUILDDIR)/texinfo.\"\n\ngettext:\n\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale\n\t@echo\n\t@echo \"Build finished. The message catalogs are in $(BUILDDIR)/locale.\"\n\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes\n\t@echo\n\t@echo \"The overview file is in $(BUILDDIR)/changes.\"\n\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in $(BUILDDIR)/linkcheck/output.txt.\"\n\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/doctest/output.txt.\"\n\nxml:\n\t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml\n\t@echo\n\t@echo \"Build finished. The XML files are in $(BUILDDIR)/xml.\"\n\npseudoxml:\n\t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml\n\t@echo\n\t@echo \"Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml.\"\n"
  },
  {
    "path": "docs/authors.rst",
    "content": ".. include:: ../AUTHORS.rst\n"
  },
  {
    "path": "docs/conf.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Google Keep CLI documentation build configuration file, created by\n# sphinx-quickstart on Tue Jul  9 22:26:36 2013.\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\nimport datetime\nimport sys\nimport os\n# import django\n\n# If extensions (or modules to document with autodoc) are in another\n# directory, add these directories to sys.path here. If the directory is\n# relative to the documentation root, use os.path.abspath to make it\n# absolute, like shown here.\n\n\n# Insert the project root dir as the first element in the PYTHONPATH.\n# This lets us ensure that the source package is imported, and that its\n# version is used.\ndirectory = os.path.dirname(os.path.abspath(__file__))\n\nsys.path.append(os.path.abspath(os.path.join(directory, '../')))\n\n# sys.path.append(os.path.abspath(os.path.join(directory, '../')))\n# os.environ['DJANGO_SETTINGS_MODULE'] = 'Google Keep CLI.settings.develop'\n# django.setup()\n\n# -- General configuration ---------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = [\n    'sphinx.ext.autodoc',\n    'sphinx.ext.intersphinx',\n    'sphinx_click.ext'\n    # 'sphinxcontrib.autohttp.drf',\n    # 'sphinxcontrib_django',\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'Google Keep CLI'\ncopyright = u\"%i, Nekmo\" % datetime.date.today().year\n\npdf_documents = [('index', u'rst2pdf', u'Google Keep CLI', u'Nekmo'), ]\n\nrinoh_documents = [('index',            # top-level file (index.rst)\n                    'target',           # output (target.pdf)\n                    'Google Keep CLI',   # document title\n                    'Nekmo')]   # document author\n# rinoh_logo = '_static/logo.png'\nrinoh_domain_indices = False\n\nhtml_context = dict(docs_scope='external')\n\n# The version info for the project you're documenting, acts as replacement\n# for |version| and |release|, also used in various other places throughout\n# the built documents.\n#\n# The short X.Y version.\nversion = '0.1.0'\n# The full version, including alpha/beta/rc tags.\nrelease = '0.1.0'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#language = None\n\n# There are two options for replacing |today|: either, you set today to\n# some non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = ['_build']\n\n# The reST default role (used for this markup: `text`) to use for all\n# documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\n# pygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built\n# documents.\n#keep_warnings = False\n\n\n# -- Options for HTML output -------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = os.environ.get('HTML_THEME', 'alabaster')\n\n# Theme options are theme-specific and customize the look and feel of a\n# theme further.  For a list of options available for each theme, see the\n# documentation.\nhtml_theme_options = {\n    'logo': 'logo.png',\n    'description': 'Google Keep Command Line Interface (CLI)',\n    'github_user': 'Nekmo',\n    'github_repo': 'gkeep',\n    'github_type': 'star',\n    'github_banner': True,\n    'travis_button': True,\n    'codecov_button': True,\n    'analytics_id': 'UA-62276079-1',\n    'canonical_url': 'http://docs.nekmo.org/gkeep/'\n}\n\n\n# Add any paths that contain custom themes here, relative to this directory.\nhtml_theme_path = ['.']\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as\n# html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the\n# top of the sidebar.\n#html_logo = None\n\n# The name of an image file (within the static path) to use as favicon\n# of the docs.  This file should be a Windows icon file (.ico) being\n# 16x16 or 32x32 pixels large.\n#html_favicon = None\n\n# Add any paths that contain custom static files (such as style sheets)\n# here, relative to this directory. They are copied after the builtin\n# static files, so a file named \"default.css\" will overwrite the builtin\n# \"default.css\".\nhtml_static_path = ['_static']\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page\n# bottom, using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n# html_sidebars = {\n#     '**': [\n#         'about.html',\n#         'navigation.html',\n#         'relations.html',\n#         'searchbox.html',\n#         'donate.html',\n#     ]\n# }\n\n# Additional templates that should be rendered to pages, maps page names\n# to template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n#html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer.\n# Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer.\n# Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages\n# will contain a <link> tag referring to it.  The value of this option\n# must be the base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'Google Keep CLIdoc'\n\n\n# -- Options for LaTeX output ------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    'papersize': 'letterpaper',\n\n    # The font size ('10pt', '11pt' or '12pt').\n    'pointsize': '10pt',\n\n    # Additional stuff for the LaTeX preamble.\n    'preamble': '',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, documentclass\n# [howto/manual]).\nlatex_documents = [\n    ('index', 'Google Keep CLI.tex',\n     u'Google Keep CLI Documentation',\n     u'Nekmo', 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at\n# the top of the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings\n# are parts, not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output ------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    ('index', 'Google Keep CLI',\n     u'Google Keep CLI Documentation',\n     [u'Nekmo'], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output ----------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    ('index', 'Google Keep CLI',\n     u'Google Keep CLI Documentation',\n     u'Nekmo',\n     'Google Keep CLI',\n     'One line description of project.',\n     'Miscellaneous'),\n]\n\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n\n# If true, do not generate a @detailmenu in the \"Top\" node's menu.\n#texinfo_no_detailmenu = False\n\ndef setup(app):\n    # app.add_stylesheet('custom.css')\n    pass\n"
  },
  {
    "path": "docs/contributing.rst",
    "content": ".. include:: ../CONTRIBUTING.rst\n"
  },
  {
    "path": "docs/history.rst",
    "content": ".. include:: ../HISTORY.rst\n"
  },
  {
    "path": "docs/index.rst",
    "content": "Welcome to gkeep's documentation!\n=================================\nGoogle Keep Command Line Interface (CLI). Create and update notes from the command line. Use this program to automate\nthe creation of notes.\n\nTo **install** gkeep, run this command in your terminal:\n\n.. code-block:: console\n\n    $ pip install -U gkeep\n\n\nContents\n--------\n\n.. toctree::\n   :maxdepth: 2\n   :glob:\n\n   installation\n   readme\n   usage\n   contributing\n   authors\n   history\n\n..\n   _ modules\n"
  },
  {
    "path": "docs/installation.rst",
    "content": ".. highlight:: console\n\n============\nInstallation\n============\n\n\nStable release\n--------------\n\nTo install gkeep, run these commands in your terminal:\n\n.. code-block:: console\n\n    $ sudo pip3 install -U gkeep\n\nThis is the preferred method to install gkeep, as it will always install the most recent stable release.\n\nIf you don't have `pip`_ installed, this `Python installation guide`_ can guide\nyou through the process.\n\n.. _pip: https://pip.pypa.io\n.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/\n\n\nOther releases\n--------------\nYou can install other versions from Pypi using::\n\n    $ pip install gkeep==<version>\n\nFor versions that are not in Pypi (it is a development version)::\n\n    $ pip install git+https://github.com/Nekmo/gkeep.git@<branch>#egg=gkeep\n\n\nIf you do not have git installed::\n\n    $ pip install https://github.com/Nekmo/gkeep/archive/<branch>.zip\n\n\nTroubleshooting\n---------------\nGkeep is unstable because **it doesn't use an official Google api**. Before opening a new incident update gkeep and its\ndependencies to the latest version::\n\n    $ pip install -U gkeep --upgrade-strategy eager\n\nIn case of problems with **authentication** check the credentials file in ``~/.config/gkeep/auth.json``. It is\nrecommended to protect this file for security. Accounts with two-step authentication must use an application password.\nFor more info: https://support.google.com/mail/answer/185833\n"
  },
  {
    "path": "docs/readme.rst",
    "content": ".. include:: ../README.rst\n"
  },
  {
    "path": "docs/usage.rst",
    "content": "\nUsage\n#####\n\n.. click:: google_keep_tasks.management:notes\n   :prog: gkeep notes\n   :show-nested:\n\n.. click:: google_keep_tasks.management:items\n   :prog: gkeep items\n   :show-nested:\n\n.. click:: google_keep_tasks.management:labels\n   :prog: gkeep labels\n   :show-nested:\n"
  },
  {
    "path": "google_keep_tasks/__init__.py",
    "content": "\n__version__ = '1.0.1'"
  },
  {
    "path": "google_keep_tasks/_compat.py",
    "content": "\ntry:\n    from json import JSONDecodeError\nexcept ImportError:\n    JSONDecodeError = ValueError\n"
  },
  {
    "path": "google_keep_tasks/auth.py",
    "content": "import json\nimport os\n\nimport click\nimport gkeepapi\nfrom click import Abort\nfrom gkeepapi.exception import LoginException\n\nfrom google_keep_tasks.cli import choices_prompt\nfrom google_keep_tasks.exceptions import UnavailableLoginError, LoginError\nfrom google_keep_tasks._compat import JSONDecodeError\n\nAUTH_FILE = os.path.expanduser('~/.config/gkeep/auth.json')\n\n\ndef get_auth(file='auth.txt'):\n    return [val.rstrip('\\n\\r') for val in open(file).read().split(' ')]\n\n\nclass GoogleKeepFileAuth(object):\n    def __init__(self, file=None):\n        self.file = file or AUTH_FILE\n\n    def save_credentials(self, username, password):\n        data = {'username': username, 'password': password}\n        directory = os.path.dirname(AUTH_FILE)\n        if not os.path.exists(directory):\n            os.makedirs(directory, 0o700)\n        json.dump(data, open(self.file, 'w'))\n\n    def get_credentials(self):\n        if not os.path.lexists(self.file):\n            raise UnavailableLoginError('Credential files \"{}\" does not exists'.format(self.file))\n        try:\n            data = json.load(open(self.file))\n        except JSONDecodeError as e:\n            raise LoginError('Invalid json from credentials file: {}. Error: {}'.format(\n                self.file, e\n            ))\n        if not isinstance(data, dict) or 'username' not in data or 'password' not in data:\n            raise LoginError('Invalid credentials format file. username and password are required.')\n        return data['username'], data['password']\n\n\nclass GoogleKeep(object):\n    def __init__(self):\n        self.keep = gkeepapi.Keep()\n        self.auth = GoogleKeepFileAuth()\n\n    def login_or_input(self):\n        auth_changed = False\n        input_login = False\n        username = password = None\n        try:\n            username, password = self.auth.get_credentials()\n        except UnavailableLoginError:\n            click.echo('Welcome to Google Keep. Enter your username and password below. '\n                       'If your account is protected, you need an application password: '\n                       'https://support.google.com/mail/answer/185833')\n            input_login = True\n        except LoginError as e:\n            click.echo('The credentials file is corrupt: {}. Credentials must be re-entered.'.format(e))\n            input_login = True\n        while True:\n            if input_login:\n                # Request new credentials\n                auth_changed = True\n                username, password = self.get_credencials_assistant(username)\n            try:\n                self.keep.login(username, password)\n            except LoginException:\n                choice = choices_prompt('Authentication failed, what do you want to do?', [\n                    'Enter new credentials',\n                    'retry',\n                    'abort',\n                ], 'e')\n                if choice == 'e':\n                    input_login = True\n                elif choice == 'r':\n                    input_login = False\n                elif choice == 'a':\n                    raise Abort\n            else:\n                if auth_changed:\n                    self.auth.save_credentials(username, password)\n                break\n\n    def get_credencials_assistant(self, default_username):\n        username = click.prompt('Enter your Google username', type=str,\n                                show_default=True, default=default_username)\n        password = click.prompt('Enter your password', hide_input=True)\n        return username, password\n"
  },
  {
    "path": "google_keep_tasks/cli.py",
    "content": "import click\n\n\ndef choices_prompt(text, choices, default_choice):\n    choices_descriptions = ['  [{}]{}'.format(choice[0].upper() if default_choice == choice[0] else choice[0],\n                                              choice[1:])\n                            for choice in choices]\n    choices_letters = [choice[0].upper() if default_choice == choice[0] else choice[0] for choice in choices]\n    choice = click.prompt(\n        '{}\\n\\n'.format(text) +\n        '\\n'.join(choices_descriptions) +\n        '\\nEnter a choice [{}]'.format('/'.join(choices_letters)),\n        default=default_choice, show_default=False\n    )\n    if not next(iter(filter(lambda x: x == choice.lower(), map(lambda x: x.lower(), choices_letters))), None):\n        return default_choice\n    return choice.lower()\n\n\nclass GkeepHelpFormatter(click.HelpFormatter):\n    def write(self, string):\n        \"\"\"Remove rst characters.\"\"\"\n        return super().write(string.replace('``', ''))\n\n\nclass GkeepContext(click.Context):\n    def make_formatter(self):\n        return GkeepHelpFormatter(width=self.terminal_width,\n                                  max_width=self.max_content_width)\n\n\nclass GkeepGroup(click.Group):\n    def make_context(self, info_name, args, parent=None, **extra):\n        for key, value in self.context_settings.items():\n            if key not in extra:\n                extra[key] = value\n        ctx = GkeepContext(self, info_name=info_name, parent=parent, **extra)\n        with ctx.scope(cleanup=False):\n            self.parse_args(ctx, args)\n        return ctx\n"
  },
  {
    "path": "google_keep_tasks/exceptions.py",
    "content": "import sys\n\n\nclass GKeepError(Exception):\n    body = ''\n\n    def __init__(self, extra_body=''):\n        self.extra_body = extra_body\n\n    def __str__(self):\n        msg = self.__class__.__name__\n        if self.body:\n            msg += ': {}'.format(self.body)\n        if self.extra_body:\n            msg += ('. {}' if self.body else ': {}').format(self.extra_body)\n        return msg\n\n\nclass ItemNotFound(GKeepError):\n    def __init__(self, text):\n        super(ItemNotFound, self).__init__('Item text not found: {}'.format(text))\n\n\nclass LoginError(GKeepError):\n    body = 'Check credentials file. The syntax is: <username> <password>.'\n\n\nclass UnavailableLoginError(GKeepError):\n    body = 'Unavailable credentials'\n\n\nclass InvalidColor(GKeepError):\n    def __init__(self, invalid_color):\n        import gkeepapi\n        colors = [color.name for color in gkeepapi.node.ColorValue]\n        super(InvalidColor, self).__init__('Invalid color: {}. Available colors: {}'.format(\n            invalid_color, ', '.join(colors)\n        ))\n\n\ndef catch(fn):\n    def wrap(*args, **kwargs):\n        try:\n            fn(*args, **kwargs)\n        except GKeepError as e:\n            sys.stderr.write('[Error] GKeep Exception:\\n{}\\n'.format(e))\n    return wrap\n"
  },
  {
    "path": "google_keep_tasks/items.py",
    "content": "import click\n\nfrom google_keep_tasks.cli import GkeepGroup\nfrom google_keep_tasks.exceptions import ItemNotFound\n# from google_keep_tasks.management import cli\n\n\ndef search_item(items, text):\n    for item in items:\n        if item.text == text:\n            return item\n    raise ItemNotFound(text)\n\n\n@click.group(cls=GkeepGroup)\ndef items():\n    \"\"\"Use ``items`` command to work with the note checkboxes. This command has\n    subcommands for adding, editing, deleting or check/uncheck items. To see all\n    subcommands of ``items`` use ``--help``::\n\n        gkeep items --help\n\n    An example of a subcommand is ``add``. To see help use\n    ``gkeep items add --help``.  In all ``items`` subcommands, note ``id`` argument is\n    mandatory. To get note ``id`` use ``gkeep notes search`` or ``gkeep notes get``.\n    \"\"\"\n\n\n@items.command('add', options_metavar='[options]')\n@click.option('--check/--uncheck', default=None, help='Item is checked or not')\n@click.option('--duplicate/--no-duplicate', default=False,\n              help='By default if the element already exists, it is not duplicated. '\n                   'If you want duplicate the element, use the this parameter')\n@click.argument('id', metavar='<id>')\n@click.argument('text', metavar='<text>')\n@click.pass_context\ndef add_item(ctx, check, duplicate, id, text):\n    \"\"\"Add a item to an existing note. By default if the element already exists,\n    it is not duplicated. To duplicate the element use ``--duplicate`` param. By\n    default the item is created unchecked.\n\n    .. code-block:: shell\n\n        gkeep items add 75e4202b0c1.9fc0b868a7b34952 \"Chip cookies\" --check\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    gnote = keep.get(id)\n    try:\n        item = search_item(gnote.items, text)\n        check = item.checked if check is None else check\n    except ItemNotFound:\n        item = None\n        check = False if check is None else check\n    if item and not duplicate:\n        item.checked = check\n    else:\n        gnote.add(text, check)\n    keep.sync()\n\n\n@items.command('edit', options_metavar='[options]')\n@click.option('--check/--uncheck', default=None, help='Item is checked or not')\n@click.option('--new-text', default='New element text', metavar='<text>')\n@click.argument('id', metavar='<id>')\n@click.argument('text', metavar='<text>')\n@click.pass_context\ndef edit_item(ctx, check, new_text, id, text):\n    \"\"\"Edit an existing item. Use this command to change the text or\n    check or uncheck the item. For example:\n\n    .. code-block:: shell\n\n        gkeep items edit 75e4202b0c1.9fc0b868a7b34952 \"Chip cookies\" --uncheck\n\n    Another example:\n\n    .. code-block:: shell\n\n        gkeep items edit 75e4202b0c1.9fc0b868a7b34952 \"Chip cookies\"\n                         --new-text \"Chocolate orange cookies\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    gnote = keep.get(id)\n    item = search_item(gnote.items, text)\n    item.text = new_text or item.text\n    item.checked = item.checked if check is None else check\n    keep.sync()\n\n\n@items.command('delete', options_metavar='[options]')\n@click.argument('id', metavar='<id>')\n@click.argument('text', metavar='<text>')\n@click.pass_context\ndef delete_item(ctx, id, text):\n    \"\"\"Delete a item to an existing note.\n\n    .. code-block:: shell\n\n        gkeep items delete 75e4202b0c1.9fc0b868a7b34952 \"Chip cookies\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    gnote = keep.get(id)\n    item = search_item(gnote.items, text)\n    item.delete()\n    keep.sync()\n\n\n@items.command('is-checked', options_metavar='[options]')\n@click.argument('id', metavar='<id>')\n@click.argument('text', metavar='<text>')\n@click.pass_context\ndef delete_item(ctx, id, text):\n    \"\"\"Returns ``True`` if the item is checked and ``False`` if it is unchecked.\n\n    .. code-block:: shell\n\n        gkeep items is-checked 75e4202b0c1.9fc0b868a7b34952 \"Chip cookies\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    gnote = keep.get(id)\n    item = search_item(gnote.items, text)\n    print(item.checked)\n    keep.sync()\n"
  },
  {
    "path": "google_keep_tasks/labels.py",
    "content": "import sys\n\nimport click\nfrom gkeepapi.exception import LabelException\n\nfrom google_keep_tasks.cli import GkeepGroup\nfrom google_keep_tasks.utils import pretty_date\n\n\ndef format_label(label):\n    return u'━ {}'.format(label)\n\n\ndef format_label_with_timestaps(label):\n    return u'{} (created {}, updated {})'.format(\n        format_label(label),\n        pretty_date(label.timestamps.created),\n        pretty_date(label.timestamps.updated),\n    )\n\n\n@click.group(cls=GkeepGroup)\ndef labels():\n    \"\"\"List, create, rename or delete labels using ``labels`` command.\n    This command has subcommands for adding, searching, editing, or\n    deleting labels. To see all subcommands of ``labels`` use ``--help``::\n\n        gkeep labels --help\n\n    An example of a subcommand is ``add``. To see help use\n    ``gkeep labels add --help``.\n    \"\"\"\n    pass\n\n\n@labels.command('list', options_metavar='[options]')\n@click.option('--timestamps', is_flag=True, help='Include timestaps per each label.')\n@click.pass_context\ndef list_labels(ctx, timestamps):\n    \"\"\"List labels on Google Keep. For example:\n\n    .. code-block:: shell\n\n        gkeep labels list\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    fmt = format_label_with_timestaps if timestamps else format_label\n    click.echo(u'\\n'.join([\n         fmt(label) for label in keep.labels()]\n    ))\n\n\n@labels.command('add', options_metavar='[options]')\n@click.argument('title', metavar='<title>')\n@click.pass_context\ndef add_label(ctx, title):\n    \"\"\"Create a label on Google Keep. For example:\n\n    .. code-block:: shell\n\n        gkeep labels create \"Label name\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    try:\n        keep.createLabel(title)\n    except LabelException as e:\n        click.echo(u'Error creating label: {}'.format(e), err=True)\n        sys.exit(3)\n    keep.sync()\n    click.echo(f'Created label {title}')\n\n\n@labels.command('edit', options_metavar='[options]')\n@click.argument('old_title', metavar='<old_title>')\n@click.argument('title', metavar='<new_title>')\n@click.pass_context\ndef edit_label(ctx, old_title, title):\n    \"\"\"Rename a label title. For example:\n\n    .. code-block:: shell\n\n        gkeep labels edit \"Old title\" \"New title\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    label = keep.findLabel(old_title)\n    if not label:\n        click.echo(u'The label was not found', err=True)\n        sys.exit(2)\n    new_label = keep.findLabel(title)\n    if new_label:\n        click.echo(u'The label {} already exists'.format(title), err=True)\n        sys.exit(2)\n    label.name = title\n    keep.sync()\n    click.echo(f'Renamed label {old_title} to {title}')\n\n\n@labels.command('delete', options_metavar='[options]')\n@click.argument('title', metavar='<title>')\n@click.pass_context\ndef edit_label(ctx, title):\n    \"\"\"Delete a label. For example:\n\n    .. code-block:: shell\n\n        gkeep labels delete \"Label name\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    label = keep.findLabel(title)\n    if label and (label.deleted or label.trashed):\n        click.echo(u'The label \"{}\" had already been deleted.'.format(title), err=True)\n        sys.exit(2)\n    elif label:\n        keep.deleteLabel(label)\n        keep.sync()\n        click.echo('Label \"{}\" deleted.'.format(title))\n    else:\n        click.echo('The label was not found', err=True)\n        sys.exit(2)\n"
  },
  {
    "path": "google_keep_tasks/management.py",
    "content": "import sys\n\nimport click\n\nfrom google_keep_tasks.auth import GoogleKeep\nfrom google_keep_tasks.cli import GkeepGroup\nfrom google_keep_tasks.items import items\nfrom google_keep_tasks.labels import labels\nfrom google_keep_tasks.notes import notes\n\n\n@click.group(cls=GkeepGroup)\n@click.option('--debug/--no-debug', default=None)\n@click.pass_context\ndef cli(ctx, debug):\n    google_keep = GoogleKeep()\n    if sys.argv[-1] not in ctx.help_option_names:\n        google_keep.login_or_input()\n    ctx.obj = {'keep': google_keep.keep}\n\n\ncli.add_command(items)\ncli.add_command(notes)\ncli.add_command(labels)\n"
  },
  {
    "path": "google_keep_tasks/notes.py",
    "content": "# -*- coding: utf-8 -*-\nimport click\nimport gkeepapi\nimport sys\n\nfrom google_keep_tasks.cli import GkeepGroup\nfrom google_keep_tasks.exceptions import InvalidColor\n\n\nCOLORS = {\n    gkeepapi.node.ColorValue.Gray: {'bg': 'black', 'fg': 'white'},\n    gkeepapi.node.ColorValue.Red: {'bg': 'red', 'fg': 'white'},\n    gkeepapi.node.ColorValue.Green: {'bg': 'green'},\n    gkeepapi.node.ColorValue.Yellow: {'bg': 'green', 'fg': 'black'},\n    gkeepapi.node.ColorValue.Blue: {'bg': 'cyan', 'fg': 'white'},\n    gkeepapi.node.ColorValue.DarkBlue: {'bg': 'blue', 'fg': 'white'},\n    gkeepapi.node.ColorValue.Purple: {'bg': 'magenta', 'fg': 'white'},\n    gkeepapi.node.ColorValue.White: {'bg': 'white', 'fg': 'black'},\n}\nCOLOR_NAMES = [color.name.lower() for color in gkeepapi.node.ColorValue]\n\n\ndef get_color(color):\n    if not color:\n        return\n    if isinstance(color, gkeepapi.node.ColorValue):\n        return color\n    color = color.title()\n    if color and not hasattr(gkeepapi.node.ColorValue, color):\n        raise InvalidColor(color)\n    return getattr(gkeepapi.node.ColorValue, color)\n\n\ndef get_click_color(ctx, param, value):\n    return get_color(value)\n\n\ndef find_or_create_label(keep, label_name):\n    label = keep.findLabel(label_name)\n    if not label:\n        label = keep.createLabel(label_name)\n    return label\n\n\ndef add_labels(keep, note, labels):\n    if not labels:\n        return\n    for label in labels:\n        note.labels.add(find_or_create_label(keep, label))\n\n\ndef get_labels(keep, labels):\n    return list(filter(bool, map(keep.findLabel, labels)))\n\n\ndef comma_separated(ctx, param, value):\n    return value.split(',') if value else []\n\n\ndef query_params(keep, **kwargs):\n    kwargs['colors'] = (list(filter(bool, [get_color(kwargs.pop('color'))])) if 'color' in kwargs else []) or None\n    labels = get_labels(keep, kwargs.pop('labels', []))\n    deleted = kwargs.pop('deleted', None)\n    title = kwargs.pop('title', None)\n    text = kwargs.pop('text', None)\n    if any(filter(lambda x: x is not None, [deleted, title, text])) or labels:\n        kwargs['func'] = lambda x: all(filter(lambda y: isinstance(y, bool),\n                                              [x.deleted == deleted if deleted is not None else None,\n                                               x.title == title if title is not None else None,\n                                               x.text == text if text is not None else None,\n                                               set(x.labels.all()) == set(labels) if labels is not None else None]))\n    return kwargs\n\n\ndef print_note(note):\n    params = COLORS.get(note.color, {})\n    note_id = (u'⚲ ' if note.pinned else '') + '(note id {})'.format(note.id)\n    note_id += u' 🗑' if note.deleted or note.trashed else ''\n    click.echo(click.style(note_id, **params))\n    click.echo(click.style('\"' * len(note_id), **params))\n    if note.title:\n        click.echo(click.style(note.title, bold=True))\n    click.echo(note.text)\n    if note.labels:\n        click.echo()\n        click.echo(' '.join(click.style('[{}]'.format(label.name), underline=True, bold=True)\n                            for label in note.labels.all()))\n    click.echo(click.style('\"' * len(note_id), **params))\n    click.echo('\\n')\n\n\ndef get_note_instance(keep, id=None, **kwargs):\n    if id:\n        note = keep.get(id)\n    else:\n        notes = keep.find(**query_params(keep, **kwargs))\n        note = next(notes, None)\n    return note\n\n\n@click.group(cls=GkeepGroup)\ndef notes():\n    \"\"\"Manage Google Keep notes using ``notes`` command.\n    This command has subcommands for adding, searching, editing, or\n    deleting notes. To see all subcommands of ``notes`` use ``--help``::\n\n        gkeep notes --help\n\n    An example of a subcommand is ``add``. To see help use\n    ``gkeep notes add --help``.\n    \"\"\"\n    pass\n\n\n@notes.command('add', options_metavar='[options]')\n@click.option('--color', default='', callback=get_click_color, metavar='<color>',\n              help='Set note color. Choices: {}'.format(', '.join(COLOR_NAMES)))\n@click.option('--labels', default='', callback=comma_separated, metavar='<label>',\n              help='Set note labels. Add multiple labels separated by commas')\n@click.argument('title', metavar='<title>')\n@click.argument('text', metavar='<note_content>')\n@click.pass_context\ndef add_note(ctx, color, labels, title, text):\n    \"\"\"Add a new note to Google Keep.\n    A title and a message body are required for the new note. For example:\n\n    .. code-block:: shell\n\n        gkeep notes add \"Today's tasks\" \"Install gkeep cli and configure it\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    gnote = keep.createNote(title, text)\n    if color:\n        gnote.color = color\n    add_labels(keep, gnote, labels)\n    keep.sync()\n\n\n@notes.command('search', options_metavar='[options]')\n@click.option('--color', default='', callback=get_click_color, metavar='<color>',\n              help='Filter by note color. Choices: {}'.format(', '.join(COLOR_NAMES)))\n@click.option('--labels', default='', callback=comma_separated, metavar='<labels>',\n              help='Filter by label notes. Filter by multiple labels separated by commas.')\n@click.option('--deleted/--not-deleted', default=None,\n              help='Filter by deleted notes or not')\n@click.option('--trashed/--not-trashed', default=None,\n              help='Filter by deleted notes or not')\n@click.option('--pinned/--not-pinned', default=None,\n              help='Filter by pinned notes or not')\n@click.option('--archived/--not-archived', default=None,\n              help='Filter by archived notes or not')\n@click.option('--title', default=None, metavar='<title>',\n              help='Filter by title note')\n@click.option('--text', default=None, metavar='<note_content>',\n              help='Search in note content')\n@click.argument('query', default='', metavar='[query]')\n@click.pass_context\ndef search_notes(ctx, **kwargs):\n    \"\"\"Search for notes using filters or/and use query text. For example:\n\n    .. code-block:: shell\n\n        gkeep notes search --not-deleted \"GKeep installed\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    for note in keep.find(**query_params(keep, **kwargs)):\n        print_note(note)\n\n\n@notes.command('get', options_metavar='[options]')\n@click.argument('id', default=None, required=False, metavar='[id]')\n@click.option('--title', default=None,\n              help='Filter by title note', metavar='<title>')\n@click.option('--query', default='', help='Search in any note field', metavar='<term>')\n@click.pass_context\ndef get_note(ctx, **kwargs):\n    \"\"\"Get a note by its id or by its title or text. If the id is unknown,\n    you can use the ``--title`` and/or ``--text`` filters. For example:\n\n    .. code-block:: shell\n\n        gkeep notes get 161d1ad8c82.b2ed17d26167c9bc\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    note = get_note_instance(keep, **kwargs)\n    if note:\n        print_note(note)\n    else:\n        click.echo('The note was not found', err=True)\n        sys.exit(2)\n\n\n@notes.command('edit', options_metavar='[options]')\n@click.option('--title', default=None, required=False, metavar='<new title>',\n              help='Change the note title')\n@click.option('--text', default=None, required=False, metavar='<new_note_content>',\n              help='Change the note text')\n@click.option('--filter-id', default=None, required=False, metavar='<id>',\n              help='Filter by id note. This is the preferred way to ensure editing the correct note')\n@click.option('--filter-title', default=None, metavar='<title>',\n              help='Filter by note title. The titles of the notes are not unique')\n@click.option('--filter-query', default='', metavar='<term>',\n              help='search in titles and body of the notes. This is the least accurate filter')\n@click.option('--color', default='', callback=get_click_color, metavar='<color>',\n              help='Change note color. Choices: {}'.format(', '.join(COLOR_NAMES)))\n@click.option('--archived/--not-archived', default=None,\n              help='Archive or unarchive note.')\n@click.option('--pinned/--not-pinned', default=None,\n              help='Pin or unpin note.')\n@click.option('--labels', default='', callback=comma_separated, metavar='<new labels>',\n              help='Set note labels')\n@click.pass_context\ndef edit_note(ctx, title, text, color, labels, archived, pinned, filter_id, filter_title, filter_query):\n    \"\"\"It is possible to edit an existing note. The following parameters\n    are available to choose the note to edit. For example:\n\n    .. code-block:: shell\n\n        gkeep notes edit --filter-title \"Today's tasks\" --text \"GKeep installed, continue reading the docs\"\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    note = get_note_instance(keep, id=filter_id, title=filter_title, query=filter_query)\n    if not note:\n        click.echo('The note was not found', err=True)\n        sys.exit(2)\n    updated = {}\n    boolean_nullables = ['archived', 'pinned']  # 3 state params\n    for param in ['title', 'text', 'color', 'labels'] + boolean_nullables:\n        value = locals()[param]\n        if value or (param in boolean_nullables and value is not None):\n            updated[param] = (getattr(note, param), value)\n            setattr(note, param, value)\n    if labels:\n        add_labels(keep, note, labels)\n    keep.sync()\n    click.echo('Updated note fields:\\n\\n' + ('\\n'.join([u'{}: {} 🠞 {}'.format(param, values[0], values[1])\n                                                        for param, values in updated.items()])))\n\n\n@notes.command('delete', options_metavar='[options]')\n@click.argument('id', default=None, required=False, metavar='[id]')\n@click.option('--title', default=None, help='Filter by title note', metavar='<title>')\n@click.option('--query', default='', help='Search in any note field', metavar='<term>')\n@click.pass_context\ndef delete_note(ctx, **kwargs):\n    \"\"\"It works just like get-note. Delete a note by its id or by its title\n    or text. If the id is unknown, you can use the --title and/or --text filters.\n    For example:\n\n    .. code-block:: shell\n\n        gkeep notes delete 161d1ad8c82.b2ed17d26167c9bc\n\n    The syntax is:\n    \"\"\"\n    keep = ctx.obj['keep']\n    note = get_note_instance(keep, **kwargs)\n    if note and (note.deleted or note.trashed):\n        click.echo('The note \"{}\" had already been deleted.'.format(note.title))\n    elif note:\n        note.delete()\n        keep.sync()\n        click.echo('Note with title \"{}\" deleted.'.format(note.title))\n    else:\n        click.echo('The note was not found', err=True)\n        sys.exit(2)\n"
  },
  {
    "path": "google_keep_tasks/utils.py",
    "content": "\n\ndef pretty_date(time=False):\n    \"\"\"\n    Get a datetime object or a int() Epoch timestamp and return a\n    pretty string like 'an hour ago', 'Yesterday', '3 months ago',\n    'just now', etc\n    \"\"\"\n    from datetime import datetime\n    now = datetime.now()\n    if type(time) is int:\n        diff = now - datetime.fromtimestamp(time)\n    elif isinstance(time,datetime):\n        diff = now - time\n    else:\n        diff = now - now\n    second_diff = diff.seconds\n    day_diff = diff.days\n\n    if day_diff < 0:\n        return ''\n\n    if day_diff == 0:\n        if second_diff < 10:\n            return \"just now\"\n        if second_diff < 60:\n            return str(second_diff) + \" seconds ago\"\n        if second_diff < 120:\n            return \"a minute ago\"\n        if second_diff < 3600:\n            return str(second_diff // 60) + \" minutes ago\"\n        if second_diff < 7200:\n            return \"an hour ago\"\n        if second_diff < 86400:\n            return str(second_diff // 3600) + \" hours ago\"\n    if day_diff == 1:\n        return \"Yesterday\"\n    if day_diff < 7:\n        return str(day_diff) + \" days ago\"\n    if day_diff < 31:\n        return str(day_diff // 7) + \" weeks ago\"\n    if day_diff < 365:\n        return str(day_diff // 30) + \" months ago\"\n    return str(day_diff // 365) + \" years ago\"\n"
  },
  {
    "path": "requirements-dev.txt",
    "content": "-r requirements.txt\nbumpversion\nsphinx-click\n"
  },
  {
    "path": "requirements.txt",
    "content": "gkeepapi>=0.10.6\nclick"
  },
  {
    "path": "scripts/gkeep",
    "content": "#!/usr/bin/env python\nfrom google_keep_tasks.exceptions import catch\nfrom google_keep_tasks.management import cli\n\n\nif __name__ == '__main__':\n    catch(cli)()\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Google Keep Command Line Interface (CLI)\n\"\"\"\nfrom setuptools import setup, find_packages\nfrom distutils.version import LooseVersion\nfrom distutils.util import convert_path\nfrom fnmatch import fnmatchcase\nimport os\nimport sys\nimport uuid\nimport pip\n\n\n###############################\n#  Configuración del paquete  #\n###############################\n\n# Información del autor\nAUTHOR = 'Nekmo'\nEMAIL = 'contacto@nekmo.com'\n\n# Información del paquete\nPACKAGE_NAME = 'gkeep'\nPACKAGE_DOWNLOAD_URL = 'https://github.com/Nekmo/gkeep/archive/master.zip'  # .tar.gz\nURL = 'https://github.com/Nekmo/gkeep'\nSTATUS_LEVEL = 3  # 1:Planning 2:Pre-Alpha 3:Alpha 4:Beta 5:Production/Stable 6:Mature 7:Inactive\nKEYWORDS = ['google', 'keep', 'tasks', 'google-keep']  # Palabras clave\n# https://github.com/github/choosealicense.com/tree/gh-pages/_licenses\nCLASSIFIERS = [\n    # Common licenses\n    'License :: OSI Approved :: MIT License',\n    # 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',\n    # 'License :: OSI Approved :: BSD License',\n]  # https://pypi.python.org/pypi?%3Aaction=list_classifiers\nNATURAL_LANGUAGE = 'English'  # English...\n\n# Requerido para la correcta instalación del paquete\nPLATFORMS = [\n    # 'universal',\n    'linux',\n    # 'macosx',\n    # 'solaris',\n    # 'irix',\n    # 'win'\n    # 'bsd'\n    # 'ios'\n    # 'android'\n]\nROOT_INCLUDE = [\n    'requirements.txt',\n    'VERSION',\n    'LICENSE.txt'\n]\nPYTHON_VERSIONS = ['2.7', '3.5-3.10']\n\n######## FIN DE LA CONFIGURACIÓN DEL PAQUTE ########\n\n__author__ = AUTHOR\n__dir__ = os.path.abspath(os.path.dirname(__file__))\n\n# paths\nreadme_path = os.path.join(__dir__, 'README')\nif not os.path.exists(readme_path):\n    readme_path = os.path.join(__dir__, 'README.rst')\nversion_path = os.path.join(__dir__, 'VERSION')\nrequirements_path = os.path.join(__dir__, 'requirements.txt')\nscripts_path = os.path.join(__dir__, 'scripts')\n\n\ndef get_url(ir):\n    if hasattr(ir, 'url'): return ir.url\n    if ir.link is None: return\n    return ir.link.url\n\n\n##############################################################################\n# find_package_data is an Ian Bicking creation.\n\n# Provided as an attribute, so you can append to these instead\n# of replicating them:\nstandard_exclude = ('*.py', '*.pyc', '*~', '.*', '*.bak', '*.swp*')\nstandard_exclude_directories = ('.*', 'CVS', '_darcs', './build',\n                                './dist', 'EGG-INFO', '*.egg-info')\n\n\ndef find_package_data(where='.', package='',\n                      exclude=standard_exclude,\n                      exclude_directories=standard_exclude_directories,\n                      only_in_packages=True,\n                      show_ignored=False):\n    \"\"\"\n    Return a dictionary suitable for use in ``package_data``\n    in a distutils ``setup.py`` file.\n\n    The dictionary looks like::\n\n        {'package': [files]}\n\n    Where ``files`` is a list of all the files in that package that\n    don't match anything in ``exclude``.\n\n    If ``only_in_packages`` is true, then top-level directories that\n    are not packages won't be included (but directories under packages\n    will).\n\n    Directories matching any pattern in ``exclude_directories`` will\n    be ignored; by default directories with leading ``.``, ``CVS``,\n    and ``_darcs`` will be ignored.\n\n    If ``show_ignored`` is true, then all the files that aren't\n    included in package data are shown on stderr (for debugging\n    purposes).\n\n    Note patterns use wildcards, or can be exact paths (including\n    leading ``./``), and all searching is case-insensitive.\n\n    This function is by Ian Bicking.\n    \"\"\"\n\n    out = {}\n    stack = [(convert_path(where), '', package, only_in_packages)]\n    while stack:\n        where, prefix, package, only_in_packages = stack.pop(0)\n        for name in os.listdir(where):\n            fn = os.path.join(where, name)\n            if os.path.isdir(fn):\n                bad_name = False\n                for pattern in exclude_directories:\n                    if (fnmatchcase(name, pattern)\n                        or fn.lower() == pattern.lower()):\n                        bad_name = True\n                        if show_ignored:\n                            sys.stderr.write(\n                                \"Directory %s ignored by pattern %s\\n\"\n                                % (fn, pattern))\n                        break\n                if bad_name:\n                    continue\n                if os.path.isfile(os.path.join(fn, '__init__.py')):\n                    if not package:\n                        new_package = name\n                    else:\n                        new_package = package + '.' + name\n                    stack.append((fn, '', new_package, False))\n                else:\n                    stack.append(\n                        (fn, prefix + name + '/', package, only_in_packages)\n                    )\n            elif package or not only_in_packages:\n                # is a file\n                bad_name = False\n                for pattern in exclude:\n                    if (fnmatchcase(name, pattern)\n                        or fn.lower() == pattern.lower()):\n                        bad_name = True\n                        if show_ignored:\n                            sys.stderr.write(\n                                \"File %s ignored by pattern %s\\n\"\n                                % (fn, pattern))\n                        break\n                if bad_name:\n                    continue\n                out.setdefault(package, []).append(prefix + name)\n    return out\n\n\n##############################################################################\n\n# Todos los módulos y submódulos a instalar (module, module.submodule, module.submodule2...)\npackages = find_packages(__dir__)\n# Prevent include symbolic links\nfor package in tuple(packages):\n    path = os.path.join(__dir__, package.replace('.', '/'))\n    if not os.path.exists(path):\n        continue\n    if not os.path.islink(path):\n        continue\n    packages.remove(package)\n\n# Otros archivos que no son Python y que son requeridos\npackage_data = {'': ROOT_INCLUDE}\n\n# Obtener la lista de módulos que se instalarán\nmodules = list(filter(lambda x: '.' not in x, packages))\n\nfor module in modules:\n    package_data.update(find_package_data(\n        module,\n        package=module,\n        only_in_packages=False,\n    ))\n\n# Descripción larga si existe un archivo README\ntry:\n    long_description = open(readme_path, 'rt').read()\nexcept IOError:\n    long_description = ''\n\n# Tomar por defecto la versión de un archivo VERSION. Si no, del módulo\nif os.path.exists(version_path):\n    package_version = open(version_path).read().replace('\\n', '')\nelse:\n    package_version = __import__(modules[0]).__version__\n\n# Si hay un directorio scripts, tomar todos sus archivos\nif os.path.exists(scripts_path):\n    scripts_dir_name = scripts_path.replace(__dir__, '', 1)\n    scripts_dir_name = scripts_dir_name[1:] if scripts_dir_name.startswith(os.sep) else scripts_dir_name\n    scripts = [os.path.join(scripts_dir_name, file) for file in os.listdir(scripts_path)]\nelse:\n    scripts = []\n\n# Eliminar archivos de ROOT_INCLUDE que no existen\nfor d in tuple(ROOT_INCLUDE):\n    if not os.path.exists(os.path.join(__dir__, d)):\n        ROOT_INCLUDE.remove(d)\n\n# Nombre del estado de desarrollo\nstatus_name = ['Planning', 'Pre-Alpha', 'Alpha', 'Beta',\n               'Production/Stable', 'Mature', 'Inactive'][STATUS_LEVEL - 1]\n\n# Añadir en los classifiers la plataforma\nplatforms_classifiers = {'linux': ('POSIX', 'Linux'), 'win': ('Microsoft', 'Windows'),\n                         'solaris': ('POSIX', 'SunOS/Solaris'), 'aix': ('POSIX', 'Linux'), 'unix': ('Unix',),\n                         'bsd': ('POSIX', 'BSD')}\nfor key, parts in platforms_classifiers.items():\n    if not key in PLATFORMS:\n        continue\n    CLASSIFIERS.append('Operating System :: {}'.format(' :: '.join(parts)))\n\n\n# Añadir la versión de Python a los Classifiers\ndef frange(x, y, jump):\n    while x < y:\n        yield x\n        x += jump\n\n\npython_versions = []\nfor version in PYTHON_VERSIONS:\n    if '-' in version:\n        version = version.split('-')\n        if len(version) != 2:\n            raise ValueError('Invalid Python version range: {}'.format('-'.join(version)))\n        version = list(map(float, version))\n        version[1] += 0.1  # Para que frange incluya la última versión\n        python_versions.extend(frange(version[0], version[1], 0.1))\n    elif isinstance(version, int) or version.isdigit():\n        python_versions.append(str(version))\n    else:\n        python_versions.append(float(version))\npython_versions = map(lambda x: x if isinstance(x, str) else '%.1f' % x, python_versions)\n# Eliminar versiones 0-2.3 y 2.8-2.9\nremove_python_versions = map(str, list(frange(0, 2.3, 0.1)) + list(frange(2.8, 3.0, 0.1)))\npython_versions = list(filter(lambda x: x not in remove_python_versions, python_versions))\nfor version in range(2, 4):\n    if not len(list(filter(lambda x: int(float(x)) != version, python_versions))):\n        # Sólo se encuentran versiones para la versión <version>\n        python_versions.append('%i :: Only' % version)\n        break\nCLASSIFIERS.extend(['Programming Language :: Python :: %s' % version for version in python_versions])\n\nCLASSIFIERS.extend([\n    'Natural Language :: {}'.format(NATURAL_LANGUAGE),\n    'Development Status :: {} - {}'.format(STATUS_LEVEL, status_name),\n])\n\n\ndef read_file(file):\n    with open(file, 'r') as f:\n        return f.read()\n\n\ninstall_requires = read_file(requirements_path)\n\n\nsetup(\n    name=PACKAGE_NAME,\n    version=package_version,\n\n    description=__doc__.strip(),\n    long_description=long_description,\n\n    author=AUTHOR,\n    author_email=EMAIL,\n\n    url=URL,\n\n    classifiers=CLASSIFIERS,\n\n    platforms=PLATFORMS,\n\n    provides=modules,\n    install_requires=install_requires,\n\n    packages=packages,\n    include_package_data=True,\n    # Scan the input for package information\n    # to grab any data files (text, images, etc.)\n    # associated with sub-packages.\n    package_data=package_data,\n\n    download_url=PACKAGE_DOWNLOAD_URL,\n    keywords=KEYWORDS,\n\n    entry_points={'console_scripts':\n                      ['gkeep = google_keep_tasks.management:cli']},\n\n    zip_safe=False,\n)\n"
  }
]