Hello community,

here is the log from the commit of package python-buku for openSUSE:Factory 
checked in at 2019-05-02 19:21:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-buku (Old)
 and      /work/SRC/openSUSE:Factory/.python-buku.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-buku"

Thu May  2 19:21:51 2019 rev:8 rq:700083 version:4.2.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-buku/python-buku.changes  2019-04-04 
15:28:31.202923751 +0200
+++ /work/SRC/openSUSE:Factory/.python-buku.new.5148/python-buku.changes        
2019-05-02 19:22:03.017873597 +0200
@@ -1,0 +2,23 @@
+Thu May  2 07:47:06 UTC 2019 - [email protected]
+
+- Update to 4.2.2:
+  * This is a minor release that fixes broken prompt due to PR #373.
+
+-------------------------------------------------------------------
+Thu May  2 06:32:10 UTC 2019 - [email protected]
+
+- Update to 4.2.1:
+  * This is a minor release with a single fix on top of v4.2 to
+    address a packaging problem.
+
+-------------------------------------------------------------------
+Tue Apr 30 05:48:26 UTC 2019 - [email protected]
+
+- Update to 4.2
+  * Disabled appending tags from page on update
+  * Improved Windows color support using colorama (optional dep)
+  * New format option to show only title and tag
+  * Python 3.4 is EOL, support discontinued
+  * Several fixes and code refactor
+
+-------------------------------------------------------------------

Old:
----
  buku-4.1.tar.gz

New:
----
  buku-4.2.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-buku.spec ++++++
--- /var/tmp/diff_new_pack.nsZCyL/_old  2019-05-02 19:22:04.509876694 +0200
+++ /var/tmp/diff_new_pack.nsZCyL/_new  2019-05-02 19:22:04.513876703 +0200
@@ -12,14 +12,14 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via https://bugs.opensuse.org/
+# Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-buku
-Version:        4.1
+Version:        4.2.2
 Release:        0
 Summary:        Command-line bookmark manager
 License:        GPL-3.0-or-later
@@ -44,6 +44,7 @@
 # /SECTION
 Requires:       python-base
 Requires:       python-beautifulsoup4 >= 4.4.1
+Requires:       python-colorama
 Requires:       python-cryptography >= 1.2.3
 Requires:       python-html5lib >= 1.0.1
 Requires:       python-requests >= 2.9.1

++++++ buku-4.1.tar.gz -> buku-4.2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/CHANGELOG new/buku-4.2.2/CHANGELOG
--- old/buku-4.1/CHANGELOG      2019-01-15 07:24:39.000000000 +0100
+++ new/buku-4.2.2/CHANGELOG    2019-05-02 08:47:59.000000000 +0200
@@ -1,3 +1,28 @@
+Buku v4.2.2
+2019-05-02
+
+- Fixes broken prompt due to PR #373
+
+-------------------------------------------------------------------------------
+
+Buku v4.2.1
+2019-04-30
+
+- A fix on top of v4.2 to address a packaging problem
+
+-------------------------------------------------------------------------------
+
+Buku v4.2
+2019-04-30
+
+- Disabled appending tags from page on update
+- Improved Windows color support using colorama (optional dep)
+- New format option to show only title and tag
+- Python 3.4 is EOL, support discontinued
+- Several fixes and code refactor
+
+-------------------------------------------------------------------------------
+
 Buku v4.1
 2019-01-15
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/PKG-INFO new/buku-4.2.2/PKG-INFO
--- old/buku-4.1/PKG-INFO       2019-01-16 00:47:36.000000000 +0100
+++ new/buku-4.2.2/PKG-INFO     2019-05-02 08:48:20.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: buku
-Version: 4.1
+Version: 4.2.2
 Summary: Bookmark manager like a text-based mini-web.
 Home-page: https://github.com/jarun/Buku
 Author: Arun Prakash Jana
@@ -20,9 +20,9 @@
         </p>
         
         <p align="center">
-        <a href="https://travis-ci.org/jarun/Buku";><img 
src="https://img.shields.io/travis/jarun/Buku.svg"; alt="Build Status" /></a>
+        <a href="https://repology.org/metapackage/buku";><img 
src="https://repology.org/badge/tiny-repos/buku.svg"; alt="Availability"></a>
+        <a href="https://circleci.com/gh/jarun/workflows/Buku";><img 
src="https://img.shields.io/circleci/project/github/jarun/Buku.svg"; alt="Build 
Status" /></a>
         <a href="http://buku.readthedocs.io/en/latest/?badge=latest";><img 
src="https://readthedocs.org/projects/buku/badge/?version=latest"; alt="Docs 
Status" /></a>
-        <a href="https://snyk.io/test/github/jarun/Buku";><img 
src="https://snyk.io/test/github/jarun/Buku/badge.svg"; /></a>
         <a href="https://github.com/jarun/buku/blob/master/LICENSE";><img 
src="https://img.shields.io/badge/license-GPLv3-yellow.svg?maxAge=2592000"; 
alt="License" /></a>
         </p>
         
@@ -38,16 +38,16 @@
         
         [bukuserver](https://github.com/jarun/Buku/tree/master/bukuserver) 
exposes a browsable front-end on a local web host server.
         
-        `buku` fetches the title, tags and description of a bookmarked url 
from the web and stores it. You can use your favourite editor to compose and 
update bookmarks. With multiple search options, including regex and a deep scan 
mode (particularly for URLs), it can find any bookmark instantly. Multiple 
search results can be opened in the browser at once. `buku` can look up the 
latest snapshot of a broken link on the Wayback Machine. There's an Easter egg 
to revisit random forgotten bookmarks too! *Buku* is too busy to track you: no 
hidden history, obsolete records, usage analytics or homing. For more details, 
please refer to the wiki page on [operational 
notes](https://github.com/jarun/Buku/wiki/Operational-notes).
+        `buku` can auto-import bookmarks from your browser(s) or fetch the 
title and description of a bookmarked url from the web. You can use your 
favourite editor to compose and update bookmarks. With multiple search options, 
including regex and a deep scan mode (particularly for URLs), it can find any 
bookmark instantly. `buku` can look up the latest snapshot of a broken link on 
the Wayback Machine. There's an Easter egg to revisit random forgotten 
bookmarks too! *Buku* is too busy to track you: no hidden history, obsolete 
records, usage analytics or homing.
         
-        To get started right away, jump to the [Quickstart](#quickstart) 
section. We have one of the best documentation around. You'll find handy 
examples in the man page too.
+        To get started right away, jump to the [Quickstart](#quickstart) 
section. We have one of the best documentation around. You'll find handy 
examples in the man page too. For more details, please refer to the wiki page 
on [operational notes](https://github.com/jarun/Buku/wiki/Operational-notes).
         
         There are several [projects based on `buku`](#related-projects), 
including a browser plug-in.
         
         *Love smart and efficient utilities? Explore [my 
repositories](https://github.com/jarun?tab=repositories). Buy me a cup of 
coffee if they help you.*
         
         <p align="center">
-        <a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-green.svg"; alt="Donate via 
PayPal!" /></a>
+        <a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-1eb0fc.svg"; alt="Donate via 
PayPal!" /></a>
         </p>
         
         ### Table of Contents
@@ -65,6 +65,7 @@
           - [Colors](#colors)
         - [Quickstart](#quickstart)
         - [Examples](#examples)
+        - [Automation](#automation)
         - [Troubleshooting](#troubleshooting)
           - [Editor integration](#editor-integration)
         - [Collaborators](#collaborators)
@@ -94,7 +95,7 @@
         
         | Feature | Dependency |
         | --- | --- |
-        | Scripting language | Python 3.4+ |
+        | Scripting language | Python 3.5+ |
         | HTTPS | certifi, urllib3 |
         | Encryption | cryptography |
         | HTML | beautifulsoup4, html5lib |
@@ -124,7 +125,6 @@
         - [Slackware](http://slackbuilds.org/repository/14.2/desktop/Buku/) 
(`slackpkg install buku`)
         - [Termux](https://pypi.python.org/pypi/buku/) (`pip3 install buku`)
         - 
[Ubuntu](https://packages.ubuntu.com/search?keywords=buku&searchon=names&exact=1)
 (`apt-get install buku`)
-        - [Ubuntu 
PPA](https://launchpad.net/~twodopeshaggy/+archive/ubuntu/jarun/) (`apt-get 
install buku`)
         - [Void 
Linux](https://github.com/voidlinux/void-packages/tree/master/srcpkgs/buku) 
(`xbps-install -S buku`)
         
         #### Release packages
@@ -175,10 +175,10 @@
                                    bookmark URL with comma-separated tags
               -u, --update [...]   update fields of an existing bookmark
                                    accepts indices and ranges
-                                   refresh title, desc, tags if no edit options
+                                   refresh title and desc if no edit options
                                    if no arguments:
                                    - update results when used with search
-                                   - otherwise refresh all titles, desc, tags
+                                   - otherwise refresh all titles and desc
               -w, --write [editor|index]
                                    open editor to edit a fresh bookmark
                                    edit last bookmark, if index=-1
@@ -239,9 +239,9 @@
                                    print all bookmarks, if no arguments
                                    -n shows the last n results (like tail)
               -f, --format N       limit fields in -p or JSON search output
-                                   N=1: URL, N=2: URL and tag, N=3: title,
-                                   N=4: URL, title and tag. To omit DB index,
-                                   use N0, e.g., 10, 20, 30, 40.
+                                   N=1: URL; N=2: URL, tag; N=3: title;
+                                   N=4: URL, title, tag; N=5: title, tag;
+                                   N0 (10, 20, 30, 40, 50) omits DB index
               -j, --json           JSON formatted output for -p and search
               --colors COLORS      set output colors in five-letter string
               --nc                 disable color output
@@ -299,7 +299,7 @@
         2. Create a sweeter shortcut with some convenience.
         
                alias b='buku --suggest'
-        3. Auto-import bookmarks from your browser(s).
+        3. Auto-import bookmarks from your browser(s). Please quit the 
relevant browsers beforehand to ensure the databases are not locked.
         
                b --ai
         4. Manually add a bookmark (for hands-on).
@@ -371,7 +371,7 @@
         
                 $ buku -u
                 $ buku -u --tacit (show only failures and exceptions)
-            This operation does not modify the indexes, URLs, tags or 
comments. Only title is refreshed if fetched title is non-empty.
+            This operation can update the title or description fields of 
non-immutable bookmarks by parsing the fetched page. Fields are updated only if 
the fetched fields are non-empty. Tags remain untouched.
         13. **Delete** bookmark at index 15012014:
         
                 $ buku -d 15012014
@@ -468,6 +468,10 @@
                 $ buku -h
                 $ man buku
         
+        ### Automation
+        
+        Interactive workflows can be automated using expect. Issue 
[#368](https://github.com/jarun/Buku/issues/368) has a working example on 
automating auto-import.
+        
         ### Troubleshooting
         
         #### Editor integration
@@ -521,13 +525,13 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
 Classifier: Topic :: Utilities
-Requires-Python: >=3.4
+Requires-Python: >=3.5
 Description-Content-Type: text/markdown
 Provides-Extra: packaging
-Provides-Extra: tests
 Provides-Extra: server
+Provides-Extra: tests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/README.md new/buku-4.2.2/README.md
--- old/buku-4.1/README.md      2019-01-15 07:24:39.000000000 +0100
+++ new/buku-4.2.2/README.md    2019-04-30 06:42:09.000000000 +0200
@@ -12,9 +12,9 @@
 </p>
 
 <p align="center">
-<a href="https://travis-ci.org/jarun/Buku";><img 
src="https://img.shields.io/travis/jarun/Buku.svg"; alt="Build Status" /></a>
+<a href="https://repology.org/metapackage/buku";><img 
src="https://repology.org/badge/tiny-repos/buku.svg"; alt="Availability"></a>
+<a href="https://circleci.com/gh/jarun/workflows/Buku";><img 
src="https://img.shields.io/circleci/project/github/jarun/Buku.svg"; alt="Build 
Status" /></a>
 <a href="http://buku.readthedocs.io/en/latest/?badge=latest";><img 
src="https://readthedocs.org/projects/buku/badge/?version=latest"; alt="Docs 
Status" /></a>
-<a href="https://snyk.io/test/github/jarun/Buku";><img 
src="https://snyk.io/test/github/jarun/Buku/badge.svg"; /></a>
 <a href="https://github.com/jarun/buku/blob/master/LICENSE";><img 
src="https://img.shields.io/badge/license-GPLv3-yellow.svg?maxAge=2592000"; 
alt="License" /></a>
 </p>
 
@@ -30,16 +30,16 @@
 
 [bukuserver](https://github.com/jarun/Buku/tree/master/bukuserver) exposes a 
browsable front-end on a local web host server.
 
-`buku` fetches the title, tags and description of a bookmarked url from the 
web and stores it. You can use your favourite editor to compose and update 
bookmarks. With multiple search options, including regex and a deep scan mode 
(particularly for URLs), it can find any bookmark instantly. Multiple search 
results can be opened in the browser at once. `buku` can look up the latest 
snapshot of a broken link on the Wayback Machine. There's an Easter egg to 
revisit random forgotten bookmarks too! *Buku* is too busy to track you: no 
hidden history, obsolete records, usage analytics or homing. For more details, 
please refer to the wiki page on [operational 
notes](https://github.com/jarun/Buku/wiki/Operational-notes).
+`buku` can auto-import bookmarks from your browser(s) or fetch the title and 
description of a bookmarked url from the web. You can use your favourite editor 
to compose and update bookmarks. With multiple search options, including regex 
and a deep scan mode (particularly for URLs), it can find any bookmark 
instantly. `buku` can look up the latest snapshot of a broken link on the 
Wayback Machine. There's an Easter egg to revisit random forgotten bookmarks 
too! *Buku* is too busy to track you: no hidden history, obsolete records, 
usage analytics or homing.
 
-To get started right away, jump to the [Quickstart](#quickstart) section. We 
have one of the best documentation around. You'll find handy examples in the 
man page too.
+To get started right away, jump to the [Quickstart](#quickstart) section. We 
have one of the best documentation around. You'll find handy examples in the 
man page too. For more details, please refer to the wiki page on [operational 
notes](https://github.com/jarun/Buku/wiki/Operational-notes).
 
 There are several [projects based on `buku`](#related-projects), including a 
browser plug-in.
 
 *Love smart and efficient utilities? Explore [my 
repositories](https://github.com/jarun?tab=repositories). Buy me a cup of 
coffee if they help you.*
 
 <p align="center">
-<a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-green.svg"; alt="Donate via 
PayPal!" /></a>
+<a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-1eb0fc.svg"; alt="Donate via 
PayPal!" /></a>
 </p>
 
 ### Table of Contents
@@ -57,6 +57,7 @@
   - [Colors](#colors)
 - [Quickstart](#quickstart)
 - [Examples](#examples)
+- [Automation](#automation)
 - [Troubleshooting](#troubleshooting)
   - [Editor integration](#editor-integration)
 - [Collaborators](#collaborators)
@@ -86,7 +87,7 @@
 
 | Feature | Dependency |
 | --- | --- |
-| Scripting language | Python 3.4+ |
+| Scripting language | Python 3.5+ |
 | HTTPS | certifi, urllib3 |
 | Encryption | cryptography |
 | HTML | beautifulsoup4, html5lib |
@@ -116,7 +117,6 @@
 - [Slackware](http://slackbuilds.org/repository/14.2/desktop/Buku/) (`slackpkg 
install buku`)
 - [Termux](https://pypi.python.org/pypi/buku/) (`pip3 install buku`)
 - 
[Ubuntu](https://packages.ubuntu.com/search?keywords=buku&searchon=names&exact=1)
 (`apt-get install buku`)
-- [Ubuntu PPA](https://launchpad.net/~twodopeshaggy/+archive/ubuntu/jarun/) 
(`apt-get install buku`)
 - [Void 
Linux](https://github.com/voidlinux/void-packages/tree/master/srcpkgs/buku) 
(`xbps-install -S buku`)
 
 #### Release packages
@@ -167,10 +167,10 @@
                            bookmark URL with comma-separated tags
       -u, --update [...]   update fields of an existing bookmark
                            accepts indices and ranges
-                           refresh title, desc, tags if no edit options
+                           refresh title and desc if no edit options
                            if no arguments:
                            - update results when used with search
-                           - otherwise refresh all titles, desc, tags
+                           - otherwise refresh all titles and desc
       -w, --write [editor|index]
                            open editor to edit a fresh bookmark
                            edit last bookmark, if index=-1
@@ -231,9 +231,9 @@
                            print all bookmarks, if no arguments
                            -n shows the last n results (like tail)
       -f, --format N       limit fields in -p or JSON search output
-                           N=1: URL, N=2: URL and tag, N=3: title,
-                           N=4: URL, title and tag. To omit DB index,
-                           use N0, e.g., 10, 20, 30, 40.
+                           N=1: URL; N=2: URL, tag; N=3: title;
+                           N=4: URL, title, tag; N=5: title, tag;
+                           N0 (10, 20, 30, 40, 50) omits DB index
       -j, --json           JSON formatted output for -p and search
       --colors COLORS      set output colors in five-letter string
       --nc                 disable color output
@@ -291,7 +291,7 @@
 2. Create a sweeter shortcut with some convenience.
 
        alias b='buku --suggest'
-3. Auto-import bookmarks from your browser(s).
+3. Auto-import bookmarks from your browser(s). Please quit the relevant 
browsers beforehand to ensure the databases are not locked.
 
        b --ai
 4. Manually add a bookmark (for hands-on).
@@ -363,7 +363,7 @@
 
         $ buku -u
         $ buku -u --tacit (show only failures and exceptions)
-    This operation does not modify the indexes, URLs, tags or comments. Only 
title is refreshed if fetched title is non-empty.
+    This operation can update the title or description fields of non-immutable 
bookmarks by parsing the fetched page. Fields are updated only if the fetched 
fields are non-empty. Tags remain untouched.
 13. **Delete** bookmark at index 15012014:
 
         $ buku -d 15012014
@@ -460,6 +460,10 @@
         $ buku -h
         $ man buku
 
+### Automation
+
+Interactive workflows can be automated using expect. Issue 
[#368](https://github.com/jarun/Buku/issues/368) has a working example on 
automating auto-import.
+
 ### Troubleshooting
 
 #### Editor integration
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/buku.1 new/buku-4.2.2/buku.1
--- old/buku-4.1/buku.1 2019-01-15 07:24:39.000000000 +0100
+++ new/buku-4.2.2/buku.1       2019-05-02 08:47:59.000000000 +0200
@@ -1,4 +1,4 @@
-.TH "BUKU" "1" "15 Jan 2019" "Version 4.1" "User Commands"
+.TH "BUKU" "1" "02 May 2019" "Version 4.2.2" "User Commands"
 .SH NAME
 buku \- Bookmark manager like a text-based mini-web
 .SH SYNOPSIS
@@ -51,7 +51,7 @@
 .IP 6. 4
 \fBUpdate\fR operation:
   - If --title, --tag or --comment is passed without argument, clear the 
corresponding field from DB.
-  - If --url is passed (and --title is omitted), update the title from web 
using the URL. Description is updated (if --comment is omitted) and tags are 
appended to (if --tag is omitted).
+  - If --url is passed (and --title is omitted), update the title from web 
using the URL. Description is updated (if --comment is omitted). Tags remain 
untouched.
   - If indices are passed without any other options (--url, --title, --tag, 
--comment and --immutable), read the URLs from DB and update titles, 
description and append tags from web. Bookmarks marked immutable are skipped.
   - Can update bookmarks matching a search, when combined with any of the 
search options and no arguments to update are passed.
 .PP
@@ -101,7 +101,7 @@
 along with comma-separated tags. A tag can have multiple words.
 .TP
 .BI \-u " " \--update " [...]"
-Update fields of the bookmarks at specified indices in DB. If no arguments are 
specified, all titles and descriptions are refreshed from the web. Tags are 
appended. Works with update modifiers for the fields url, title, tag and 
comment. If only indices are passed without any edit options, titles and 
descriptions are fetched and updated (if not empty). Accepts hyphenated ranges 
and space-separated indices. Updates search results when used with search 
options, if no arguments.
+Update fields of the bookmarks at specified indices in DB. If no arguments are 
specified, all titles and descriptions are refreshed from the web. Tags remain 
untouched. Works with update modifiers for the fields url, title, tag and 
comment. If only indices are passed without any edit options, titles and 
descriptions are fetched and updated (if not empty). Accepts hyphenated ranges 
and space-separated indices. Updates search results when used with search 
options, if no arguments.
 .TP
 .BI \-w " " \--write " [editor|index]"
 Edit a bookmark in
@@ -223,9 +223,12 @@
 = 3, show only title.
 .br
 .I N
-= 4, show URL, title and tags in a single line
+= 4, show URL, title and tags in a single line.
 .br
-To omit DB index from printed results, use N0, e.g., 10, 20, 30, 40.
+.I N
+= 5, show title and tags in a single line.
+.br
+To omit DB index from printed results, use N0, e.g., 10, 20, 30, 40, 50.
 .TP
 .BI \-j " " \--json
 Output data formatted as JSON, works with --print output and search results.
@@ -576,7 +579,7 @@
 .EE
 .PP
 .IP "" 4
-This operation does not modify the indexes, URLs, tags or comments. Only title 
is refreshed if fetched title is non-empty.
+This operation can update the title or description fields of non-immutable 
bookmarks by parsing the fetched page. Fields are updated only if the fetched 
fields are non-empty. Tags remain untouched.
 .PP
 .IP 13. 4
 \fBDelete\fR bookmark at index 15012014:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/buku.egg-info/PKG-INFO 
new/buku-4.2.2/buku.egg-info/PKG-INFO
--- old/buku-4.1/buku.egg-info/PKG-INFO 2019-01-16 00:47:35.000000000 +0100
+++ new/buku-4.2.2/buku.egg-info/PKG-INFO       2019-05-02 08:48:19.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: buku
-Version: 4.1
+Version: 4.2.2
 Summary: Bookmark manager like a text-based mini-web.
 Home-page: https://github.com/jarun/Buku
 Author: Arun Prakash Jana
@@ -20,9 +20,9 @@
         </p>
         
         <p align="center">
-        <a href="https://travis-ci.org/jarun/Buku";><img 
src="https://img.shields.io/travis/jarun/Buku.svg"; alt="Build Status" /></a>
+        <a href="https://repology.org/metapackage/buku";><img 
src="https://repology.org/badge/tiny-repos/buku.svg"; alt="Availability"></a>
+        <a href="https://circleci.com/gh/jarun/workflows/Buku";><img 
src="https://img.shields.io/circleci/project/github/jarun/Buku.svg"; alt="Build 
Status" /></a>
         <a href="http://buku.readthedocs.io/en/latest/?badge=latest";><img 
src="https://readthedocs.org/projects/buku/badge/?version=latest"; alt="Docs 
Status" /></a>
-        <a href="https://snyk.io/test/github/jarun/Buku";><img 
src="https://snyk.io/test/github/jarun/Buku/badge.svg"; /></a>
         <a href="https://github.com/jarun/buku/blob/master/LICENSE";><img 
src="https://img.shields.io/badge/license-GPLv3-yellow.svg?maxAge=2592000"; 
alt="License" /></a>
         </p>
         
@@ -38,16 +38,16 @@
         
         [bukuserver](https://github.com/jarun/Buku/tree/master/bukuserver) 
exposes a browsable front-end on a local web host server.
         
-        `buku` fetches the title, tags and description of a bookmarked url 
from the web and stores it. You can use your favourite editor to compose and 
update bookmarks. With multiple search options, including regex and a deep scan 
mode (particularly for URLs), it can find any bookmark instantly. Multiple 
search results can be opened in the browser at once. `buku` can look up the 
latest snapshot of a broken link on the Wayback Machine. There's an Easter egg 
to revisit random forgotten bookmarks too! *Buku* is too busy to track you: no 
hidden history, obsolete records, usage analytics or homing. For more details, 
please refer to the wiki page on [operational 
notes](https://github.com/jarun/Buku/wiki/Operational-notes).
+        `buku` can auto-import bookmarks from your browser(s) or fetch the 
title and description of a bookmarked url from the web. You can use your 
favourite editor to compose and update bookmarks. With multiple search options, 
including regex and a deep scan mode (particularly for URLs), it can find any 
bookmark instantly. `buku` can look up the latest snapshot of a broken link on 
the Wayback Machine. There's an Easter egg to revisit random forgotten 
bookmarks too! *Buku* is too busy to track you: no hidden history, obsolete 
records, usage analytics or homing.
         
-        To get started right away, jump to the [Quickstart](#quickstart) 
section. We have one of the best documentation around. You'll find handy 
examples in the man page too.
+        To get started right away, jump to the [Quickstart](#quickstart) 
section. We have one of the best documentation around. You'll find handy 
examples in the man page too. For more details, please refer to the wiki page 
on [operational notes](https://github.com/jarun/Buku/wiki/Operational-notes).
         
         There are several [projects based on `buku`](#related-projects), 
including a browser plug-in.
         
         *Love smart and efficient utilities? Explore [my 
repositories](https://github.com/jarun?tab=repositories). Buy me a cup of 
coffee if they help you.*
         
         <p align="center">
-        <a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-green.svg"; alt="Donate via 
PayPal!" /></a>
+        <a 
href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RMLTQ76JSXJ4Q";><img
 src="https://img.shields.io/badge/PayPal-donate-1eb0fc.svg"; alt="Donate via 
PayPal!" /></a>
         </p>
         
         ### Table of Contents
@@ -65,6 +65,7 @@
           - [Colors](#colors)
         - [Quickstart](#quickstart)
         - [Examples](#examples)
+        - [Automation](#automation)
         - [Troubleshooting](#troubleshooting)
           - [Editor integration](#editor-integration)
         - [Collaborators](#collaborators)
@@ -94,7 +95,7 @@
         
         | Feature | Dependency |
         | --- | --- |
-        | Scripting language | Python 3.4+ |
+        | Scripting language | Python 3.5+ |
         | HTTPS | certifi, urllib3 |
         | Encryption | cryptography |
         | HTML | beautifulsoup4, html5lib |
@@ -124,7 +125,6 @@
         - [Slackware](http://slackbuilds.org/repository/14.2/desktop/Buku/) 
(`slackpkg install buku`)
         - [Termux](https://pypi.python.org/pypi/buku/) (`pip3 install buku`)
         - 
[Ubuntu](https://packages.ubuntu.com/search?keywords=buku&searchon=names&exact=1)
 (`apt-get install buku`)
-        - [Ubuntu 
PPA](https://launchpad.net/~twodopeshaggy/+archive/ubuntu/jarun/) (`apt-get 
install buku`)
         - [Void 
Linux](https://github.com/voidlinux/void-packages/tree/master/srcpkgs/buku) 
(`xbps-install -S buku`)
         
         #### Release packages
@@ -175,10 +175,10 @@
                                    bookmark URL with comma-separated tags
               -u, --update [...]   update fields of an existing bookmark
                                    accepts indices and ranges
-                                   refresh title, desc, tags if no edit options
+                                   refresh title and desc if no edit options
                                    if no arguments:
                                    - update results when used with search
-                                   - otherwise refresh all titles, desc, tags
+                                   - otherwise refresh all titles and desc
               -w, --write [editor|index]
                                    open editor to edit a fresh bookmark
                                    edit last bookmark, if index=-1
@@ -239,9 +239,9 @@
                                    print all bookmarks, if no arguments
                                    -n shows the last n results (like tail)
               -f, --format N       limit fields in -p or JSON search output
-                                   N=1: URL, N=2: URL and tag, N=3: title,
-                                   N=4: URL, title and tag. To omit DB index,
-                                   use N0, e.g., 10, 20, 30, 40.
+                                   N=1: URL; N=2: URL, tag; N=3: title;
+                                   N=4: URL, title, tag; N=5: title, tag;
+                                   N0 (10, 20, 30, 40, 50) omits DB index
               -j, --json           JSON formatted output for -p and search
               --colors COLORS      set output colors in five-letter string
               --nc                 disable color output
@@ -299,7 +299,7 @@
         2. Create a sweeter shortcut with some convenience.
         
                alias b='buku --suggest'
-        3. Auto-import bookmarks from your browser(s).
+        3. Auto-import bookmarks from your browser(s). Please quit the 
relevant browsers beforehand to ensure the databases are not locked.
         
                b --ai
         4. Manually add a bookmark (for hands-on).
@@ -371,7 +371,7 @@
         
                 $ buku -u
                 $ buku -u --tacit (show only failures and exceptions)
-            This operation does not modify the indexes, URLs, tags or 
comments. Only title is refreshed if fetched title is non-empty.
+            This operation can update the title or description fields of 
non-immutable bookmarks by parsing the fetched page. Fields are updated only if 
the fetched fields are non-empty. Tags remain untouched.
         13. **Delete** bookmark at index 15012014:
         
                 $ buku -d 15012014
@@ -468,6 +468,10 @@
                 $ buku -h
                 $ man buku
         
+        ### Automation
+        
+        Interactive workflows can be automated using expect. Issue 
[#368](https://github.com/jarun/Buku/issues/368) has a working example on 
automating auto-import.
+        
         ### Troubleshooting
         
         #### Editor integration
@@ -521,13 +525,13 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
 Classifier: Topic :: Utilities
-Requires-Python: >=3.4
+Requires-Python: >=3.5
 Description-Content-Type: text/markdown
 Provides-Extra: packaging
-Provides-Extra: tests
 Provides-Extra: server
+Provides-Extra: tests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/buku.egg-info/requires.txt 
new/buku-4.2.2/buku.egg-info/requires.txt
--- old/buku-4.1/buku.egg-info/requires.txt     2019-01-16 00:47:35.000000000 
+0100
+++ new/buku-4.2.2/buku.egg-info/requires.txt   2019-05-02 08:48:19.000000000 
+0200
@@ -24,9 +24,11 @@
 beautifulsoup4>=4.6.0
 flake8>=3.4.1
 hypothesis>=3.7.0
+mypy-extensions==0.4.1
 py>=1.5.0
 pylint>=1.7.2
 pytest-cov
 pytest>=3.4.2
 PyYAML>=4.2b1
+setuptools>=41.0.1
 vcrpy>=1.13.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/buku.py new/buku-4.2.2/buku.py
--- old/buku-4.1/buku.py        2019-01-16 00:47:34.000000000 +0100
+++ new/buku-4.2.2/buku.py      2019-05-02 08:48:18.000000000 +0200
@@ -34,6 +34,7 @@
 import sys
 import threading
 import time
+from typing import Any, Dict, List, Optional, Tuple
 import webbrowser
 try:
     import readline
@@ -45,8 +46,12 @@
 import urllib3
 from urllib3.exceptions import LocationParseError
 from urllib3.util import parse_url, make_headers
+try:
+    from mypy_extensions import TypedDict
+except ImportError:
+    TypedDict = None  # type: ignore
 
-__version__ = '4.1'
+__version__ = '4.2.2'
 __author__ = 'Arun Prakash Jana <[email protected]>'
 __license__ = 'GPLv3'
 
@@ -328,6 +333,9 @@
             sys.exit(1)
 
 
+BookmarkVar = Tuple[int, str, str, str, str, int]
+
+
 class BukuDb:
     """Abstracts all database operations.
 
@@ -343,7 +351,9 @@
         Sets the verbosity of the APIs. Default is False.
     """
 
-    def __init__(self, json=False, field_filter=0, chatty=False, dbfile=None, 
colorize=True):
+    def __init__(
+            self, json: Optional[bool] = False, field_filter: Optional[int] = 
0, chatty: Optional[bool] = False,
+            dbfile: Optional[str] = None, colorize: Optional[bool] = True) -> 
None:
         """Database initialization API.
 
         Parameters
@@ -394,7 +404,7 @@
         return os.path.join(data_home, 'buku')
 
     @staticmethod
-    def initdb(dbfile=None, chatty=False):
+    def initdb(dbfile: Optional[str] = None, chatty: Optional[bool] = False) 
-> Tuple[sqlite3.Connection, sqlite3.Cursor]:
         """Initialize the database connection.
 
         Create DB file and/or bookmarks table if they don't exist.
@@ -515,7 +525,7 @@
         resultset = self.cur.fetchall()
         return resultset[0][0] if resultset else -1
 
-    def get_max_id(self):
+    def get_max_id(self) -> int:
         """Fetch the ID of the last record.
 
         Returns
@@ -530,13 +540,13 @@
 
     def add_rec(
             self,
-            url,
-            title_in=None,
-            tags_in=None,
-            desc=None,
-            immutable=0,
-            delay_commit=False,
-            fetch=True):
+            url: str,
+            title_in: Optional[str] = None,
+            tags_in: Optional[str] = None,
+            desc: Optional[str] = None,
+            immutable: Optional[int] = 0,
+            delay_commit: Optional[bool] = False,
+            fetch: Optional[bool] = True) -> int:
         """Add a new bookmark.
 
         Parameters
@@ -589,15 +599,13 @@
                 LOGDBG('Title: [%s]', ptitle)
         else:
             ptitle = pdesc = ptags = ''
+            LOGDBG('ptags: [%s]', ptags)
 
         if title_in is not None:
             ptitle = title_in
 
         # Fix up tags, if broken
-        if tags_in and tags_in != DELIM:
-            tags_in = delim_wrap(tags_in)
-        else:
-            tags_in = delim_wrap(parse_tags([ptags]))
+        tags_in = delim_wrap(tags_in)
 
         # Process description
         if desc is None:
@@ -866,9 +874,6 @@
                 query += ' desc = ?,'
                 arguments += (pdesc,)
                 to_update = True
-
-            if not tags_in and ptags:
-                self.append_tag_at_index(index, delim_wrap(ptags))
         elif not to_update and not tag_modified:
             ret = self.refreshdb(index, threads)
             if ret and index and self.chatty:
@@ -1015,7 +1020,7 @@
                 to_update = False
 
                 if not title or title == '':
-                    print(blank_url_str % row[0])
+                    LOGERR(blank_url_str, row[0])
                 else:
                     query += ' metadata = ?,'
                     arguments += (title,)
@@ -1035,7 +1040,6 @@
                 LOGDBG('refreshdb query: "%s", args: %s', query, arguments)
 
                 self.cur.execute(query, arguments)
-                self.append_tag_at_index(row[0], delim_wrap(tags), 
delay_commit=True)
 
                 # Save after fetching 32 titles per thread
                 if count & 0b11111 == 0:
@@ -1994,11 +1998,11 @@
                 # If range starts from 0 throw an error
                 if low <= 0:
                     raise IndexError
-                else:
-                    qry = 'SELECT URL from bookmarks where id BETWEEN ? AND ?'
-                    for row in self.cur.execute(qry, (low, high)):
-                        browse(row[0])
-                    return True
+
+                qry = 'SELECT URL from bookmarks where id BETWEEN ? AND ?'
+                for row in self.cur.execute(qry, (low, high)):
+                    browse(row[0])
+                return True
             except IndexError:
                 LOGERR('Index out of range')
                 return False
@@ -2031,7 +2035,7 @@
 
         return False
 
-    def exportdb(self, filepath, resultset=None):
+    def exportdb(self, filepath: str, resultset: Optional[List[BookmarkVar]] = 
None) -> bool:
         """Export DB bookmarks to file.
         Exports full DB, if resultset is None
 
@@ -2059,7 +2063,6 @@
         """
 
         count = 0
-        timestamp = str(int(time.time()))
 
         if not resultset:
             resultset = self.get_rec_all()
@@ -2080,12 +2083,9 @@
             qry = 'INSERT INTO bookmarks(URL, metadata, tags, desc, flags) 
VALUES (?, ?, ?, ?, ?)'
             for row in resultset:
                 outdb.cur.execute(qry, (row[1], row[2], row[3], row[4], 
row[5]))
+                count += 1
             outdb.conn.commit()
             outdb.close()
-
-            count = self.get_max_id()
-            if count == -1:
-                count = 0
             print('%s exported' % count)
             return True
 
@@ -2095,48 +2095,19 @@
             LOGERR(e)
             return False
 
+        res = {}  # type: Dict
         if filepath.endswith('.md'):
-            for row in resultset:
-                if row[2] == '':
-                    out = '- [Untitled](' + row[1] + ')\n'
-                else:
-                    out = '- [' + row[2] + '](' + row[1] + ')\n'
-                outfp.write(out)
-                count += 1
-
+            res = convert_bookmark_set(resultset, 'markdown')
+            count += res['count']
+            outfp.write(res['data'])
         elif filepath.endswith('.org'):
-            for row in resultset:
-                if row[2] == '':
-                    out = '* [[{}][Untitled]]\n'.format(row[1])
-                else:
-                    out = '* [[{}][{}]]\n'.format(row[1], row[2])
-                outfp.write(out)
-                count += 1
+            res = convert_bookmark_set(resultset, 'org')
+            count += res['count']
+            outfp.write(res['data'])
         else:
-            outfp.write('<!DOCTYPE NETSCAPE-Bookmark-file-1>\n\n'
-                        '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; 
charset=UTF-8">\n'
-                        '<TITLE>Bookmarks</TITLE>\n'
-                        '<H1>Bookmarks</H1>\n\n'
-                        '<DL><p>\n'
-                        '    <DT><H3 ADD_DATE="%s" LAST_MODIFIED="%s" '
-                        'PERSONAL_TOOLBAR_FOLDER="true">Buku bookmarks</H3>\n'
-                        '    <DL><p>\n'
-                        % (timestamp, timestamp))
-
-            for row in resultset:
-                out = ('        <DT><A HREF="%s" ADD_DATE="%s" 
LAST_MODIFIED="%s"'
-                       % (row[1], timestamp, timestamp))
-                if row[3] != DELIM:
-                    out += ' TAGS="' + row[3][1:-1] + '"'
-                out += '>' + row[2] + '</A>\n'
-                if row[4] != '':
-                    out += '        <DD>' + row[4] + '\n'
-
-                outfp.write(out)
-                count += 1
-
-            outfp.write('    </DL><p>\n</DL><p>')
-
+            res = convert_bookmark_set(resultset, 'html')
+            count += res['count']
+            outfp.write(res['data'])
         outfp.close()
         print('%s exported' % count)
         return True
@@ -2226,11 +2197,7 @@
         """
 
         # Connect to input DB
-        if sys.version_info >= (3, 4, 4):
-            # Python 3.4.4 and above
-            conn = sqlite3.connect('file:%s?mode=ro' % path, uri=True)
-        else:
-            conn = sqlite3.connect(path)
+        conn = sqlite3.connect('file:%s?mode=ro' % path, uri=True)
 
         cur = conn.cursor()
         res = cur.execute('SELECT DISTINCT fk, parent, title FROM 
moz_bookmarks WHERE type=1')
@@ -2483,11 +2450,7 @@
 
         try:
             # Connect to input DB
-            if sys.version_info >= (3, 4, 4):
-                # Python 3.4.4 and above
-                indb_conn = sqlite3.connect('file:%s?mode=ro' % path, uri=True)
-            else:
-                indb_conn = sqlite3.connect(path)
+            indb_conn = sqlite3.connect('file:%s?mode=ro' % path, uri=True)
 
             indb_cur = indb_conn.cursor()
             indb_cur.execute('SELECT * FROM bookmarks')
@@ -2553,18 +2516,19 @@
         if MYPROXY is None:
             gen_headers()
 
+        ca_certs = os.getenv('BUKU_CA_CERTS', default=certifi.where())
         if MYPROXY:
             manager = urllib3.ProxyManager(
                 MYPROXY,
                 num_pools=1,
                 headers=MYHEADERS,
                 cert_reqs='CERT_REQUIRED',
-                ca_certs=certifi.where())
+                ca_certs=ca_certs)
         else:
             manager = urllib3.PoolManager(num_pools=1,
                                           headers={'User-Agent': USER_AGENT},
                                           cert_reqs='CERT_REQUIRED',
-                                          ca_certs=certifi.where())
+                                          ca_certs=ca_certs)
 
         try:
             r = manager.request(
@@ -2794,6 +2758,70 @@
 # Helper functions
 # ----------------
 
+
+ConverterResult = TypedDict('ConverterResult', {'data': str, 'count': int}) if 
TypedDict else Dict[str, Any]
+
+
+def convert_bookmark_set(
+        bookmark_set: List[BookmarkVar],
+        export_type: str) -> ConverterResult:  # type: ignore
+    """Convert list of bookmark set into multiple data format.
+
+    Parameters
+    ----------
+        bookmark_set: bookmark set
+        export type: one of supported type: markdown, html, org
+
+    Returns
+    -------
+        converted data and count of converted bookmark set
+    """
+    assert export_type in ['markdown', 'html', 'org']
+    #  compatibility
+    resultset = bookmark_set
+
+    count = 0
+    out = ''
+    if export_type == 'markdown':
+        for row in resultset:
+            if not row[2]:
+                out += '- [Untitled](' + row[1] + ')\n'
+            else:
+                out += '- [' + row[2] + '](' + row[1] + ')\n'
+            count += 1
+    elif export_type == 'org':
+        for row in resultset:
+            if not row[2]:
+                out += '* [[{}][Untitled]]\n'.format(row[1])
+            else:
+                out += '* [[{}][{}]]\n'.format(row[1], row[2])
+            count += 1
+    elif export_type == 'html':
+        timestamp = str(int(time.time()))
+        out = (
+            '<!DOCTYPE NETSCAPE-Bookmark-file-1>\n\n'
+            '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; 
charset=UTF-8">\n'
+            '<TITLE>Bookmarks</TITLE>\n'
+            '<H1>Bookmarks</H1>\n\n'
+            '<DL><p>\n'
+            '    <DT><H3 ADD_DATE="{0}" LAST_MODIFIED="{0}" '
+            'PERSONAL_TOOLBAR_FOLDER="true">Buku bookmarks</H3>\n'
+            '    <DL><p>\n'.format(timestamp))
+
+        for row in resultset:
+            out += '        <DT><A HREF="%s" ADD_DATE="%s" LAST_MODIFIED="%s"' 
% (row[1], timestamp, timestamp)
+            if row[3] != DELIM:
+                out += ' TAGS="' + row[3][1:-1] + '"'
+            out += '>{}</A>\n'.format(row[2] if row[2] else '')
+            if row[4] != '':
+                out += '        <DD>' + row[4] + '\n'
+            count += 1
+
+        out += '    </DL><p>\n</DL><p>'
+
+    return {'data': out, 'count': count}
+
+
 def get_firefox_profile_name(path):
     """List folder and detect default Firefox profile name.
 
@@ -3144,14 +3172,14 @@
     # Get the netloc token
     try:
         netloc = parse_url(url).netloc
+        if not netloc:
+            # Try of prepend '//' and get netloc
+            netloc = parse_url('//' + url).netloc
+            if not netloc:
+                return True
     except LocationParseError as e:
         LOGERR('%s, URL: %s', e, url)
         return True
-    if not netloc:
-        # Try of prepend '//' and get netloc
-        netloc = parse_url('//' + url).netloc
-        if not netloc:
-            return True
 
     LOGDBG('netloc: %s', netloc)
 
@@ -3398,17 +3426,17 @@
     ProxyManager or PoolManager
         ProxyManager if https_proxy is defined, PoolManager otherwise.
     """
-
+    ca_certs = os.getenv('BUKU_CA_CERTS', default=certifi.where())
     if MYPROXY:
         return urllib3.ProxyManager(MYPROXY, num_pools=1, headers=MYHEADERS, 
timeout=15,
-                                    cert_reqs='CERT_REQUIRED', 
ca_certs=certifi.where())
+                                    cert_reqs='CERT_REQUIRED', 
ca_certs=ca_certs)
 
     return urllib3.PoolManager(
         num_pools=1,
         headers=MYHEADERS,
         timeout=15,
         cert_reqs='CERT_REQUIRED',
-        ca_certs=certifi.where())
+        ca_certs=ca_certs)
 
 
 def network_handler(url, http_head=False):
@@ -4008,6 +4036,9 @@
         elif field_filter == 4:
             for row in records:
                 print('%s\t%s\t%s\t%s' % (row[0], row[1], row[2], 
row[3][1:-1]))
+        elif field_filter == 5:
+            for row in records:
+                print('%s\t%s\t%s' % (row[0], row[2], row[3][1:-1]))
         elif field_filter == 10:
             for row in records:
                 print(row[1])
@@ -4020,6 +4051,9 @@
         elif field_filter == 40:
             for row in records:
                 print('%s\t%s\t%s' % (row[1], row[2], row[3][1:-1]))
+        elif field_filter == 50:
+            for row in records:
+                print('%s\t%s' % (row[2], row[3][1:-1]))
     except BrokenPipeError:
         sys.stdout = os.fdopen(1)
         sys.exit(1)
@@ -4224,19 +4258,20 @@
     if MYPROXY is None:
         gen_headers()
 
+    ca_certs = os.getenv('BUKU_CA_CERTS', default=certifi.where())
     if MYPROXY:
         manager = urllib3.ProxyManager(
             MYPROXY,
             num_pools=1,
             headers=MYHEADERS,
             cert_reqs='CERT_REQUIRED',
-            ca_certs=certifi.where()
+            ca_certs=ca_certs
         )
     else:
         manager = urllib3.PoolManager(num_pools=1,
                                       headers={'User-Agent': USER_AGENT},
                                       cert_reqs='CERT_REQUIRED',
-                                      ca_certs=certifi.where())
+                                      ca_certs=ca_certs)
 
     try:
         r = manager.request(
@@ -4683,10 +4718,10 @@
                          bookmark URL with comma-separated tags
     -u, --update [...]   update fields of an existing bookmark
                          accepts indices and ranges
-                         refresh title, desc, tags if no edit options
+                         refresh title and desc if no edit options
                          if no arguments:
                          - update results when used with search
-                         - otherwise refresh all titles, desc, tags
+                         - otherwise refresh all titles and desc
     -w, --write [editor|index]
                          open editor to edit a fresh bookmark
                          edit last bookmark, if index=-1
@@ -4790,9 +4825,9 @@
                          print all bookmarks, if no arguments
                          -n shows the last n results (like tail)
     -f, --format N       limit fields in -p or JSON search output
-                         N=1: URL, N=2: URL and tag, N=3: title,
-                         N=4: URL, title and tag. To omit DB index,
-                         use N0, e.g., 10, 20, 30, 40.
+                         N=1: URL; N=2: URL, tag; N=3: title;
+                         N=4: URL, title, tag; N=5: title, tag;
+                         N0 (10, 20, 30, 40, 50) omits DB index
     -j, --json           JSON formatted output for -p and search
     --colors COLORS      set output colors in five-letter string
     --nc                 disable color output
@@ -4817,7 +4852,7 @@
     addarg('-e', '--export', nargs=1, help=hide)
     addarg('-i', '--import', nargs=1, dest='importfile', help=hide)
     addarg('-p', '--print', nargs='*', help=hide)
-    addarg('-f', '--format', type=int, default=0, choices={1, 2, 3, 4, 10, 20, 
30, 40}, help=hide)
+    addarg('-f', '--format', type=int, default=0, choices={1, 2, 3, 4, 5, 10, 
20, 30, 40, 50}, help=hide)
     addarg('-j', '--json', action='store_true', help=hide)
     addarg('--colors', dest='colorstr', type=argparser.is_colorstr, 
metavar='COLORS', help=hide)
     addarg('--nc', action='store_true', help=hide)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/bukuserver/server.py 
new/buku-4.2.2/bukuserver/server.py
--- old/buku-4.1/bukuserver/server.py   2019-01-01 16:28:25.000000000 +0100
+++ new/buku-4.2.2/bukuserver/server.py 2019-05-01 01:32:47.000000000 +0200
@@ -14,7 +14,7 @@
 from markupsafe import Markup
 import click
 import flask
-from flask import (
+from flask import (  # type: ignore
     __version__ as flask_version,
     abort,
     current_app,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/requirements.txt 
new/buku-4.2.2/requirements.txt
--- old/buku-4.1/requirements.txt       2019-01-01 16:28:25.000000000 +0100
+++ new/buku-4.2.2/requirements.txt     2019-04-30 06:42:09.000000000 +0200
@@ -1,5 +1,7 @@
+# use setup.py for latest required package 
 beautifulsoup4>=4.4.1
 certifi
 cryptography>=1.2.3
+html5lib>=1.0.1
 setuptools
 urllib3>=1.23
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/setup.py new/buku-4.2.2/setup.py
--- old/buku-4.1/setup.py       2019-01-15 07:24:39.000000000 +0100
+++ new/buku-4.2.2/setup.py     2019-05-01 01:32:47.000000000 +0200
@@ -10,7 +10,7 @@
     shutil.copyfile('buku', 'buku.py')
 
 with open('buku.py', encoding='utf-8') as f:
-    version = re.search('__version__ = \'([^\']+)\'', f.read()).group(1)
+    version = re.search('__version__ = \'([^\']+)\'', f.read()).group(1)  # 
type: ignore
 
 with open('README.md', encoding='utf-8') as f:
     long_description = f.read()
@@ -20,11 +20,13 @@
     'beautifulsoup4>=4.6.0',
     'flake8>=3.4.1',
     'hypothesis>=3.7.0',
+    'mypy-extensions==0.4.1',
     'py>=1.5.0',
     'pylint>=1.7.2',
     'pytest-cov',
     'pytest>=3.4.2',
     'PyYAML>=4.2b1',
+    'setuptools>=41.0.1',
     'vcrpy>=1.13.0',
 ]
 
@@ -52,7 +54,7 @@
     author_email='[email protected]',
     url='https://github.com/jarun/Buku',
     license='GPLv3',
-    python_requires='>=3.4',  # requires pip>=9.0.0
+    python_requires='>=3.5',  # requires pip>=9.0.0
     platforms=['any'],
     py_modules=['buku'],
     install_requires=[
@@ -85,9 +87,9 @@
         'Operating System :: OS Independent',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3 :: Only',
-        'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
         'Topic :: Internet :: WWW/HTTP :: Indexing/Search',
         'Topic :: Utilities'
     ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/tests/test_buku.py 
new/buku-4.2.2/tests/test_buku.py
--- old/buku-4.1/tests/test_buku.py     2019-01-01 16:28:25.000000000 +0100
+++ new/buku-4.2.2/tests/test_buku.py   2019-05-01 01:32:47.000000000 +0200
@@ -3,6 +3,7 @@
 from unittest import mock
 from urllib.parse import urlparse
 import json
+import logging
 import os
 import signal
 import sys
@@ -528,15 +529,15 @@
         ['about:new_page', ((None, None, None, 0, 1))],
         ['chrome://version/', ((None, None, None, 0, 1))],
         ['chrome://version/', ((None, None, None, 0, 1))],
-        [
-            
'http://4pda.ru/forum/index.php?showtopic=182463&st=1640#entry6044923',
-            (
-                'Samsung GT-I5800 Galaxy 580 - Обсуждение - 4PDA',
-                'Samsung GT-I5800 Galaxy 580 - Обсуждение - 4PDA',
-                None,
-                0, 0
-            )
-        ],
+        # [
+        #     
'http://4pda.ru/forum/index.php?showtopic=182463&st=1640#entry6044923',
+        #     (
+        #         'Samsung GT-I5800 Galaxy 580 - Обсуждение - 4PDA',
+        #         'Samsung GT-I5800 Galaxy 580 - Обсуждение - 4PDA',
+        #         None,
+        #         0, 0
+        #     )
+        # ],
         [
             'https://www.google.ru/search?'
             'newwindow=1&safe=off&q=xkbcomp+alt+gr&'
@@ -726,4 +727,41 @@
                 params, stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, 
stderr=subprocess.DEVNULL)
             m_popen_retval.communicate.assert_called_once_with(content)
         else:
-            m_popen.assert_not_called()
+            logging.info('popen is called {} on unrecognized 
platform'.format(m_popen.call_count))
+
+
[email protected]('export_type, exp_res', [
+    [
+        'html',
+        '<!DOCTYPE NETSCAPE-Bookmark-file-1>\n\n'
+        '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">\n'
+        '<TITLE>Bookmarks</TITLE>\n<H1>Bookmarks</H1>\n\n<DL><p>\n'
+        '    <DT><H3 ADD_DATE="1556430615" LAST_MODIFIED="1556430615" 
PERSONAL_TOOLBAR_FOLDER="true">Buku bookmarks</H3>\n'
+        '    <DL><p>\n'
+        '        <DT><A HREF="htttp://example.com" ADD_DATE="1556430615" 
LAST_MODIFIED="1556430615"></A>\n'
+        '        <DT><A HREF="htttp://example.org" ADD_DATE="1556430615" 
LAST_MODIFIED="1556430615"></A>\n'
+        '        <DT><A HREF="http://google.com"; ADD_DATE="1556430615" 
LAST_MODIFIED="1556430615">Google</A>\n'
+        '    </DL><p>\n</DL><p>'
+    ],
+    ['org', '* [[htttp://example.com][Untitled]]\n* 
[[htttp://example.org][Untitled]]\n* [[http://google.com][Google]]\n'],
+    ['markdown', '- [Untitled](htttp://example.com)\n- 
[Untitled](htttp://example.org)\n- [Google](http://google.com)\n'],
+    ['random', None],
+])
+def test_convert_bookmark_set(export_type, exp_res, monkeypatch):
+    from buku import convert_bookmark_set
+    import buku
+    bms = [
+        (1, 'htttp://example.com', '', ',', '', 0),
+        (1, 'htttp://example.org', None, ',', '', 0),
+        (2, 'http://google.com', 'Google', ',', '', 0)]
+    if export_type == 'random':
+        with pytest.raises(AssertionError):
+            convert_bookmark_set(bms, export_type=export_type)
+    else:
+
+        def return_fixed_number():
+            return 1556430615
+        monkeypatch.setattr(buku.time, 'time', return_fixed_number)
+        res = convert_bookmark_set(bms, export_type=export_type)
+        assert res['count'] == 3
+        assert exp_res == res['data']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/buku-4.1/tests/test_bukuDb.py 
new/buku-4.2.2/tests/test_bukuDb.py
--- old/buku-4.1/tests/test_bukuDb.py   2019-01-15 08:37:12.000000000 +0100
+++ new/buku-4.2.2/tests/test_bukuDb.py 2019-05-01 01:53:29.000000000 +0200
@@ -13,7 +13,7 @@
 import zipfile
 from genericpath import exists
 from itertools import product
-from tempfile import TemporaryDirectory
+from tempfile import TemporaryDirectory, NamedTemporaryFile
 
 from unittest import mock
 import unittest
@@ -1027,52 +1027,71 @@
 
 
 @pytest.mark.parametrize(
-    'kwargs, exp_query, exp_arguments',
+    'kwargs, exp_query, exp_query_p37, exp_arguments, exp_arguments_p37',
     [
         [
             {'index': 1, 'url': 'http://example.com'},
             'UPDATE bookmarks SET URL = ?, metadata = ? WHERE id = ?',
-            ['http://example.com', 'Example Domain', 1]
+            'UPDATE bookmarks SET URL = ?, desc = ?, metadata = ? WHERE id = 
?',
+            ['http://example.com', 'Example Domain', 1],
+            ['http://example.com', '', 'Example Domain', 1]
 
         ],
         [
             {'index': 1, 'url': 'http://example.com', 'title_in': 
'randomtitle'},
             'UPDATE bookmarks SET URL = ?, metadata = ? WHERE id = ?',
+            'UPDATE bookmarks SET URL = ?, metadata = ? WHERE id = ?',
+            ['http://example.com', 'randomtitle', 1],
             ['http://example.com', 'randomtitle', 1]
 
         ],
         [
             {'index': 1, 'url': 'http://example.com', 'tags_in': 'tag1'},
             'UPDATE bookmarks SET URL = ?, tags = ?, metadata = ? WHERE id = 
?',
-            ['http://example.com', ',tag1', 'Example Domain', 1]
+            'UPDATE bookmarks SET URL = ?, tags = ?, desc = ?, metadata = ? 
WHERE id = ?',
+            ['http://example.com', ',tag1', 'Example Domain', 1],
+            ['http://example.com', ',tag1,', '', 'Example Domain', 1]
 
         ],
         [
             {'index': 1, 'url': 'http://example.com', 'tags_in': '+,tag1'},
             'UPDATE bookmarks SET URL = ?, metadata = ? WHERE id = ?',
-            ['http://example.com', 'Example Domain', 1]
+            'UPDATE bookmarks SET URL = ?, desc = ?, metadata = ? WHERE id = 
?',
+            ['http://example.com', 'Example Domain', 1],
+            ['http://example.com', '', 'Example Domain', 1]
 
         ],
         [
             {'index': 1, 'url': 'http://example.com', 'tags_in': '-,tag1'},
             'UPDATE bookmarks SET URL = ?, metadata = ? WHERE id = ?',
-            ['http://example.com', 'Example Domain', 1]
+            'UPDATE bookmarks SET URL = ?, desc = ?, metadata = ? WHERE id = 
?',
+            ['http://example.com', 'Example Domain', 1],
+            ['http://example.com', '', 'Example Domain', 1]
 
         ],
         [
             {'index': 1, 'url': 'http://example.com', 'desc': 'randomdesc'},
             'UPDATE bookmarks SET URL = ?, desc = ?, metadata = ? WHERE id = 
?',
+            'UPDATE bookmarks SET URL = ?, desc = ?, metadata = ? WHERE id = 
?',
+            ['http://example.com', 'randomdesc', 'Example Domain', 1],
             ['http://example.com', 'randomdesc', 'Example Domain', 1]
 
         ],
     ]
 )
-def test_update_rec_exec_arg(caplog, kwargs, exp_query, exp_arguments):
+def test_update_rec_exec_arg(caplog, kwargs, exp_query, exp_query_p37, 
exp_arguments, exp_arguments_p37):
     """test method."""
+    if (sys.version_info.major, sys.version_info.minor) == (3, 7):
+        caplog.set_level(logging.DEBUG)
+        exp_query = exp_query_p37
+        exp_arguments = exp_arguments_p37
     bdb = BukuDb()
     res = bdb.update_rec(**kwargs)
     assert res
+
     exp_log = 'query: "{}", args: {}'.format(exp_query, exp_arguments)
+    if (sys.version_info.major, sys.version_info.minor) == (3, 7):
+        exp_log = 'update_rec ' + exp_log
     try:
         assert caplog.records[-1].getMessage() == exp_log
         assert caplog.records[-1].levelname == 'DEBUG'
@@ -1088,37 +1107,57 @@
 
 
 @pytest.mark.parametrize(
-    'tags_to_search, exp_query, exp_arguments',
+    'tags_to_search, exp_query, exp_query_p37, exp_arguments, 
exp_arguments_p37',
     [
         [
             'tag1, tag2',
             "SELECT id, url, metadata, tags, desc FROM bookmarks WHERE tags 
LIKE '%' || ? || '%' "
             "OR tags LIKE '%' || ? || '%' ORDER BY id ASC",
-            [',tag1,', ',tag2,']
-
+            "SELECT id, url, metadata, tags, desc "
+            "FROM (SELECT *, CASE WHEN tags LIKE '%' || ? || '%' THEN 1 ELSE 0 
END + CASE "
+            "WHEN tags LIKE '%' || ? || '%' THEN 1 ELSE 0 END AS score "
+            "FROM bookmarks WHERE score > 0 ORDER BY score DESC)",
+            [',tag1,', ',tag2,'],
+            None
         ],
         [
-            'tag1+tag2,tag3, tag4',
+            'tag2+tag2,tag3, tag4',
             "SELECT id, url, metadata, tags, desc FROM bookmarks WHERE tags 
LIKE '%' || ? || '%' "
             "OR tags LIKE '%' || ? || '%' OR tags LIKE '%' || ? || '%' ORDER 
BY id ASC",
-            [',tag1+tag2,', ',tag3,', ',tag4,']
+            "SELECT id, url, metadata, tags, desc "
+            "FROM (SELECT *, CASE WHEN tags LIKE '%' || ? || '%' THEN 1 ELSE 0 
END + CASE "
+            "WHEN tags LIKE '%' || ? || '%' THEN 1 ELSE 0 END + CASE "
+            "WHEN tags LIKE '%' || ? || '%' THEN 1 ELSE 0 END AS score "
+            "FROM bookmarks WHERE score > 0 ORDER BY score DESC)",
+            [',tag1+tag2,', ',tag3,', ',tag4,'],
+            [',tag2+tag2,', ',tag3,', ',tag4,']
         ],
         [
             'tag1 + tag2+tag3',
             "SELECT id, url, metadata, tags, desc FROM bookmarks WHERE tags 
LIKE '%' || ? || '%' "
             "AND tags LIKE '%' || ? || '%' ORDER BY id ASC",
-            [',tag1,', ',tag2+tag3,']
+            None,
+            [',tag1,', ',tag2+tag3,'],
+            None
         ],
         [
             'tag1-tag2 + tag 3 - tag4',
             "SELECT id, url, metadata, tags, desc FROM bookmarks WHERE (tags 
LIKE '%' || ? || '%' "
             "AND tags LIKE '%' || ? || '%' ) AND tags NOT REGEXP ? ORDER BY id 
ASC",
-            [',tag1-tag2,', ',tag 3,', ',tag4,']
+            None,
+            [',tag1-tag2,', ',tag 3,', ',tag4,'],
+            None
         ]
     ]
 )
-def test_search_by_tag_query(caplog, tags_to_search, exp_query, exp_arguments):
+def test_search_by_tag_query(caplog, tags_to_search, exp_query, exp_query_p37, 
exp_arguments, exp_arguments_p37):
     """test that the correct query and argments are constructed"""
+    if (sys.version_info.major, sys.version_info.minor) == (3, 7):
+        caplog.set_level(logging.DEBUG)
+        if exp_query_p37:
+            exp_query = exp_query_p37
+        if exp_arguments_p37:
+            exp_arguments = exp_arguments_p37
     bdb = BukuDb()
     bdb.search_by_tag(tags_to_search)
     exp_log = 'query: "{}", args: {}'.format(exp_query, exp_arguments)
@@ -1174,6 +1213,8 @@
 @pytest.mark.parametrize('read_in_retval', ['y', 'n', ''])
 def test_update_rec_update_all_bookmark(caplog, read_in_retval):
     """test method."""
+    if (sys.version_info.major, sys.version_info.minor) == (3, 7):
+        caplog.set_level(logging.DEBUG)
     with mock.patch('buku.read_in', return_value=read_in_retval):
         import buku
         bdb = buku.BukuDb()
@@ -1183,8 +1224,12 @@
             return
         assert res
         try:
-            assert caplog.records[0].getMessage() == \
-                   'query: "UPDATE bookmarks SET tags = ?", args: [\',tags1\']'
+            if (sys.version_info.major, sys.version_info.minor) == (3, 7):
+                assert caplog.records[0].getMessage() == \
+                       'update_rec query: "UPDATE bookmarks SET tags = ?", 
args: [\',tags1,\']'
+            else:
+                assert caplog.records[0].getMessage() == \
+                       'query: "UPDATE bookmarks SET tags = ?", args: 
[\',tags1\']'
             assert caplog.records[0].levelname == 'DEBUG'
         except IndexError as e:
             # TODO: fix test
@@ -1372,6 +1417,50 @@
     assert exp_res == res
 
 
+def test_exportdb_empty_db():
+    with NamedTemporaryFile(delete=False) as f:
+        db = BukuDb(dbfile=f.name)
+        with NamedTemporaryFile(delete=False) as f2:
+            res = db.exportdb(f2.name)
+            assert not res
+
+
+def test_exportdb_single_rec(tmpdir):
+    with NamedTemporaryFile(delete=False) as f:
+        db = BukuDb(dbfile=f.name)
+        db.add_rec('http://example.com')
+        exp_file = tmpdir.join('export')
+        db.exportdb(exp_file.strpath)
+        with open(exp_file.strpath) as f:
+            assert f.read()
+
+
+def test_exportdb_to_db():
+    with NamedTemporaryFile(delete=False) as f1, 
NamedTemporaryFile(delete=False, suffix='.db') as f2:
+        db = BukuDb(dbfile=f1.name)
+        db.add_rec('http://example.com')
+        db.add_rec('http://google.com')
+        with mock.patch('builtins.input', return_value='y'):
+            db.exportdb(f2.name)
+        db2 = BukuDb(dbfile=f2.name)
+        assert db.get_rec_all() == db2.get_rec_all()
+
+
[email protected](
+    'urls, exp_res',
+    [
+        [[], -1],
+        [['http://example.com'], 1],
+        [['htttp://example.com', 'http://google.com'], 2],
+    ])
+def test_get_max_id(urls, exp_res):
+    with NamedTemporaryFile(delete=False) as f:
+        db = BukuDb(dbfile=f.name)
+        if urls:
+            list(map(lambda x: db.add_rec(x), urls))
+        assert db.get_max_id() == exp_res
+
+
 # Helper functions for testcases
 
 


Reply via email to