diff --git a/latex.plugin.desktop.in.in b/latex.plugin.desktop.in.in
index 62b1e58..0c9090b 100644
--- a/latex.plugin.desktop.in.in
+++ b/latex.plugin.desktop.in.in
@@ -1,7 +1,7 @@
 [Plugin]
 Module=latex
 IAge=3
-Loader=python
+Loader=python3
 _Name=LaTeX Plugin
 _Description=A plugin that assists you in handling LaTeX documents and BibTeX bibliographies
 Authors=Michael Zeising <michael@michaels-website.de>
diff --git a/latex/__init__.py b/latex/__init__.py
index 003d38c..1083e29 100644
--- a/latex/__init__.py
+++ b/latex/__init__.py
@@ -35,7 +35,7 @@ if "org.gnome.gedit.plugins.latex" not in Gio.Settings.list_schemas():
     logging.critical("Could not find GSettings schema: org.gnome.gedit.plugins.latex")
     raise Exception("Plugin schema not installed")
 
-from appactivatable import LaTeXAppActivatable
-from windowactivatable import LaTeXWindowActivatable
+from .appactivatable import LaTeXAppActivatable
+from .windowactivatable import LaTeXWindowActivatable
 
 # ex:ts=4:et:
diff --git a/latex/appactivatable.py b/latex/appactivatable.py
index f735caa..02e9abf 100644
--- a/latex/appactivatable.py
+++ b/latex/appactivatable.py
@@ -19,7 +19,7 @@ import os.path
 import platform
 
 from gi.repository import GLib, Gedit, GObject
-from resources import Resources
+from .resources import Resources
 
 class LaTeXAppActivatable(GObject.Object, Gedit.AppActivatable):
     __gtype_name__ = "GeditLaTeXAppActivatable"
diff --git a/latex/bibtex/actions.py b/latex/bibtex/actions.py
index a4b3602..756b61c 100644
--- a/latex/bibtex/actions.py
+++ b/latex/bibtex/actions.py
@@ -24,7 +24,7 @@ latex.actions
 
 from ..action import Action
 from ..gldefs import _
-from dialogs import InsertBibTeXEntryDialog
+from .dialogs import InsertBibTeXEntryDialog
 
 
 class BibTeXMenuAction(Action):
diff --git a/latex/bibtex/cache.py b/latex/bibtex/cache.py
index bbed557..2c9c18a 100644
--- a/latex/bibtex/cache.py
+++ b/latex/bibtex/cache.py
@@ -24,7 +24,7 @@ bibtex.cache
 
 from logging import getLogger
 
-from parser import BibTeXParser
+from .parser import BibTeXParser
 from ..issues import MockIssueHandler
 
 
diff --git a/latex/bibtex/completion.py b/latex/bibtex/completion.py
index 4149535..9437908 100644
--- a/latex/bibtex/completion.py
+++ b/latex/bibtex/completion.py
@@ -30,8 +30,8 @@ from ..preferences import Preferences
 from ..resources import Resources
 from ..completion import ICompletionHandler, Proposal
 from ..issues import MockIssueHandler
-from model import BibTeXModel
-from parser import BibTeXParser
+from .model import BibTeXModel
+from .parser import BibTeXParser
 
 LOG = logging.getLogger(__name__)
 
diff --git a/latex/bibtex/dialogs.py b/latex/bibtex/dialogs.py
index 5fb35ff..c676e05 100644
--- a/latex/bibtex/dialogs.py
+++ b/latex/bibtex/dialogs.py
@@ -26,7 +26,7 @@ from gi.repository import Gtk
 
 from ..util import GladeInterface
 from ..resources import Resources
-from model import BibTeXModel
+from .model import BibTeXModel
 
 
 class InsertBibTeXEntryDialog(GladeInterface):
@@ -48,7 +48,7 @@ class InsertBibTeXEntryDialog(GladeInterface):
 
             # fields
             f = []
-            for entry, field in self._mapping.iteritems():
+            for entry, field in self._mapping.items():
                 value = entry.get_text()
                 if len(value):
                     if field == "title":
@@ -118,7 +118,7 @@ class InsertBibTeXEntryDialog(GladeInterface):
 
         # cache values
 
-        for entry, fieldName in self._mapping.iteritems():
+        for entry, fieldName in self._mapping.items():
             text = entry.get_text()
             if len(text):
                 self._fieldCache[fieldName] = entry.get_text()
diff --git a/latex/bibtex/editor.py b/latex/bibtex/editor.py
index 9ad1ba6..4e79f78 100644
--- a/latex/bibtex/editor.py
+++ b/latex/bibtex/editor.py
@@ -34,9 +34,9 @@ from ..util import verbose
 
 from ..job import Job, JobChangeListener
 
-from parser import BibTeXParser
-from completion import BibTeXCompletionHandler
-from validator import BibTeXValidator
+from .parser import BibTeXParser
+from .completion import BibTeXCompletionHandler
+from .validator import BibTeXValidator
 
 LOG = logging.getLogger(__name__)
 
diff --git a/latex/bibtex/model.py b/latex/bibtex/model.py
index f4a27c8..c67227b 100644
--- a/latex/bibtex/model.py
+++ b/latex/bibtex/model.py
@@ -100,7 +100,7 @@ class BibTeXModel(object):
         List all entry types in sorted order
         """
         if self._types_list is None:
-            self._types_list = self._types.values()
+            self._types_list = list(self._types.values())
             self._types_list.sort()
         return self._types_list
 
diff --git a/latex/bibtex/parser.py b/latex/bibtex/parser.py
index f98412d..7ce9b4e 100644
--- a/latex/bibtex/parser.py
+++ b/latex/bibtex/parser.py
@@ -65,7 +65,7 @@ class Token(object):
     A BibTeX token
     """
 
-    AT, TEXT, COMMA, EQUALS, QUOTE, HASH, CURLY_OPEN, CURLY_CLOSE, ROUND_OPEN, ROUND_CLOSE = range(10)
+    AT, TEXT, COMMA, EQUALS, QUOTE, HASH, CURLY_OPEN, CURLY_CLOSE, ROUND_OPEN, ROUND_CLOSE = list(range(10))
 
     def __init__(self, type, offset, value):
         self.type = type
@@ -98,7 +98,7 @@ class BibTeXLexer(object):
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         """
         Return the next token
         """
@@ -141,7 +141,7 @@ class BibTeXParser(object):
 
     _OUTSIDE, _TYPE, _AFTER_TYPE, _AFTER_STRING_TYPE, _KEY, _STRING_KEY, _AFTER_KEY, _AFTER_STRING_KEY, \
             _STRING_VALUE, _QUOTED_STRING_VALUE, _FIELD_NAME, _AFTER_FIELD_NAME, _FIELD_VALUE, _EMBRACED_FIELD_VALUE, \
-            _QUOTED_FIELD_VALUE = range(15)
+            _QUOTED_FIELD_VALUE = list(range(15))
 
     def __init__(self, quiet=False):
         self._quiet = quiet
diff --git a/latex/bibtex/validator.py b/latex/bibtex/validator.py
index 43b7ecd..46584e3 100644
--- a/latex/bibtex/validator.py
+++ b/latex/bibtex/validator.py
@@ -24,7 +24,7 @@ bibtex.validator
 from logging import getLogger
 
 from ..issues import Issue
-from model import BibTeXModel
+from .model import BibTeXModel
 
 
 class BibTeXValidator:
@@ -69,7 +69,7 @@ class BibTeXValidator:
 
             try:
                 # check for missing required fields
-                required_field_names = set(map(lambda f: f.name, self._model.find_type(entry.type).required_fields))
+                required_field_names = set([f.name for f in self._model.find_type(entry.type).required_fields])
                 missing_field_names = required_field_names.difference(set(field_names))
 
                 if len(missing_field_names) > 0:
@@ -77,7 +77,7 @@ class BibTeXValidator:
                                               entry.start, entry.end, file, Issue.SEVERITY_WARNING))
 
                 # check for unused fields
-                optional_field_names = set(map(lambda f: f.name, self._model.find_type(entry.type).optional_fields))
+                optional_field_names = set([f.name for f in self._model.find_type(entry.type).optional_fields])
                 unused_field_names = set(field_names).difference(optional_field_names.union(required_field_names))
 
                 if len(unused_field_names) > 0:
diff --git a/latex/bibtex/views.py b/latex/bibtex/views.py
index 7b164ed..63de7fa 100644
--- a/latex/bibtex/views.py
+++ b/latex/bibtex/views.py
@@ -31,7 +31,7 @@ from logging import getLogger
 from ..outline import OutlineOffsetMap, BaseOutlineView
 from ..resources import Resources
 from ..preferences import Preferences
-from parser import Entry
+from .parser import Entry
 from ..gldefs import _
 
 
@@ -170,7 +170,7 @@ class OutlineConverter(object):
                     groups[entry.type] = [entry]
 
             # sort by type
-            entryTypes = groups.keys()
+            entryTypes = list(groups.keys())
             entryTypes.sort()
 
             # build tree
@@ -213,7 +213,7 @@ class OutlineConverter(object):
                     groups[year] = [entry]
 
             # sort by year
-            years = groups.keys()
+            years = list(groups.keys())
             years.sort()
 
             # build tree
@@ -260,7 +260,7 @@ class OutlineConverter(object):
                         groups[author] = [entry]
 
             # sort
-            authors = groups.keys()
+            authors = list(groups.keys())
             authors.sort()
 
             # build tree
diff --git a/latex/completion.py b/latex/completion.py
index 3b4c638..517cce3 100644
--- a/latex/completion.py
+++ b/latex/completion.py
@@ -277,7 +277,7 @@ class ProposalPopup(Gtk.Window):
             # activate
             self._details_popup.activate(proposal.details)
 
-        except Exception, e:
+        except Exception as e:
             self._log.error(e)
 
     def _move_to_cursor(self, text_view):
@@ -431,7 +431,7 @@ class CompletionDistributor(object):
         self._trigger_keys = []
         for handler in self._handlers:
             for key in handler.trigger_keys:
-                if key in self._SPECIAL_KEYS.keys():
+                if key in list(self._SPECIAL_KEYS.keys()):
                     self._trigger_keys.append(self._SPECIAL_KEYS[key])
                 else:
                     self._trigger_keys.append(key)
@@ -488,7 +488,7 @@ class CompletionDistributor(object):
                 self._state = self._STATE_IDLE
                 self._complete()
                 return True
-            else:
+            elif key != "Control_L" and key != "Control_R":
                 self._state = self._STATE_IDLE
 
         self._stop_timer()
diff --git a/latex/editor.py b/latex/editor.py
index f8ad525..c126ab5 100644
--- a/latex/editor.py
+++ b/latex/editor.py
@@ -195,7 +195,7 @@ class Editor(object):
                     LOG.debug("Found TextMark '%s' at offset %s" % (name, it.get_offset()))
 
                     if name:
-                        if name in self._markers.keys():
+                        if name in list(self._markers.keys()):
                             marker = self._markers[name]
                             return self.on_marker_activated(marker, event)
                         else:
@@ -294,7 +294,7 @@ class Editor(object):
         Return the string contained in the TextBuffer
         """
         return self._text_buffer.get_text(self._text_buffer.get_start_iter(),
-                                    self._text_buffer.get_end_iter(), False).decode(self.charset)
+                                    self._text_buffer.get_end_iter(), False)
 
     @property
     def content_at_left_of_cursor(self):
@@ -402,7 +402,7 @@ class Editor(object):
         @param background_color: a hex color
         @param anonymous: markers of an anonymous type may not be activated and do not get a unique ID
         """
-        assert not marker_type in self._marker_types.keys()
+        assert not marker_type in list(self._marker_types.keys())
 
         # create Gtk.TextTag
         tag = self._text_buffer.create_tag(marker_type, background=background_color)
diff --git a/latex/file.py b/latex/file.py
index ea003e1..6d9d873 100644
--- a/latex/file.py
+++ b/latex/file.py
@@ -25,8 +25,8 @@ import logging
 import os.path
 
 import re
-import urllib
-import urlparse
+import urllib.request, urllib.parse, urllib.error
+import urllib.parse
 
 class File(object):
     """
@@ -64,10 +64,10 @@ class File(object):
         if uri is None:
             raise ValueError("URI must not be None")
 
-        self._uri = urlparse.urlparse(uri)
+        self._uri = urllib.parse.urlparse(uri)
         if len(self._uri.scheme) == 0:
             # prepend default scheme if missing
-            self._uri = urlparse.urlparse("%s%s" % (self._DEFAULT_SCHEME, uri))
+            self._uri = urllib.parse.urlparse("%s%s" % (self._DEFAULT_SCHEME, uri))
 
     def create(self, content=None):
         """
@@ -83,7 +83,7 @@ class File(object):
         """
         Returns '/home/user/image.jpg' for 'file:///home/user/image.jpg'
         """
-        return urllib.url2pathname(self._uri.path)
+        return urllib.request.url2pathname(self._uri.path)
 
     @property
     def extension(self):
@@ -151,7 +151,7 @@ class File(object):
             neighbors = [File(filename) for filename in filenames]
             return neighbors
 
-        except Exception, e:
+        except Exception as e:
             # as seen in Bug #2002630 the glob() call compiles a regex and so we must be prepared
             # for an exception from that because the shortname may contain regex characters
 
@@ -172,7 +172,7 @@ class File(object):
         try:
             filenames = glob("%s.*" % self.shortname)
             siblings = [File(filename) for filename in filenames]
-        except Exception, e:
+        except Exception as e:
             # as seen in Bug #2002630 the glob() call compiles a regex and so we must be prepared
             # for an exception from that because the shortname may contain regex characters
 
@@ -277,7 +277,7 @@ class Folder(File):
             files = [File(filename) for filename in filenames]
             return files
 
-        except Exception, e:
+        except Exception as e:
             # as seen in Bug #2002630 the glob() call compiles a regex and so we must be prepared
             # for an exception from that because the shortname may contain regex characters
 
@@ -337,15 +337,15 @@ def fixurl(url):
     url = url.strip()
     if not url:
         return ''
-    if not urlparse.urlsplit(url).scheme:
+    if not urllib.parse.urlsplit(url).scheme:
         ## We usually deal with local files here
         url = 'file://' + url
         ## url = 'http://' + url
 
     # turn it into Unicode
     try:
-        url = unicode(url, 'utf-8')
-    except Exception, exc:   # UnicodeDecodeError, exc:
+        url = str(url, 'utf-8')
+    except Exception as exc:   # UnicodeDecodeError, exc:
         ## It often happens that the url is already "python unicode" encoded
         if not str(exc) == "decoding Unicode is not supported":
             return ''  # bad UTF-8 chars in URL
@@ -354,7 +354,7 @@ def fixurl(url):
         ## so we can just continue (see http://www.red-mercury.com/blog/eclectic-tech/python-mystery-of-the-day/ )
 
     # parse the URL into its components
-    parsed = urlparse.urlsplit(url)
+    parsed = urllib.parse.urlsplit(url)
     scheme, netloc, path, query, fragment = parsed
 
     # ensure scheme is a letter followed by letters, digits, and '+-.' chars
@@ -376,16 +376,16 @@ def fixurl(url):
     # ensure path is valid and convert Unicode chars to %-encoded
     if not path:
         path = '/'  # eg: 'http://google.com' -> 'http://google.com/'
-    path = urllib.quote(urllib.unquote(path.encode('utf-8')), safe='/;')
+    path = urllib.parse.quote(urllib.parse.unquote(path.encode('utf-8')), safe='/;')
 
     # ensure query is valid
-    query = urllib.quote(urllib.unquote(query.encode('utf-8')), safe='=&?/')
+    query = urllib.parse.quote(urllib.parse.unquote(query.encode('utf-8')), safe='=&?/')
 
     # ensure fragment is valid
-    fragment = urllib.quote(urllib.unquote(fragment.encode('utf-8')))
+    fragment = urllib.parse.quote(urllib.parse.unquote(fragment.encode('utf-8')))
 
     # piece it all back together, truncating it to a maximum of 4KB
-    url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
+    url = urllib.parse.urlunsplit((scheme, netloc, path, query, fragment))
     return url[:4096]
 
 # ex:ts=4:et:
diff --git a/latex/job.py b/latex/job.py
index 7e37a28..de65768 100644
--- a/latex/job.py
+++ b/latex/job.py
@@ -112,7 +112,7 @@ class Job(object):
         self.__exception = None
         try:
             returned = self._run(argument)
-        except Exception, e:
+        except Exception as e:
             self.__log.error(e)
             self.__exception = e
 
diff --git a/latex/latex/cache.py b/latex/latex/cache.py
index 72dc558..47faabe 100644
--- a/latex/latex/cache.py
+++ b/latex/latex/cache.py
@@ -26,7 +26,7 @@ Cache for LaTeX document models for speeding up reference expanding
 
 from logging import getLogger
 
-from parser import LaTeXParser
+from .parser import LaTeXParser
 from ..issues import IIssueHandler
 
 
diff --git a/latex/latex/completion.py b/latex/latex/completion.py
index 3e4a5d9..757beb6 100644
--- a/latex/latex/completion.py
+++ b/latex/latex/completion.py
@@ -96,8 +96,8 @@ class LaTeXChoiceProposal(Proposal):
         return self._overlap
 
 
-from model import LanguageModelFactory, Choice, MandatoryArgument, OptionalArgument
-from parser import PrefixParser, Node
+from .model import LanguageModelFactory, Choice, MandatoryArgument, OptionalArgument
+from .parser import PrefixParser, Node
 
 from ..bibtex.cache import BibTeXDocumentCache
 
@@ -213,7 +213,7 @@ class LaTeXCompletionHandler(ICompletionHandler):
 
             return proposals
 
-        except Exception, e:
+        except Exception as e:
             self._log.debug(e)
 
         return []
@@ -308,7 +308,7 @@ class PrefixModelParser(object):
 
             if len(commandName) == 0:
                 # no name, so propose all commands
-                commands = self.__language_model.commands.values()
+                commands = list(self.__language_model.commands.values())
                 overlap = 1        # only "\"
             else:
                 commands = self.__language_model.find_command(commandName)
@@ -333,7 +333,7 @@ class PrefixModelParser(object):
 
             try:
                 argumentNode, storedArgument = self.__match_argument(commandNode, storedCommand)
-            except Exception, e:
+            except Exception as e:
                 self._log.error(e)
                 return []
 
diff --git a/latex/latex/dialogs.py b/latex/latex/dialogs.py
index a1a0d00..f846dae 100644
--- a/latex/latex/dialogs.py
+++ b/latex/latex/dialogs.py
@@ -376,7 +376,7 @@ class NewDocumentDialog(GladeInterface):
 
             try:
                 self._proxy_babel.restore(self._LOCALE_MAPPINGS[environment.language_code])
-            except Exception, e:
+            except Exception as e:
                 self._log.error("Failed to guess babel package: %s" % e)
                 self._proxy_babel.restore("english")
 
diff --git a/latex/latex/editor.py b/latex/latex/editor.py
index be5fe12..33d1dff 100644
--- a/latex/latex/editor.py
+++ b/latex/latex/editor.py
@@ -33,13 +33,13 @@ from ..editor import Editor
 from ..file import File
 from ..issues import Issue, IIssueHandler
 
-from parser import LaTeXParser
-from expander import LaTeXReferenceExpander
-from outline import LaTeXOutlineGenerator
-from validator import LaTeXValidator
-from completion import LaTeXCompletionHandler
+from .parser import LaTeXParser
+from .expander import LaTeXReferenceExpander
+from .outline import LaTeXOutlineGenerator
+from .validator import LaTeXValidator
+from .completion import LaTeXCompletionHandler
 
-from dialogs import ChooseMasterDialog
+from .dialogs import ChooseMasterDialog
 
 from . import LaTeXSource
 from ..preferences import Preferences, DocumentPreferences
@@ -137,7 +137,7 @@ class LaTeXEditor(Editor, IIssueHandler):
         """
         Insert source at a certain position in the LaTeX document:
 
-         * POSITION_PACKAGES: after the last \usepackage statement
+         * POSITION_PACKAGES: after the last usepackage statement
          * POSITION_BIBLIOGRAPHY: before \end{document}
 
         @param source: a LaTeXSource object
diff --git a/latex/latex/environment.py b/latex/latex/environment.py
index 6211c21..548b5a9 100644
--- a/latex/latex/environment.py
+++ b/latex/latex/environment.py
@@ -323,7 +323,7 @@ class Environment(object):
             # no files found
             self._log.error("No %s-files found in %s%s" % (extension, search_path, relative))
 
-        for name, label in labels.iteritems():
+        for name, label in labels.items():
             found = False
             for resource in resources:
                 if resource.name == name:
diff --git a/latex/latex/expander.py b/latex/latex/expander.py
index 2d4c256..a02c399 100644
--- a/latex/latex/expander.py
+++ b/latex/latex/expander.py
@@ -25,8 +25,8 @@ latex.expander
 from logging import getLogger
 
 from ..file import File
-from cache import LaTeXDocumentCache
-from parser import Node
+from .cache import LaTeXDocumentCache
+from .parser import Node
 
 
 class LaTeXReferenceExpander(object):
diff --git a/latex/latex/lexer.py b/latex/latex/lexer.py
index 4cb1455..0325102 100644
--- a/latex/latex/lexer.py
+++ b/latex/latex/lexer.py
@@ -68,7 +68,7 @@ class Token(object):
     A Token returned by the Lexer
     """
 
-    COMMAND, TEXT, COMMENT, VERBATIM, BEGIN_CURLY, END_CURLY, BEGIN_SQUARE, END_SQUARE = range(8)
+    COMMAND, TEXT, COMMENT, VERBATIM, BEGIN_CURLY, END_CURLY, BEGIN_SQUARE, END_SQUARE = list(range(8))
 
     def __init__(self, type, offset=None, value=None):
         self.type = type
@@ -97,7 +97,7 @@ class Lexer(object):
     # TODO: redesign and optimize this from a DFA
 
     # states of the lexer
-    _DEFAULT, _BACKSLASH, _COMMAND, _TEXT, _COMMENT, _PRE_VERB, _VERB, _VERBATIM = range(8)
+    _DEFAULT, _BACKSLASH, _COMMAND, _TEXT, _COMMENT, _PRE_VERB, _VERB, _VERBATIM = list(range(8))
 
     _SPECIAL = set(["&", "$", "{", "}", "[", "]", "%", "#", "_", "\\"])
 
@@ -109,7 +109,7 @@ class Lexer(object):
 
 
     # additional states for recognizing "\begin{verbatim}"
-    _VERBATIM_DEFAULT, _VERBATIM_BEGIN, _VERBATIM_BEGIN_CURLY, _VERBATIM_BEGIN_CURLY_ENVIRON = range(4)
+    _VERBATIM_DEFAULT, _VERBATIM_BEGIN, _VERBATIM_BEGIN_CURLY, _VERBATIM_BEGIN_CURLY_ENVIRON = list(range(4))
 
 
     def __init__(self, string, skipWs=True, skipComment=False):
@@ -127,7 +127,7 @@ class Lexer(object):
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         if self._eof:
             raise StopIteration
 
diff --git a/latex/latex/model.py b/latex/latex/model.py
index 50f5b52..2c85190 100644
--- a/latex/latex/model.py
+++ b/latex/latex/model.py
@@ -152,7 +152,7 @@ class LanguageModel(object):
         """
         Find a command by a prefix. A prefix like 'be' would return the command '\begin'
         """
-        return [command for name, command in self.commands.iteritems() if name.startswith(prefix)]
+        return [command for name, command in self.commands.items() if name.startswith(prefix)]
 
     def register_placeholder(self, placeholder):
         """
@@ -303,7 +303,7 @@ class LanguageModelFactory(object):
                 parser = LanguageModelParser()
                 parser.parse(xml_filename, self.language_model)
 
-                pickle.dump(self.language_model, open(pkl_filename, 'w'))
+                pickle.dump(self.language_model, open(pkl_filename, 'wb'))
                 LOG.info("Pickling language model")
 
             self._ready = True
diff --git a/latex/latex/outline.py b/latex/latex/outline.py
index 8fcdc67..0dfc569 100644
--- a/latex/latex/outline.py
+++ b/latex/latex/outline.py
@@ -24,13 +24,13 @@ latex.outline
 
 from logging import getLogger
 
-from parser import Node
+from .parser import Node
 from ..issues import Issue
 
 
 class OutlineNode(list):
 
-    ROOT, STRUCTURE, LABEL, NEWCOMMAND, REFERENCE, GRAPHICS, PACKAGE, TABLE, NEWENVIRONMENT = range(9)
+    ROOT, STRUCTURE, LABEL, NEWCOMMAND, REFERENCE, GRAPHICS, PACKAGE, TABLE, NEWENVIRONMENT = list(range(9))
 
     def __init__(self, type, start=None, end=None, value=None, level=None, foreign=False, numOfArgs=None, file=None, **kwargs):
         """
@@ -133,7 +133,7 @@ class LaTeXOutlineGenerator(object):
 #            if node.type == Node.DOCUMENT:
 #                self._file = node.value
             if node.type == Node.COMMAND:
-                if node.value in self._STRUCTURE_LEVELS.keys():
+                if node.value in list(self._STRUCTURE_LEVELS.keys()):
                     try:
                         headline = node.firstOfType(Node.MANDATORY_ARGUMENT).innerMarkup
                         level = self._STRUCTURE_LEVELS[node.value]
@@ -151,7 +151,7 @@ class LaTeXOutlineGenerator(object):
                     try:
                         value = node.firstOfType(Node.MANDATORY_ARGUMENT).innerText
 
-                        if value in self._labelCache.keys():
+                        if value in list(self._labelCache.keys()):
                             start, end = self._labelCache[value]
                             issue_handler.issue(Issue("Label <b>%s</b> has already been defined" % value, start, end, node.file, Issue.SEVERITY_ERROR))
                         else:
diff --git a/latex/latex/parser.py b/latex/latex/parser.py
index 534de5c..a9de5b9 100644
--- a/latex/latex/parser.py
+++ b/latex/latex/parser.py
@@ -35,7 +35,7 @@ class Node(list):
     This is the base class of the LaTeX object model
     """
 
-    DOCUMENT, COMMAND, MANDATORY_ARGUMENT, OPTIONAL_ARGUMENT, TEXT, EMBRACED = range(6)
+    DOCUMENT, COMMAND, MANDATORY_ARGUMENT, OPTIONAL_ARGUMENT, TEXT, EMBRACED = list(range(6))
 
     def __init__(self, type, value=None):
         self.type = type
@@ -265,7 +265,7 @@ class Document(Node):
     @property
     def end_of_packages(self):
         """
-        Return the offset right after the last \usepackage
+        Return the offset right after the last usepackage
 
         used by LaTeXEditor.insert_at_position
         """
@@ -311,7 +311,7 @@ class FatalParseException(Exception):
     """
 
 
-from lexer import Lexer, Token
+from .lexer import Lexer, Token
 
 
 class LaTeXParser(object):
diff --git a/latex/latex/preview.py b/latex/latex/preview.py
index b3c2555..b936e9e 100644
--- a/latex/latex/preview.py
+++ b/latex/latex/preview.py
@@ -26,7 +26,7 @@ from ..file import File
 from ..tools import Tool, Job, ToolRunner
 from ..tools.postprocess import RubberPostProcessor, GenericPostProcessor
 from ..issues import MockStructuredIssueHandler
-from environment import Environment
+from .environment import Environment
 
 from gi.repository import GdkPixbuf
 
diff --git a/latex/latex/validator.py b/latex/latex/validator.py
index cc3fafe..063323b 100644
--- a/latex/latex/validator.py
+++ b/latex/latex/validator.py
@@ -30,9 +30,9 @@ from ..file import File
 from ..issues import Issue
 from ..util import escape
 
-from parser import Node
-from environment import Environment
-from model import LanguageModelFactory
+from .parser import Node
+from .environment import Environment
+from .model import LanguageModelFactory
 
 LOG = getLogger(__name__)
 
diff --git a/latex/latex/views.py b/latex/latex/views.py
index 2d3b000..e4e88ce 100644
--- a/latex/latex/views.py
+++ b/latex/latex/views.py
@@ -36,7 +36,7 @@ from ..file import File
 from ..resources import Resources
 from ..snippetmanager import SnippetManager
 from ..outline import OutlineOffsetMap, BaseOutlineView
-from outline import OutlineNode
+from .outline import OutlineNode
 from ..gldefs import _
 
 LOG = logging.getLogger(__name__)
diff --git a/latex/outline.py b/latex/outline.py
index 42c5a35..97ec73d 100644
--- a/latex/outline.py
+++ b/latex/outline.py
@@ -28,10 +28,10 @@ import logging
 
 from gi.repository import Gtk, GdkPixbuf
 
-from panelview import PanelView
-from preferences import Preferences
-from resources import Resources
-from gldefs import _
+from .panelview import PanelView
+from .preferences import Preferences
+from .resources import Resources
+from .gldefs import _
 
 LOG = logging.getLogger(__name__)
 
@@ -262,7 +262,7 @@ class OutlineOffsetMap(object):
         """
 
         # sort offsets
-        offsets = self._map.keys()
+        offsets = list(self._map.keys())
         offsets.sort()
 
         # find nearest offset
@@ -280,7 +280,7 @@ class OutlineOffsetMap(object):
     def __str__(self):
         s = "<OutlineOffsetMap>"
 
-        ofs = self._map.keys()
+        ofs = list(self._map.keys())
         ofs.sort()
 
         for o in ofs:
diff --git a/latex/preferences/__init__.py b/latex/preferences/__init__.py
index 45cf090..9996e9a 100644
--- a/latex/preferences/__init__.py
+++ b/latex/preferences/__init__.py
@@ -27,29 +27,29 @@ from gi.repository import GObject, Gio, GLib
 import re
 import os.path
 import logging
-import ConfigParser
+import configparser
 
 from ..util import singleton
 
 LOG = logging.getLogger(__name__)
 
-class _DocumentConfigParser(ConfigParser.RawConfigParser):
+class _DocumentConfigParser(configparser.RawConfigParser):
 
     SECTION = "LATEX"
 
     def __init__(self, filename):
-        ConfigParser.RawConfigParser.__init__(self)
+        configparser.RawConfigParser.__init__(self)
         self._filename = filename
         self.read(filename)
         try:
             self.add_section(self.SECTION)
-        except ConfigParser.DuplicateSectionError:
+        except configparser.DuplicateSectionError:
             pass
 
     def __getitem__(self, key):
         try:
-            return ConfigParser.RawConfigParser.get(self,self.SECTION, key)
-        except ConfigParser.NoOptionError:
+            return configparser.RawConfigParser.get(self,self.SECTION, key)
+        except configparser.NoOptionError:
             raise KeyError
 
     def get(self, key, default=None):
@@ -59,7 +59,7 @@ class _DocumentConfigParser(ConfigParser.RawConfigParser):
             return default
 
     def set(self, key, value):
-        ConfigParser.RawConfigParser.set(self, self.SECTION, key, value)
+        configparser.RawConfigParser.set(self, self.SECTION, key, value)
 
     def save(self):
         f = open(self._filename,'w')
diff --git a/latex/preferences/dialog.py b/latex/preferences/dialog.py
index 04ab2db..61103e4 100644
--- a/latex/preferences/dialog.py
+++ b/latex/preferences/dialog.py
@@ -158,7 +158,7 @@ class ConfigureToolDialog(GladeInterface):
             commandRenderer.connect("edited", self._on_job_command_edited)
 
             self._store_pp = Gtk.ListStore(str)
-            for p in self._tool_preferences.POST_PROCESSORS.iterkeys():
+            for p in self._tool_preferences.POST_PROCESSORS.keys():
                 self._store_pp.append([p])
 
             ppRenderer = Gtk.CellRendererCombo()
diff --git a/latex/preferences/tools.py b/latex/preferences/tools.py
index 62357ab..f50b819 100644
--- a/latex/preferences/tools.py
+++ b/latex/preferences/tools.py
@@ -38,7 +38,7 @@ def str_to_bool(x):
     """
     if type(x) is bool:
         return x
-    elif type(x) is str or type(x) is unicode:
+    elif type(x) is str or type(x) is str:
         try:
             return {"false" : False, "0" : False, "true" : True, "1" : True}[x.strip().lower()]
         except KeyError:
@@ -129,7 +129,7 @@ class ToolPreferences(GObject.GObject):
             # create new tool tag
             LOG.debug("Creating new Tool...")
 
-            id = unicode(uuid.uuid4())
+            id = str(uuid.uuid4())
             self.__tool_ids[tool] = id
 
             tool_element = ElementTree.SubElement(self.__tools, "tool")
@@ -139,7 +139,7 @@ class ToolPreferences(GObject.GObject):
         tool_element.set("description", tool.description)
         tool_element.set("extensions", " ".join(tool.extensions))
         if tool.accelerator is None:
-            if "accelerator" in tool_element.attrib.keys():
+            if "accelerator" in list(tool_element.attrib.keys()):
                 del tool_element.attrib["accelerator"]
         else:
             tool_element.set("accelerator", tool.accelerator)
@@ -221,7 +221,7 @@ class ToolPreferences(GObject.GObject):
             del self.__tool_ids[tool]
 
             self.__tools_changed = True
-        except KeyError, e:
+        except KeyError as e:
             LOG.error("delete_tool: %s" % e)
 
         self.__notify_tools_changed()
diff --git a/latex/resources.py b/latex/resources.py
index a973268..ac8753b 100644
--- a/latex/resources.py
+++ b/latex/resources.py
@@ -26,7 +26,7 @@ resources
 import logging
 import os.path
 import errno
-from singleton import Singleton
+from .singleton import Singleton
 
 _log = logging.getLogger("resources")
 
@@ -41,7 +41,7 @@ class Resources(Singleton):
         # Make sure dir exists
         try:
             os.makedirs(userdir)
-        except OSError, e:
+        except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
 
diff --git a/latex/snippetmanager.py b/latex/snippetmanager.py
index 3f14c01..98d06a4 100644
--- a/latex/snippetmanager.py
+++ b/latex/snippetmanager.py
@@ -17,7 +17,7 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330,
 #  Boston, MA 02111-1307, USA.
 
-from singleton import Singleton
+from .singleton import Singleton
 import logging
 
 LOG = logging.getLogger(__name__)
diff --git a/latex/tools/__init__.py b/latex/tools/__init__.py
index 8ffbcd4..389c449 100644
--- a/latex/tools/__init__.py
+++ b/latex/tools/__init__.py
@@ -139,7 +139,7 @@ class ToolAction(Action):
 
 
 from os import chdir
-from util import Process
+from .util import Process
 from string import Template
 
 
@@ -182,7 +182,7 @@ class ToolRunner(Process):
 
     def __proceed(self):
         try:
-            self._job = self._job_iter.next()
+            self._job = next(self._job_iter)
 
             command_template = Template(self._job.command_template)
             command = command_template.safe_substitute({"filename" : self._file.path,
diff --git a/latex/tools/util.py b/latex/tools/util.py
index e994aa8..2775ff7 100644
--- a/latex/tools/util.py
+++ b/latex/tools/util.py
@@ -68,14 +68,14 @@ class Process(object):
                 os.kill(self.__process.pid, signal.SIGTERM)
 
                 self._on_abort()
-            except OSError, e:
+            except OSError as e:
                 LOG.error("Failed to abort process: %s" % e)
 
     def __on_stdout(self):
         try:
             s = self.__process.stdout.read()
-            if len(s):
-                self._on_stdout(s)
+            if s != None:
+                self._on_stdout(s.decode())
         except IOError:
             pass
         return True
@@ -83,8 +83,8 @@ class Process(object):
     def __on_stderr(self):
         try:
             s = self.__process.stderr.read()
-            if len(s):
-                self._on_stderr(s)
+            if s != None:
+                self._on_stderr(s.decode())
         except IOError:
             pass
         return True
diff --git a/latex/util.py b/latex/util.py
index 1b56ff1..410f609 100644
--- a/latex/util.py
+++ b/latex/util.py
@@ -61,7 +61,7 @@ class StringReader(object):
             return self._pushbackChar
         else:
             self.offset += 1
-            return self._iter.next()
+            return next(self._iter)
 
     def unread(self, char):
         #assert not self._pushbackFlag
@@ -113,7 +113,7 @@ def verbose(function):
     def decorated_function(*args, **kw):
         try:
             return function(*args, **kw)
-        except Exception, e:
+        except Exception as e:
             stack = traceback.format_exc(limit=10)
             open_error(str(e), stack)
     return decorated_function
diff --git a/latex/views.py b/latex/views.py
index de8c5af..07bb377 100644
--- a/latex/views.py
+++ b/latex/views.py
@@ -25,12 +25,12 @@ views
 from gi.repository import Gtk, GdkPixbuf
 from logging import getLogger
 
-from preferences import Preferences
-from resources import Resources
-from panelview import PanelView
-from issues import Issue
-from util import escape
-from gldefs import _
+from .preferences import Preferences
+from .resources import Resources
+from .panelview import PanelView
+from .issues import Issue
+from .util import escape
+from .gldefs import _
 
 
 class IssueView(PanelView):
diff --git a/latex/windowactivatable.py b/latex/windowactivatable.py
index 8ad3803..17ef0c9 100644
--- a/latex/windowactivatable.py
+++ b/latex/windowactivatable.py
@@ -179,7 +179,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
             self._action_objects[clazz.__name__] = action
 
             for extension in action.extensions:
-                if extension in self._action_extensions.keys():
+                if extension in list(self._action_extensions.keys()):
                     self._action_extensions[extension].append(clazz.__name__)
                 else:
                     self._action_extensions[extension] = [clazz.__name__]
@@ -320,7 +320,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 
         @param file: a File object
         """
-        for tab, tab_decorator in self._tab_decorators.iteritems():
+        for tab, tab_decorator in self._tab_decorators.items():
             if tab_decorator.file and tab_decorator.file == file:
                 self.window.set_active_tab(tab)
                 return
@@ -346,11 +346,11 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
             self._toolbar.hide()
 
         # disable all actions
-        for name in self._action_objects.iterkeys():
+        for name in self._action_objects.keys():
             self._action_group.get_action(name).set_visible(False)
 
         # disable all tool actions
-        for l in self._tool_action_extensions.values():
+        for l in list(self._tool_action_extensions.values()):
             for name in l:
                 self._tool_action_group.get_action(name).set_sensitive(False)
 
@@ -386,7 +386,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
             self._action_group.get_action(name).set_visible(False)
 
         # disable all tool actions
-        for l in self._tool_action_extensions.values():
+        for l in list(self._tool_action_extensions.values()):
             for name in l:
                 self._tool_action_group.get_action(name).set_sensitive(False)
 
@@ -428,7 +428,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 
         if tab_decorator.editor:
             editor_views = self._window_context.editor_views[tab_decorator.editor]
-            for id, view in editor_views.iteritems():
+            for id, view in editor_views.items():
                 if isinstance(view, PanelView):
                     if view.get_orientation() == Gtk.Orientation.HORIZONTAL:
                         bottom_views.append(view)
@@ -514,7 +514,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
         """
         LOG.debug("active_tab_changed")
 
-        if tab in self._tab_decorators.keys():
+        if tab in list(self._tab_decorators.keys()):
             decorator = self._tab_decorators[tab]
         else:
             # (on Gedit startup 'tab-changed' comes before 'tab-added')
diff --git a/latex/windowcontext.py b/latex/windowcontext.py
index da0a44f..8e506ea 100644
--- a/latex/windowcontext.py
+++ b/latex/windowcontext.py
@@ -60,7 +60,7 @@ class WindowContext(object):
         """
         self.editor_views[editor] = {}
         try:
-            for id, clazz in self._editor_view_classes[file.extension].iteritems():
+            for id, clazz in self._editor_view_classes[file.extension].items():
                 # create View instance and add it to the map
                 self.editor_views[editor][id] = clazz(self, editor)
 
@@ -99,7 +99,7 @@ class WindowContext(object):
         except KeyError:
             LOG.critical("Unknown view id: %s (we have: %s)" % (
                     view_id,
-                    ",".join(self.editor_views.get(editor,{}).keys())))
+                    ",".join(list(self.editor_views.get(editor,{}).keys()))))
 
     def set_action_enabled(self, action_id, enabled):
         """
