This is an autogenerated patch header for a single-debian-patch file. The
delta against upstream is either kept as a single patch, or maintained
in some VCS, and exported as a single patch instead of more manageable
atomic patches.

--- /dev/null
+++ gmailieer-1.3/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: gauteh
+custom: ["https://www.paypal.me/gauteh"]
--- /dev/null
+++ gmailieer-1.3/.github/workflows/python-test.yml
@@ -0,0 +1,34 @@
+# This workflow will install Python dependencies, run tests and lint with a single version of Python
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
+
+name: Python tests
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python 3.9
+      uses: actions/setup-python@v2
+      with:
+        python-version: 3.9
+    - name: Install notmuch
+      run: |
+        sudo apt-get install notmuch
+        sudo apt-get install libnotmuch-dev
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install pytest
+        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+    - name: Test with pytest
+      run: |
+        pytest -v tests
--- gmailieer-1.3.orig/docs/index.md
+++ gmailieer-1.3/docs/index.md
@@ -27,7 +27,7 @@ While Lieer has been used to successfull
 
 ## Installation
 
-After cloning the repository Lieer can be installed through pip by using the command ```pip install .``
+After cloning the repository Lieer can be installed through pip by using the command ```pip install .```
 # Usage
 
 This assumes your root mail folder is in `~/.mail` and that this folder is _already_ set up with notmuch.
@@ -176,6 +176,14 @@ Lieer can be configured using `gmi set`.
   
   *Important*: See note below on [changing this setting after initial sync](#changing-ignored-tags-and-translation-after-initial-sync).
 
+**`Local Trash Tag (local)`** can be used to set the local tag to which the remote GMail 'TRASH' label is translated.
+
+  *Important*: See note below on [changing this setting after initial sync](#changing-ignored-tags-and-translation-after-initial-sync).
+
+**`Translation List Overlay`** can be used to add or change entries in the translation mapping between local and remote tags. Argument is a comment-separated list with an even number of items. This is interpreted as a list of pairs of (remote, local), where each pair is added to the tag translation overwriting any existing translation for that tag if any. For example,
+`--translation-list-overlay CATEGORY_FORUMS,my_forum_tag` will translate Google's CATEGORY_FORUMS tag to my_forum_tag.')
+
+  *Important*: See note below on [changing this setting after initial sync](#changing-ignored-tags-and-translation-after-initial-sync).
 
 ## Changing ignored tags and translation after initial sync
 
@@ -187,11 +195,12 @@ Before changing either setting make sure
 
 When changing the opposite setting: `--ignore-tags-local`, do a full push (dry-run first): `gmi push -f --dry-run`.
 
-The same goes for the option `--replace-slash-with-dot`. I prefer to do `gmi pull -f --dry-run` after changing this option. This will overwrite the local tags with the remote labels.
+The same goes for the options `--replace-slash-with-dot` and `--local-trash-tag`. I prefer to do `gmi pull -f --dry-run` after changing this option. This will overwrite the local tags with the remote labels.
+
 
 # Translation between labels and tags
 
-We translate some of the GMail labels to other tags. The map of labels to tags are:
+We translate some of the GMail labels to other tags. The default map of labels to tags are:
 
 ```py
   'INBOX'     : 'inbox',
@@ -211,16 +220,22 @@ We translate some of the GMail labels to
   'CATEGORY_FORUMS'       : 'forums',
 ```
 
+The 'trash' local tag can be replaced using the `--local-trash-tag` option.
+
 # Using your own API key
 
 Lieer ships with an API key that is shared openly, this key shares API quota, but [cannot be used to access data](https://github.com/gauteh/lieer/pull/9) unless access is gained to your private `access_token` or `refresh_token`.
 
-You can get an [api key](https://console.developers.google.com/flows/enableapi?apiid=gmail) for a CLI application to use for yourself. Store the `client_secret.json` file somewhere safe and specify it to `gmi auth -c`. You can do this on a repository that is already initialized.
+You can get an [api key](https://console.developers.google.com/flows/enableapi?apiid=gmail) for a CLI application to use for yourself. Store the `client_secret.json` file somewhere safe and specify it to `gmi auth -c`. You can do this on a repository that is already initialized, possibly using `-f` to force reauthorizing with the new client secrets.
 
 
 # Privacy policy
 
-  Lieer downloads e-mail and labels to your local computer. No data is sent elsewhere.
+Lieer downloads e-mail and labels to your local computer. No data is sent elsewhere.
+
+Lieers use and transfer to any other app of information received from Google
+APIs will adhere to [Google API Services User Data Policy](https://developers.google.com/terms/api-services-user-data-policy#additional_requirements_for_specific_api_scopes),
+including the Limited Use requirements
 
 # Caveats
 
--- gmailieer-1.3.orig/lieer/gmailieer.py
+++ gmailieer-1.3/lieer/gmailieer.py
@@ -22,7 +22,8 @@ import  os, sys
 import  argparse
 from    oauth2client import tools
 import  googleapiclient
-import  notmuch
+import  googleapiclient.errors
+import  notmuch2
 
 from .remote import *
 from .local  import *
@@ -200,6 +201,12 @@ class Gmailieer:
     parser_set.add_argument ('--no-remove-local-messages', action = 'store_true', default = False,
         help = 'Do not remove messages that have been deleted on the remote')
 
+    parser_set.add_argument ('--local-trash-tag', type = str, default = None,
+        help = 'The local tag to use for the remote label TRASH.')
+
+    parser_set.add_argument ('--translation-list-overlay', type = str, default = None,
+        help = 'A list with an even number of items representing a list of pairs of (remote, local), where each pair is added to the tag translation.')
+
     parser_set.set_defaults (func = self.set)
 
 
@@ -305,20 +312,17 @@ class Gmailieer:
       self.remote.get_labels ()
 
     # loading local changes
-    with notmuch.Database () as db:
-      (rev, uuid) = db.get_revision ()
 
+    with notmuch2.Database() as db:
+      rev = db.revision().rev
       if rev == self.local.state.lastmod:
         self.vprint ("push: everything is up-to-date.")
         return
 
       qry = "path:%s/** and lastmod:%d..%d" % (self.local.nm_relative, self.local.state.lastmod, rev)
 
-      query = notmuch.Query (db, qry)
-      total = query.count_messages () # probably destructive here as well
-      query = notmuch.Query (db, qry)
+      messages = [db.get(m.path) for m in db.messages(qry)]
 
-      messages = list(query.search_messages ())
       if self.limit is not None and len(messages) > self.limit:
         messages = messages[:self.limit]
 
@@ -358,7 +362,7 @@ class Gmailieer:
         self.bar_create (leave = True, total = len(actions), desc = 'pushing, 0 changed')
         changed = 0
 
-        def cb (resp):
+        def cb (_):
           nonlocal changed
           self.bar_update (1)
           changed += 1
@@ -552,7 +556,7 @@ class Gmailieer:
       changed = True
 
     if self.local.config.remove_local_messages and len(deleted_messages) > 0:
-      with notmuch.Database (mode = notmuch.Database.MODE.READ_WRITE) as db:
+      with notmuch2.Database(mode = notmuch2.Database.MODE.READ_WRITE) as db:
         for m in tqdm (deleted_messages, leave = True, desc = 'removing messages'):
           self.local.remove (m['id'], db)
 
@@ -560,7 +564,7 @@ class Gmailieer:
 
     if len (labels_changed) > 0:
       lchanged = 0
-      with notmuch.Database (mode = notmuch.Database.MODE.READ_WRITE) as db:
+      with notmuch2.Database(mode = notmuch2.Database.MODE.READ_WRITE) as db:
         self.bar_create (total = len(labels_changed), leave = True, desc = 'updating tags (0)')
         for m in labels_changed:
           r = self.local.update_tags (m, None, db)
@@ -644,7 +648,7 @@ class Gmailieer:
       all_local  = set(self.local.gids.keys())
       remove     = list(all_local - all_remote)
       self.bar_create (leave = True, total = len(remove), desc = 'removing deleted')
-      with notmuch.Database (mode = notmuch.Database.MODE.READ_WRITE) as db:
+      with notmuch2.Database (mode = notmuch2.Database.MODE.READ_WRITE) as db:
         for m in remove:
           self.local.remove(m, db)
           self.bar_update (1)
@@ -668,8 +672,8 @@ class Gmailieer:
 
     # set notmuch lastmod time, since we have now synced everything from remote
     # to local
-    with notmuch.Database() as db:
-      (rev, uuid) = db.get_revision()
+    with notmuch2.Database() as db:
+      rev = db.revision().rev
 
     if not self.dry_run:
       self.local.state.set_lastmod(rev)
@@ -709,7 +713,7 @@ class Gmailieer:
 
       # opening db for whole metadata sync
       def _got_msgs (ms):
-        with notmuch.Database (mode = notmuch.Database.MODE.READ_WRITE) as db:
+        with notmuch2.Database(mode = notmuch2.Database.MODE.READ_WRITE) as db:
           for m in ms:
             self.bar_update (1)
             self.local.update_tags (m, None, db)
@@ -743,7 +747,7 @@ class Gmailieer:
 
       def _got_msgs (ms):
         # opening db per message batch since it takes some time to download each one
-        with notmuch.Database (mode = notmuch.Database.MODE.READ_WRITE) as db:
+        with notmuch2.Database(mode = notmuch2.Database.MODE.READ_WRITE) as db:
           for m in ms:
             self.bar_update (1)
             self.local.store (m, db)
@@ -812,11 +816,11 @@ class Gmailieer:
     if 'In-Reply-To' in eml:
       repl = eml['In-Reply-To'].strip().strip('<>')
       self.vprint("looking for original message: %s" % repl)
-      with notmuch.Database (mode = notmuch.Database.MODE.READ_ONLY) as db:
-        nmsg = db.find_message(repl)
+      with notmuch2.Database(mode = notmuch2.Database.MODE.READ_ONLY) as db:
+        nmsg = db.find(repl)
         if nmsg is not None:
           (_, gids) = self.local.messages_to_gids([nmsg])
-          if nmsg.get_header('Subject') != eml['Subject']:
+          if nmsg.header('Subject') != eml['Subject']:
             self.vprint ("warning: subject does not match, might not be able to associate with existing thread.")
 
           if len(gids) > 0:
@@ -875,6 +879,12 @@ class Gmailieer:
     if args.file_extension is not None:
       self.local.config.set_file_extension (args.file_extension)
 
+    if args.local_trash_tag is not None:
+      self.local.config.set_local_trash_tag (args.local_trash_tag)
+
+    if args.translation_list_overlay is not None:
+      self.local.config.set_translation_list_overlay (args.translation_list_overlay)
+
     print ("Repository information and settings:")
     print ("Account ...........: %s" % self.local.config.account)
     print ("historyId .........: %d" % self.local.state.last_historyId)
@@ -887,6 +897,8 @@ class Gmailieer:
     print ("Replace . with / ..........:", self.local.config.replace_slash_with_dot)
     print ("Ignore tags (local) .......:", self.local.config.ignore_tags)
     print ("Ignore labels (remote) ....:", self.local.config.ignore_remote_labels)
+    print ("Trash tag (local) .........:", self.local.config.local_trash_tag)
+    print ("Translation list overlay ..:", self.local.config.translation_list_overlay)
 
   def vprint (self, *args, **kwargs):
     """
--- gmailieer-1.3.orig/lieer/local.py
+++ gmailieer-1.3/lieer/local.py
@@ -22,7 +22,7 @@ import configparser
 from pathlib import Path
 import tempfile
 
-import notmuch
+import notmuch2
 from .remote import Remote
 
 class Local:
@@ -31,7 +31,7 @@ class Local:
 
 
   # NOTE: Update README when changing this map.
-  translate_labels = {
+  translate_labels_default = {
                       'INBOX'     : 'inbox',
                       'SPAM'      : 'spam',
                       'TRASH'     : 'trash',
@@ -49,7 +49,7 @@ class Local:
                       'CATEGORY_FORUMS'       : 'forums',
                       }
 
-  labels_translate = { v: k for k, v in translate_labels.items () }
+  labels_translate_default = { v: k for k, v in translate_labels_default.items () }
 
   ignore_labels = set ([
                         'archive',
@@ -66,6 +66,35 @@ class Local:
                         'voicemail',
                         ])
 
+  def update_translation(self, remote, local):
+    """
+    Convenience function to ensure both maps (remote -> local and local -> remote)
+    get updated when you update a translation.
+    """
+    # Did you reverse the parameters?
+    assert remote in self.translate_labels
+    self.translate_labels[remote] = local
+    self.labels_translate = { v: k for k, v in self.translate_labels.items () }
+
+  def update_translation_list_with_overlay(self, translation_list_overlay):
+    """
+    Takes a list with an even number of items. The list is interpreted as a list of pairs
+    of (remote, local), where each member of each pair is a string. Each pair is added to the
+    translation, overwriting the translation if one already exists (in either direction).
+    If either the remote or the local labels are non-unique, the later items in the list will
+    overwrite the earlier ones in the direction in which the source is non-unique (for example,
+    ["a", "1", "b", 2", "a", "3"] will yield {'a': 3, 'b': 2} in one direction and {1: 'a', 2: 'b', 3: 'a'}
+    in the other).
+    """
+
+    if len(translation_list_overlay) % 2 != 0:
+      raise Exception(f'Translation list overlay must have an even number of items: {translation_list_overlay}')
+
+    for i in range(0,len(translation_list_overlay),2):
+      (remote, local) = translation_list_overlay[i], translation_list_overlay[i+1]
+      self.translate_labels[remote] = local
+      self.labels_translate[local] = remote
+
   class RepositoryException (Exception):
     pass
 
@@ -80,6 +109,8 @@ class Local:
     ignore_remote_labels = None
     remove_local_messages = True
     file_extension = None
+    local_trash_tag = 'trash'
+    translation_list_overlay = None
 
     def __init__ (self, config_f):
       self.config_f = config_f
@@ -103,6 +134,8 @@ class Local:
       self.ignore_tags = set(self.json.get ('ignore_tags', []))
       self.ignore_remote_labels = set(self.json.get ('ignore_remote_labels', Remote.DEFAULT_IGNORE_LABELS))
       self.file_extension = self.json.get ('file_extension', '')
+      self.local_trash_tag = self.json.get ('local_trash_tag', 'trash')
+      self.translation_list_overlay = self.json.get ('translation_list_overlay', [])
 
     def write (self):
       self.json = {}
@@ -116,6 +149,8 @@ class Local:
       self.json['ignore_remote_labels'] = list(self.ignore_remote_labels)
       self.json['remove_local_messages'] = self.remove_local_messages
       self.json['file_extension'] = self.file_extension
+      self.json['local_trash_tag'] = self.local_trash_tag
+      self.json['translation_list_overlay'] = self.translation_list_overlay
 
       if os.path.exists (self.config_f):
         shutil.copyfile (self.config_f, self.config_f + '.bak')
@@ -166,7 +201,7 @@ class Local:
 
     def set_file_extension (self, t):
       try:
-        with tempfile.NamedTemporaryFile (dir = os.path.dirname (self.state_f), suffix = t) as fd:
+        with tempfile.NamedTemporaryFile (dir = os.path.dirname (self.config_f), suffix = t) as _:
           pass
 
         self.file_extension = t.strip ()
@@ -175,6 +210,23 @@ class Local:
         print ("Failed creating test file with file extension: " + t + ", not set.")
         raise
 
+    def set_local_trash_tag (self, t):
+      if ',' in t:
+        print('The local_trash_tag must be a single tag, not a list.  Commas are not allowed.')
+        raise ValueError()
+      self.local_trash_tag = t.strip() or 'trash'
+      self.write()
+
+    def set_translation_list_overlay (self, t):
+      if len(t.strip ()) == 0:
+        self.translation_list_overlay = []
+      else:
+        self.translation_list_overlay = [ tt.strip () for tt in t.split(',') ]
+      if len(self.translation_list_overlay) % 2 != 0:
+        raise Exception(f'Translation list overlay must have an even number of items: {self.translation_list_overlay}')
+      self.write ()
+
+
 
   class State:
     # last historyid of last synchronized message, anything that has happened
@@ -241,7 +293,7 @@ class Local:
       self.lastmod = m
       self.write ()
 
-
+  # we are in the class "Local"; this is the Local instance constructor
   def __init__ (self, g):
     self.gmailieer = g
     self.wd = os.getcwd ()
@@ -255,6 +307,10 @@ class Local:
     # mail store
     self.md = os.path.join (self.wd, 'mail')
 
+    # initialize label translation instance variables
+    self.translate_labels = Local.translate_labels_default.copy()
+    self.labels_translate = Local.labels_translate_default.copy()
+
   def load_repository (self, block = False):
     """
     Loads the current local repository
@@ -269,25 +325,13 @@ class Local:
              for mail_dir in ('cur', 'new', 'tmp')]):
       raise Local.RepositoryException ('local repository not initialized: could not find mail dir structure')
 
-    self.config = Local.Config (self.config_f)
-    self.state = Local.State (self.state_f, self.config)
-
-    self.ignore_labels = self.ignore_labels | self.config.ignore_tags
-
     ## Check if we are in the notmuch db
-    with notmuch.Database () as db:
+    with notmuch2.Database () as db:
       try:
-        self.nm_dir  = db.get_directory (os.path.abspath(self.md))
-        if self.nm_dir is not None:
-          self.nm_dir = self.nm_dir.path
-        else:
-          # probably empty dir
-          self.nm_dir = os.path.abspath (self.md)
-
-        self.nm_relative = self.nm_dir[len(db.get_path ())+1:]
-
-      except notmuch.errors.FileError:
+        self.nm_relative=str(Path(self.md).relative_to(db.path))
+      except ValueError:
         raise Local.RepositoryException ("local mail repository not in notmuch db")
+      self.nm_dir=str(Path(self.md).resolve())
 
     ## Lock repository
     try:
@@ -299,17 +343,19 @@ class Local:
     except OSError:
       raise Local.RepositoryException ("failed to lock repository (probably in use by another gmi instance)")
 
+    self.config = Local.Config (self.config_f)
+    self.state = Local.State (self.state_f, self.config)
+
+    self.ignore_labels = self.ignore_labels | self.config.ignore_tags
+    self.update_translation('TRASH', self.config.local_trash_tag)
+    self.update_translation_list_with_overlay(self.config.translation_list_overlay)
+
     self.__load_cache__ ()
 
     # load notmuch config
-    cfg = os.environ.get('NOTMUCH_CONFIG', os.path.expanduser('~/.notmuch-config'))
-    if not os.path.exists (cfg):
-      raise Local.RepositoryException("could not find notmuch-config: %s" % cfg)
-
-    self.nmconfig = configparser.ConfigParser ()
-    self.nmconfig.read (cfg)
-    self.new_tags = self.nmconfig['new']['tags'].split (';')
-    self.new_tags = [t.strip () for t in self.new_tags if len(t.strip()) > 0]
+    with notmuch2.Database() as db:
+      self.new_tags = db.config["new.tags"].split(';')
+    self.new_tags = [t.strip() for t in self.new_tags if len(t.strip()) > 0]
 
     self.loaded = True
 
@@ -319,12 +365,12 @@ class Local:
     ## this cache is used to know which messages we have a physical copy of.
     ## hopefully this won't grow too gigantic with lots of messages.
     self.files = []
-    for (dp, dirnames, fnames) in os.walk (os.path.join (self.md, 'cur')):
+    for (_, _, fnames) in os.walk (os.path.join (self.md, 'cur')):
       _fnames = ( 'cur/' + f for f in fnames )
       self.files.extend (_fnames)
       break
 
-    for (dp, dirnames, fnames) in os.walk (os.path.join (self.md, 'new')):
+    for (_, _, fnames) in os.walk (os.path.join (self.md, 'new')):
       _fnames = ( 'new/' + f for f in fnames )
       self.files.extend (_fnames)
       break
@@ -370,7 +416,7 @@ class Local:
     """
     Update cache with filenames from nmsg, removing the old:
 
-      nmsg - NotmuchMessage
+      nmsg - notmuch2.Message
       old  - tuple of old gid and old fname
     """
 
@@ -383,7 +429,8 @@ class Local:
       self.gids.pop (old_gid)
 
     # add message to cache
-    for _f in nmsg.get_filenames ():
+    fname_iter = nmsg.filenames ()
+    for _f in fname_iter:
       if self.contains (_f):
         new_f = Path (_f)
 
@@ -404,7 +451,7 @@ class Local:
     messages = []
 
     for m in msgs:
-      for fname in m.get_filenames ():
+      for fname in m.filenames ():
         if self.contains (fname):
           # get gmail id
           gid = self.__filename_to_gid__ (os.path.basename (fname))
@@ -468,13 +515,16 @@ class Local:
       return
 
     fname = os.path.join (self.md, fname)
-    nmsg  = db.find_message_by_filename (fname)
+    try:
+        nmsg = db.get(fname)
+    except LookupError:
+        nmsg = None
 
     if self.dry_run:
       print ("(dry-run) deleting %s: %s." % (gid, fname))
     else:
       if nmsg is not None:
-        db.remove_message (fname)
+        db.remove(fname)
       os.unlink (fname)
 
       self.files.remove (ffname)
@@ -507,7 +557,7 @@ class Local:
       raise Local.RepositoryException ("local file already exists: %s" % p)
 
     if os.path.exists (tmp_p):
-      raise Local.RepositoryException ("local file already exists: %s" % p)
+      raise Local.RepositoryException ("local temporary file already exists: %s" % tmp_p)
 
     if not self.dry_run:
       with open (tmp_p, 'wb') as fd:
@@ -574,52 +624,47 @@ class Local:
       else:
         print ("(dry-run) tried to update tags on non-existant file: %s" % fname)
 
-    nmsg  = db.find_message_by_filename (fname)
+    try:
+      nmsg = db.get(fname)
+    except LookupError:
+      nmsg = None
 
     if nmsg is None:
       if self.dry_run:
         print ("(dry-run) adding message: %s: %s, with tags: %s" % (gid, fname, str(labels)))
       else:
         try:
-          if hasattr (notmuch.Database, 'index_file'):
-            (nmsg, stat) = db.index_file (fname, True)
-          else:
-            (nmsg, stat) = db.add_message (fname, True)
-        except notmuch.errors.FileNotEmailError:
+          (nmsg, _) = db.add (fname, sync_flags = True)
+        except notmuch2.errors.FileNotEmailError:
           print('%s is not an email' % fname)
           return True
-        nmsg.freeze ()
 
         # adding initial tags
-        for t in labels:
-          nmsg.add_tag (t, True)
+        with nmsg.frozen():
+          for t in labels:
+            nmsg.tags.add (t)
 
-        for t in self.new_tags:
-          nmsg.add_tag (t, True)
+          for t in self.new_tags:
+            nmsg.tags.add (t)
 
-        nmsg.thaw ()
-        nmsg.tags_to_maildir_flags ()
+        nmsg.tags.to_maildir_flags()
         self.__update_cache__ (nmsg)
 
       return True
 
     else:
       # message is already in db, set local tags to match remote tags
-      otags   = set(nmsg.get_tags ())
+      otags   = nmsg.tags
       igntags = otags & self.ignore_labels
       otags   = otags - self.ignore_labels # remove ignored tags while checking
       if otags != set (labels):
         labels.extend (igntags) # add back local ignored tags before adding
         if not self.dry_run:
-          nmsg.freeze ()
-
-          nmsg.remove_all_tags ()
-          for t in labels:
-            nmsg.add_tag (t, False)
-
-          nmsg.thaw ()
-
-          nmsg.tags_to_maildir_flags ()
+          with nmsg.frozen():
+            nmsg.tags.clear()
+            for t in labels:
+              nmsg.tags.add (t)
+          nmsg.tags.to_maildir_flags()
           self.__update_cache__ (nmsg, (gid, fname))
 
         else:
--- gmailieer-1.3.orig/lieer/remote.py
+++ gmailieer-1.3/lieer/remote.py
@@ -333,16 +333,16 @@ class Remote:
       try:
         batch.execute (http = self.http)
 
-        # gradually reduce user delay if we had 10 ok batches
+        # gradually reduce user delay upon every ok batch
         user_rate_ok += 1
-        if user_rate_delay > 0 and user_rate_ok > 10:
+        if user_rate_delay > 0 and user_rate_ok > 0:
           user_rate_delay = user_rate_delay // 2
           print ("remote: decreasing delay to %s" % user_rate_delay)
           user_rate_ok    = 0
 
-        # gradually increase batch request size if we had 10 ok requests
+        # gradually increase batch request size upon every ok request
         req_ok += 1
-        if max_req < self.BATCH_REQUEST_SIZE and req_ok > 10:
+        if max_req < self.BATCH_REQUEST_SIZE and req_ok > 0:
           max_req = min (max_req * 2, self.BATCH_REQUEST_SIZE)
           print ("remote: increasing batch request size to: %d" % max_req)
           req_ok  = 0
@@ -488,8 +488,8 @@ class Remote:
     gid    = gmsg['id']
 
     found = False
-    for f in nmsg.get_filenames ():
-      if gid in f:
+    for f in nmsg.filenames():
+      if gid in str(f):
         found = True
 
     # this can happen if a draft is edited remotely and is synced before it is sent. we'll
@@ -528,7 +528,7 @@ class Remote:
     labels = set(labels)
 
     # current tags
-    tags = set(nmsg.get_tags ())
+    tags = nmsg.tags
 
     # remove special notmuch tags
     tags = tags - self.gmailieer.local.ignore_labels
@@ -606,7 +606,7 @@ class Remote:
     Push label changes
     """
     max_req = self.BATCH_REQUEST_SIZE
-    N       = len (actions)
+    N       = len(actions)
     i       = 0
     j       = 0
 
@@ -615,19 +615,19 @@ class Remote:
     # How many requests with the current delay returned ok.
     user_rate_ok        = 0
 
-    def _cb (rid, resp, excep):
+    def _cb(rid, resp, excep):
       nonlocal j
       if excep is not None:
         if type(excep) is googleapiclient.errors.HttpError and excep.resp.status == 404:
           # message could not be found this is probably a deleted message, spam or draft
           # message since these are not included in the messages.get() query by default.
-          print ("remote: could not find remote message: %s!" % gids[j])
+          print ("remote: could not find remote message: %s!" % resp)
           j += 1
           return
 
         elif type(excep) is googleapiclient.errors.HttpError and excep.resp.status == 400:
           # message id invalid, probably caused by stray files in the mail repo
-          print ("remote: message id: %s is invalid! are there any non-lieer files created in the lieer repository?" % gids[j])
+          print ("remote: message id is invalid! are there any non-lieer files created in the lieer repository? %s" % resp)
           j += 1
           return
 
@@ -639,16 +639,16 @@ class Remote:
       else:
         j += 1
 
-      cb (resp)
+      cb(resp)
 
     while i < N:
       n = 0
       j = i
-      batch = self.service.new_batch_http_request  (callback = _cb)
+      batch = self.service.new_batch_http_request(callback = _cb)
 
       while n < max_req and i < N:
         a = actions[i]
-        batch.add (a)
+        batch.add(a)
         n += 1
         i += 1
 
@@ -666,14 +666,14 @@ class Remote:
           user_rate_delay = user_rate_delay // 2
           user_rate_ok    = 0
 
-      except Remote.UserRateException as ex:
+      except Remote.UserRateException:
         user_rate_delay = user_rate_delay * 2 + 1
         print ("remote: user rate error, increasing delay to %s" % user_rate_delay)
         user_rate_ok = 0
 
         i = j # reset
 
-      except Remote.BatchException as ex:
+      except Remote.BatchException:
         if max_req > self.MIN_BATCH_REQUEST_SIZE:
           max_req = max_req / 2
           i = j # reset
--- gmailieer-1.3.orig/requirements.txt
+++ gmailieer-1.3/requirements.txt
@@ -1,4 +1,4 @@
 google-api-python-client
 oauth2client
 tqdm
-notmuch
+notmuch2
--- gmailieer-1.3.orig/setup.py
+++ gmailieer-1.3/setup.py
@@ -69,7 +69,7 @@ setup(
     # your project is installed. For an analysis of "install_requires" vs pip's
     # requirements files see:
     # https://packaging.python.org/en/latest/requirements.html
-    install_requires=['oauth2client', 'google-api-python-client', 'tqdm', 'notmuch'],
+    install_requires=['oauth2client', 'google-api-python-client', 'tqdm', 'notmuch2'],
 
     # List additional groups of dependencies here (e.g. development
     # dependencies). You can install these using the following syntax,
--- /dev/null
+++ gmailieer-1.3/tests/__init__.py
@@ -0,0 +1,18 @@
+import pytest
+import tempfile
+
+class MockGmi:
+    dry_run = False
+
+    def __init__(self):
+        pass
+
+
+
+@pytest.fixture
+def gmi():
+    """
+    Test gmi
+    """
+
+    return MockGmi()
--- /dev/null
+++ gmailieer-1.3/tests/test_local.py
@@ -0,0 +1,14 @@
+from . import *
+import lieer
+
+
+def test_update_translation_list(gmi):
+    l = lieer.Local(gmi)
+    l.update_translation_list_with_overlay(['a', '1', 'b', '2'])
+    assert l.translate_labels['a'] == '1'
+    assert l.translate_labels['b'] == '2'
+    assert l.labels_translate['1'] == 'a'
+    assert l.labels_translate['2'] == 'b'
+
+    with pytest.raises(Exception):
+        l.update_translation_list_with_overlay(['a', '1', 'b', '2', 'c'])
