diff --git a/CHANGES.txt b/CHANGES.txt
index 7c081329c77e3c3edf509c97efc8ae1583a305e2..d39d7c77ce5abfe4cca7bf90015beffec1d7da22 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -6,13 +6,13 @@ Make Experiments!
 Release Changes
 ---------------
 
-Milestone 1.1.1
-===============
+Release 1.1.1
+=============
 
 Global
 ------
 
-* TODO: Porting to python3
+* Updated code to run with python3 and full Unicode set
 
 Configuration
 -------------
diff --git a/Makefile b/Makefile
index a0df22993833a4903b9af775552fd38d53567847..d58d87f44592cdac3832c0448632ac1acce7de4e 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ distclean: clean
 doc: doc/mkexp.pdf
 
 check:
-	$(PYTHON) test.py -v
+	PYTHON=$(PYTHON) $(PYTHON) test.py -v
 
 dist: doc
 	$(PYTHON) setup.py sdist
diff --git a/doc/mkexp.fodt b/doc/mkexp.fodt
index 442e625b319009e93fc063efcd1ae2aae9878f4d..56ab80a9895d76d7202f255f17ae4e881b3ef946 100644
--- a/doc/mkexp.fodt
+++ b/doc/mkexp.fodt
@@ -2708,7 +2708,7 @@
    </text:sequence-decls>
    <text:p text:style-name="P349">Make Experiments!</text:p>
    <text:p text:style-name="P338">Run-script generation for earth system models</text:p>
-   <text:p text:style-name="P339">Release 1.1.1rc2</text:p>
+   <text:p text:style-name="P339">Release 1.1.1</text:p>
    <text:p text:style-name="P312">Karl-Hermann Wieners<text:line-break/><text:span text:style-name="T274">Max-Planck-Institut für Meteorologie<text:line-break/>Hamburg</text:span></text:p>
    <text:table-of-content text:style-name="Sect1" text:protected="true" text:name="Table of Contents1">
     <text:table-of-content-source text:outline-level="10">
@@ -3461,4 +3461,4 @@
    <text:p text:style-name="P47"><text:span text:style-name="T140">This</text:span><text:span text:style-name="T148"> will result in a &apos;.run_first&apos; </text:span><text:span text:style-name="T149">script</text:span><text:span text:style-name="T148"> tha</text:span><text:span text:style-name="T149">t gets the model state from &apos;anotherexp&apos;, while the &apos;.run&apos; script</text:span><text:span text:style-name="T148"> </text:span><text:span text:style-name="T149">uses &apos;myexp&apos;.</text:span></text:p>
   </office:text>
  </office:body>
-</office:document>
\ No newline at end of file
+</office:document>
diff --git a/doc/mkexp.pdf b/doc/mkexp.pdf
index a836f8f9afab24a22b0be11c38299bcb0eb70d5c..a126a268b522063dc6931389b2c0cc6bd0fed16a 100644
Binary files a/doc/mkexp.pdf and b/doc/mkexp.pdf differ
diff --git a/expargparse.py b/expargparse.py
index dc49f87c075fd0be784d67ebb3f672537211e7c3..a73c05132e5f45e69a6eedb28f4d1ea835e3e1cd 100644
--- a/expargparse.py
+++ b/expargparse.py
@@ -63,5 +63,5 @@ def assigns_to_dicts(args):
             current = {key: current}
         return current
 
-    return map(assign_to_dict, args.assigns)
+    return list(map(assign_to_dict, args.assigns))
 
diff --git a/expconfig.py b/expconfig.py
index e12156c6a87b2f68c3a012d219d4be837e6e5e5f..0c34c31c7ebe2a36ff9fc6d563273e1a795f6e08 100644
--- a/expconfig.py
+++ b/expconfig.py
@@ -4,9 +4,10 @@ Generate an earth system model configuration from the given configuration file.
 $Id$
 '''
 
+import io
+import locale
 import os
 import re
-import StringIO
 import time # for 'eval' context only
 
 from itertools import dropwhile
@@ -18,16 +19,24 @@ import feedback
 
 # Utilities used for config and templates
 
+_preferred_encoding = locale.getpreferredencoding()
+    
 # - Check a namelist logical
 def is_set(s):
     if not s:
         return False
     return s.strip('.').lower().startswith('t')
 
-
 class ConfigObj(configobj.ConfigObj):
 
     def __init__(self, *args, **kwargs):
+        default_args = {
+            'encoding': _preferred_encoding,
+            'default_encoding': _preferred_encoding,
+        }
+        for kw in default_args:
+            if not kw in kwargs:
+                kwargs[kw] = default_args[kw]
         configobj.ConfigObj.__init__(self, *args, **kwargs)
 
     def merge(self, indict):
@@ -35,10 +44,10 @@ class ConfigObj(configobj.ConfigObj):
         def is_not_empty(arg):
             if arg is None:
                 return None
-            elif isinstance(arg, basestring):
+            elif not isinstance(arg, (list, tuple)):
                 return arg.rstrip()
             else:
-                return filter(None, map(lambda x: x.rstrip(), arg))
+                return [_f for _f in [x.rstrip() for x in arg] if _f]
 
         def merge_comments(this, indict):
             '''Merge comments from indict into current configuration. 
@@ -108,7 +117,7 @@ class ExpConfig(ConfigObj):
             '''Post-process job definition to allow for shared configs as [[job1, job2]]'''
             if 'jobs' in config:
                 sep = re.compile(r'\s*,\s*')
-                for subjobs, subconfig in config['jobs'].iteritems():
+                for subjobs, subconfig in config['jobs'].items():
                     if re.search(sep, subjobs):
                         for subjob in re.split(sep, subjobs):
                             if subjob in config['jobs']:
@@ -164,7 +173,7 @@ class ExpConfig(ConfigObj):
         def add_years(value, years):
             '''Add specified number of years (possible negative) to date'''
             years = int(years)
-            dt = map(int, split_date(value))
+            dt = list(map(int, split_date(value)))
             dt[0] += years
             return "{0:+05}-{1:02}-{2:02}".format(*dt).lstrip('+')
 
@@ -203,7 +212,7 @@ class ExpConfig(ConfigObj):
                 return (year, mon, day)
 
             days = int(days)
-            dt = map(int, split_date(value))
+            dt = list(map(int, split_date(value)))
             dt = add_days_(dt[0], dt[1], dt[2], days)
             return "{0:+05}-{1:02}-{2:02}".format(*dt).lstrip('+')
 
@@ -214,7 +223,7 @@ class ExpConfig(ConfigObj):
             '''
             result = eval(value)
             if isinstance(result, (list, tuple)):
-                result = map(str, result)
+                result = list(map(str, result))
             else:
                 result = str(result)
             return result
@@ -267,12 +276,12 @@ class ExpConfig(ConfigObj):
             try:
                 value = section[key]
                 if isinstance(value, (list, tuple)):
-                    value = map(eval_expression, value)
-                elif isinstance(value, basestring):
+                    value = list(map(eval_expression, value))
+                elif not isinstance(value, dict):
                     value = eval_expression(value)
                 if isinstance(value, (list, tuple)):
                     value = [v.replace('$', '$$') for v in value]
-                elif isinstance(value, basestring):
+                elif not isinstance(value, dict):
                     value = value.replace('$', '$$')
             except (InterpolationError, ValueError) as error:
                 raise ExpConfigError(error.message, key)
@@ -284,7 +293,7 @@ class ExpConfig(ConfigObj):
                 value = section[key]
                 if isinstance(value, (list, tuple)):
                     value = [v.replace('$$', '$') for v in value]
-                elif isinstance(value, basestring):
+                elif not isinstance(value, dict):
                     value = value.replace('$$', '$')
             except (InterpolationError, ValueError) as error:
                 raise ExpConfigError(error.message, key)
@@ -323,7 +332,7 @@ class ExpConfig(ConfigObj):
         setup_options = extra_dict.get('SETUP_OPTIONS',
                         pre_config.get('SETUP_OPTIONS',
                         ''))
-        if isinstance(setup_options, basestring):
+        if not isinstance(setup_options, (list, tuple)):
             if setup_options:
                 setup_options = [setup_options]
             else:
@@ -331,7 +340,7 @@ class ExpConfig(ConfigObj):
         exp_options = extra_dict.get('EXP_OPTIONS',
                       pre_config.get('EXP_OPTIONS',
                       ''))
-        if isinstance(exp_options, basestring):
+        if not isinstance(exp_options, (list, tuple)):
             if exp_options:
                 exp_options = [exp_options]
             else:
@@ -364,10 +373,10 @@ class ExpConfig(ConfigObj):
         env_dict = dict(os.environ)
         if not getexp:
             # Mask literal dollar characters
-            for key, value in env_dict.iteritems():
+            for key, value in env_dict.items():
                 env_dict[key] = value.replace('$', '$$')
         pre_config.merge({'DEFAULT': {}})
-        for key, value in sorted(env_dict.iteritems()):
+        for key, value in sorted(env_dict.items()):
             pre_config['DEFAULT'][key] = value
 
         # Read experiment settings from library (default and type specific)
@@ -438,18 +447,18 @@ class ExpConfig(ConfigObj):
         # This works around incomprehensible inheritance of interpolation with
         # merge. Make sure that all values are interpolated
 
-        config_lines = StringIO.StringIO()
+        config_lines = io.BytesIO()
 
         pre_config.write(config_lines)
         pre_config = None
 
         config_lines.seek(0)
-        pre_config = ConfigObj(config_lines,
+        pre_config = ConfigObj(io.TextIOWrapper(config_lines),
                                interpolation=False if getexp else 'template')
 
         # Extract experiment description from initial comment
         # if not set explicitly
-        if not pre_config.has_key('EXP_DESCRIPTION'):
+        if 'EXP_DESCRIPTION' not in pre_config:
             is_empty = lambda s: re.match(r'^[\s#]*$', s)
             rm_comment = lambda s: re.sub(r'^\s*# ?', '', s)       
             pre_config['EXP_DESCRIPTION'] = "\n".join(
@@ -457,8 +466,8 @@ class ExpConfig(ConfigObj):
                     dropwhile(is_empty,
                         reversed(list(
                             dropwhile(is_empty,
-                                map(rm_comment,
-                                    experiment_config.initial_comment)
+                                list(map(rm_comment,
+                                    experiment_config.initial_comment))
                             )
                         )) 
                     )
@@ -470,14 +479,14 @@ class ExpConfig(ConfigObj):
         # Re-read final config without interpolation.
         # This allows copying data without evaluation of version keywords.
 
-        config_lines.seek(0)
-        config_lines.truncate()
-
+        config_lines = io.BytesIO()
+        
         pre_config.write(config_lines)
         pre_config = None
 
         config_lines.seek(0)
-        ConfigObj.__init__(self, config_lines, interpolation=False)
+        ConfigObj.__init__(self, io.TextIOWrapper(config_lines),
+                           interpolation=False)
         self.walk(uneval_key)
         
         self.experiment_id = self[ExpConfig.id_name]
diff --git a/getconfig b/getconfig
index b964230e5135fb23c75d53482c93ccf59a21a834..4b67f900eb4fc16f13961cedeeb2b557b65c2fd1 100755
--- a/getconfig
+++ b/getconfig
@@ -5,10 +5,13 @@
 # $Id$
 #
 
+from __future__ import print_function
+
 import argparse
+import io
 import sys
 
-from configobj import ConfigObj
+from expconfig import ConfigObj
 
 import update
 from feedback import die
@@ -39,5 +42,12 @@ config_data = ConfigObj(update_data.get_config_file(), interpolation=False,
 for d in update_data.get_config_dicts():
     config_data.merge(d)
 
-config_data.write(sys.stdout)
+# Ready to roll out
+
+lines = io.BytesIO()
+config_data.write(lines)
+
+lines.seek(0)
+for line in io.TextIOWrapper(lines):
+    print(line, end='')
 
diff --git a/getexp b/getexp
index c704fa1c2a73f676508f161d4faf368a539d59a9..18ba8877aae14e35a424790e5a5835ba47081ef2 100755
--- a/getexp
+++ b/getexp
@@ -5,7 +5,10 @@
 # $Id$
 #
 
+from __future__ import print_function
+
 import argparse
+import io
 import os
 import sys
 
@@ -72,7 +75,7 @@ if not os.path.exists(experiment_config_name):
     die("config file '{0}' does not exist".format(experiment_config_name))
 
 # Overrides
-invalid_args = filter(lambda x: not x.find('=')+1, args.assigns)
+invalid_args = [x for x in args.assigns if not x.find('=')+1]
 
 if invalid_args:
     die("invalid parameters ('"+"', '".join(invalid_args)+"')\n" +
@@ -82,12 +85,12 @@ if invalid_args:
 # Store environment as default for control settings, then add config from files
 
 # Hack to allow use in diffexp
-if os.environ.has_key('DIFF'):
+if 'DIFF' in os.environ:
     del os.environ['DIFF']
 
 try:
     config = ExpConfig(experiment_config_name,
-                       dict(map(lambda x: x.split('=', 1), args.assigns)),
+                       dict([x.split('=', 1) for x in args.assigns]),
                        config_roots)
 except ExpConfigError as error:
     die(error.message, status=2)
@@ -105,13 +108,17 @@ elif args.key:
         die("invalid config name '{0}'".format(error.message))
 elif args.verbose >= 2:
     config.indent_type = '  '
-    config.write(sys.stdout)
+    lines = io.BytesIO()
+    config.write(lines)
+    lines.seek(0)
+    for line in io.TextIOWrapper(lines):
+        print(line, end='')
 elif args.verbose == 1:
-    items = config.items()
-    items.sort(key=lambda x: x[0])
-    for (key, value) in items:
-        if not isinstance(value, dict):
-            print("{0}='{1}'".format(key, str(value).replace("'",'"')))
+    for key in sorted(config.scalars):
+        value = config[key]
+        if isinstance(value, (list, tuple)):
+            value = u'"{0}"'.format(u'" "'.join(value))
+        print(u"{0}='{1}'".format(key, value.replace("'",'"')))
 else:
     print("EXP_ID='{0}'".format(config.experiment_id))
     print("MODEL_DIR='{0}'".format(config['MODEL_DIR']))
diff --git a/mkexp b/mkexp
index 18740082caabc83ee5a179f0596f699763eb942c..de30beeffa8b88d8b1e506eff72e2270234e60c0 100755
--- a/mkexp
+++ b/mkexp
@@ -5,24 +5,22 @@
 # $Id$
 #
 
-import codecs
 import copy
+import io
 import os
 import re
 import stat
-import StringIO
 import sys
 import textwrap
 from time import strftime
 
-from configobj import ConfigObj
 import jinja2
 from jinja2 import Environment, ChoiceLoader, FileSystemLoader, \
                    TemplateNotFound, TemplatesNotFound, is_undefined
 
 import expargparse
 import expconfig
-from expconfig import ExpConfig, ExpConfigError
+from expconfig import ConfigObj, ExpConfig, ExpConfigError
 import feedback
 import files
 import package_info
@@ -37,9 +35,6 @@ import package_info
 
 # File system
 
-def open_utf8(name, mode='r'):
-    return codecs.open(name, mode, encoding='utf8')
- 
 def chmod_plus_x(file_name):
     '''Make a file executable, respecting user mask.'''
     # Get umask
@@ -79,13 +74,13 @@ def expand_template(template_dict, template_name):
 def expand_template_file(template_dict, template_names, expanded_name, backup_name):
     '''Replace keywords in template file using the given dictionary.'''
     move_file_to_backup(expanded_name, backup_name)
-    expanded_file = open_utf8(expanded_name, 'w')
+    expanded_file = io.open(expanded_name, 'w')
     try:
         for line in template_env.select_template(template_names).generate(template_dict):
             expanded_file.write(line)
     except TemplatesNotFound as error:
         feedback.die(error.message)
-    expanded_file.write('\n')
+    expanded_file.write(u'\n')
     expanded_file.close()
     chmod_plus_x(expanded_name)
 
@@ -99,7 +94,8 @@ def move_file_to_backup(file_name, backup_name):
 
 # Namelist formatting
 
-quote = repr
+def quote(value):
+    return repr(value).lstrip('u')
 
 def format_atom(value):
     '''Format atomic value for use in namelists'''
@@ -133,7 +129,7 @@ def format_value(value, indent):
                 sep = ', '
         if line:
             lines.append(line)
-        return (',\n' + ' '*indent).join(lines)
+        return (u',\n' + ' '*indent).join(lines)
     return format_atom(value)
 
 def keyword_warning(key):
@@ -145,7 +141,7 @@ def get_remove_list(section, key):
         # Deprecation warning for non .keys
         if key[0] != '.':
             keyword_warning(key)
-        if isinstance(section[key], basestring):
+        if not isinstance(section[key], (list, tuple)):
             remove_list = [key, section[key]]
         else:
             remove_list = [key] + section[key]
@@ -159,8 +155,8 @@ def format_namelist_comment(line):
         comment = ''
         if match.group(4):
             comment = ' ! '+match.group(4)
-        return '! '+key+' = '+format_value(value, 0)+comment+'\n'
-    return re.sub(r'^#', '!', line)+'\n'
+        return '! '+key+' = '+format_value(value, 0)+comment+u'\n'
+    return re.sub(r'^#', '!', line)+u'\n'
 
 def format_namelist(section, group=None, default_value=''):
     '''Format config section as a namelist.
@@ -182,17 +178,16 @@ def format_namelist(section, group=None, default_value=''):
     # Support old keyword for backward compatibility
     remove_list = get_remove_list(section, '.remove')
     remove_list += get_remove_list(section, 'remove')
-    black_list = map(lambda x: x.replace(r'\*', '.*').replace(r'\?', '.')+'$', 
-                     map(lambda x: re.escape(x.lower()), remove_list))
+    black_list = [x.replace(r'\*', '.*').replace(r'\?', '.')+'$' for x in [re.escape(x.lower()) for x in remove_list]]
     # Format namelist groups that were not removed
-    lines = StringIO.StringIO()
-    iterator = {group: section[group]}.iteritems() if group else section.iteritems()
+    lines = io.StringIO()
+    iterator = iter({group: section[group]}.items()) if group else iter(section.items())
     for group, contents in iterator:
         if isinstance(contents, dict):
             hidden = is_set(contents.get(hide_key))
             group_def_val = contents.get(default_key, default_value)
             group_id = group.lower()
-            if not hidden and not any(map(lambda x: re.match(x, group_id), black_list)):
+            if not hidden and not any([re.match(x, group_id) for x in black_list]):
                 # Create list of removed keys
                 remove_keys = get_remove_list(contents, '.remove')
                 # Start namelist group
@@ -200,16 +195,17 @@ def format_namelist(section, group=None, default_value=''):
                     lines.write(format_namelist_comment(line))
                 group_names = group_id.split(' ', 1)
                 if len(group_names) == 1:
-                    lines.write('&'+group_names[0]+'\n')
+                    lines.write(u'&'+group_names[0]+u'\n')
                 else:
-                    lines.write('&'+group_names[0]+" ! '"+group_names[1]+"'\n")
-                for key, value in contents.iteritems():
+                    lines.write('&'+group_names[0]+" ! '"+group_names[1]
+                        +u"'\n")
+                for key, value in contents.items():
                     if (key[0] != '.' and key not in remove_keys and
                         value != group_def_val):
                         key = key.lower()
                         indent = base_indent + len(key) + 3
                         for line in contents.comments.get(key, []):
-                            lines.write(' '*base_indent)
+                            lines.write(u' '*base_indent)
                             lines.write(format_namelist_comment(line))
                         line = contents.inline_comments[key]
                         if not line:
@@ -217,12 +213,12 @@ def format_namelist(section, group=None, default_value=''):
                         line = re.sub(r'^#', ' !', line)
                         lines.write(' '*base_indent+key+' = '+
                                     format_value(value, indent)+
-                                    line+'\n')
+                                    line+u'\n')
                 if end_key in contents:
                     for line in contents.comments[end_key]:
-                        lines.write(' '*base_indent)
+                        lines.write(u' '*base_indent)
                         lines.write(format_namelist_comment(line))
-                lines.write('/\n')
+                lines.write(u'/\n')
     return lines.getvalue()
 
 # Global formatting
@@ -238,12 +234,12 @@ def format_vars(section, key, log, fmt):
     value = section[key]
     newkey = transform(key)
     section.rename(key, newkey)
-    if isinstance(value, basestring):
+    if not isinstance(value, (list, tuple, dict)):
         # Format string variables
         section[newkey] = transform(value)
-    elif '__iter__' in dir(value) and not isinstance(value, dict):
+    elif isinstance(value, (list, tuple)):
         # Format all list elements
-        section[newkey] = map(transform, value)
+        section[newkey] = list(map(transform, value))
 
 #
 # Main routine
@@ -277,7 +273,7 @@ if not os.path.exists(experiment_config_name):
     feedback.die("config file '{0}' does not exist".format(experiment_config_name))
 
 # Overrides
-invalid_args = filter(lambda x: not x.find('=')+1, args.assigns)
+invalid_args = [x for x in args.assigns if not x.find('=')+1]
 
 if invalid_args:
     feedback.die("invalid parameters ('"+"', '".join(invalid_args)+"')\n" +
@@ -286,15 +282,15 @@ if invalid_args:
 # Setup templating environment
 
 template_env = Environment(
-    loader = ChoiceLoader(map(FileSystemLoader, config_roots)),
+    loader = ChoiceLoader(list(map(FileSystemLoader, config_roots))),
     variable_start_string = '%{',
     variable_end_string = '}',
     line_statement_prefix = '#%',
     line_comment_prefix = '#%#',
     block_start_string = '{%__mkexp__',
     comment_start_string = '{#__mkexp__',
-    extensions=['jinja2.ext.do']
-)    
+    extensions = ['jinja2.ext.do']
+)
 
 # Additional global functions
 
@@ -337,12 +333,18 @@ template_env.filters['match'] = match
 template_env.filters['split'] = lambda x, s=None, m=-1: x.split(s, m)
 
 # - Add list operation filter
-template_env.filters['filter'] = lambda x, f=None: filter(f, x)
+template_env.filters['filter'] = lambda x, f=None: list(filter(f, x))
 
 # - Replace 'list' handling simple values and strings as singleton lists
 list_original = template_env.filters['list']
-def list_singleton(x, keep_empty=False, *args, **kwargs):
-    if '__iter__' in dir(x):
+@jinja2.evalcontextfilter
+def list_singleton(eval_ctx, x, keep_empty=False, *args, **kwargs):
+    # Workaround for 2.8 bug when applied to literals
+    if isinstance(x, jinja2.nodes.EvalContext):
+        (eval_ctx, x) = (x, eval_ctx)
+    if isinstance(x, (list, tuple)):
+        if getattr(list_original, 'evalcontextfilter', False):
+            return list_original(eval_ctx, x, *args, **kwargs)
         return list_original(x, *args, **kwargs)
     if not keep_empty and x == '':
         return []
@@ -356,7 +358,7 @@ def join_singleton(eval_ctx, x, *args, **kwargs):
     # Workaround for 2.8 bug when applied to literals
     if isinstance(x, jinja2.nodes.EvalContext):
         (eval_ctx, x) = (x, eval_ctx)
-    if '__iter__' in dir(x):
+    if isinstance(x, (list, tuple)):
         return join_original(eval_ctx, x, *args, **kwargs)
     return x
 template_env.filters['join'] = join_singleton
@@ -393,7 +395,7 @@ def cut_dir_variable(directory):
 
 # Create directory for scripts if it doesn't exist
 script_dir = config['SCRIPT_DIR']
-print "Script directory: '"+script_dir+"'"
+print("Script directory: '"+script_dir+"'")
 time_stamp = strftime("%Y%m%d%H%M%S")
 backup_dir = os.path.join(script_dir, 'backup', time_stamp)
 if not os.path.isdir(script_dir):
@@ -406,8 +408,8 @@ else:
 # Create directory for output data if it doesn't exist
 data_dir = config['DATA_DIR']
 data_cut = cut_dir_variable(data_dir)
-print "Data directory: '"+data_dir+"'"+(
-    " (not created)" if not args.make_dirs else "")
+print("Data directory: '"+data_dir+"'"+(
+    " (not created)" if not args.make_dirs else ""))
 if args.make_dirs:
     if data_dir != data_cut:
         feedback.warning("only considering non-variable part of directory")
@@ -420,8 +422,8 @@ if args.make_dirs:
 work_dir = config['WORK_DIR']
 work_cut = cut_dir_variable(work_dir)
 if work_dir != data_dir:
-    print "Work directory: '"+work_dir+"'"+(
-        " (not created)" if not args.make_dirs else "")
+    print("Work directory: '"+work_dir+"'"+(
+        " (not created)" if not args.make_dirs else ""))
     if args.make_dirs:
         if work_dir != work_cut:
             feedback.warning("only considering non-variable part of directory")
@@ -435,7 +437,7 @@ if work_dir != data_dir:
 dump_name = config.experiment_id+'.dump'
 move_file_to_backup(os.path.join(script_dir, dump_name),
                     os.path.join(backup_dir, dump_name))
-dump_file = open_utf8(os.path.join(script_dir, dump_name), 'w')
+dump_file = io.open(os.path.join(script_dir, dump_name), 'wb')
 default_indent_type = config.indent_type
 config.indent_type = '  '
 config.write(dump_file)
@@ -450,7 +452,7 @@ dump_file.close()
 job_dict = {}
 remove_list = get_remove_list(config['jobs'], '.remove')
 remove_list += get_remove_list(config['jobs'], 'remove')
-for key, value in config['jobs'].iteritems():
+for key, value in config['jobs'].items():
     if not isinstance(value, dict):
         job_dict[key] = value
         del config['jobs'][key]
@@ -483,7 +485,7 @@ def extend(subjob, jobs_config, extended_jobs):
         # Add actual subjob config
         pre_config.merge(subconfig)
 
-        # Replace subjob config by extended config_lines
+        # Replace subjob config by extended config
         jobs_config[subjob] = {}
         jobs_config[subjob].merge(pre_config)
         del pre_config
@@ -503,20 +505,19 @@ for subjob in jobs_config:
         subconfig = jobs_config[subjob]
         subconfig['id'] = subjob
         if not 'tasks' in subconfig:
-            subconfig['tasks'] = int(subconfig.get('nodes', 1)) * \
-                                 int(subconfig.get('tasks_per_node', 1))
-
-# Save configuration to buffer, to be merged with each job config
-config_lines = StringIO.StringIO()
-config.write(config_lines)
+            subconfig['tasks'] = str(int(subconfig.get('nodes', 1)) * 
+                                     int(subconfig.get('tasks_per_node', 1)))
 
 # Paste them into each job
-for subjob, subconfig in jobs_config.iteritems():
+for subjob, subconfig in jobs_config.items():
     if not subjob in remove_list:
 
         # Copy current config settings to job
+        config_lines = io.BytesIO()
+        config.write(config_lines)
         config_lines.seek(0)
-        job_config = ConfigObj(config_lines, interpolation=False)
+        job_config = ConfigObj(io.TextIOWrapper(config_lines),
+                               interpolation=False)
 
         # Check namelist override
         if 'namelists' in subconfig:
@@ -529,7 +530,7 @@ for subjob, subconfig in jobs_config.iteritems():
             del subconfig['files']
 
         # Paste pre config into job config
-        job_config['JOB'] = subconfig
+        job_config[u'JOB'] = subconfig
         del subconfig
 
         # Prepare namelists for inclusion in scripts
@@ -539,7 +540,7 @@ for subjob, subconfig in jobs_config.iteritems():
         job_config['jobs'] = copy.deepcopy(jobs_config)
         job_config.walk(format_vars, log=var_list, fmt=var_format)
         job_config['VARIABLES_'] = var_list
-        for namelist, groups in job_config['namelists'].iteritems():
+        for namelist, groups in job_config['namelists'].items():
             if isinstance(groups, dict):
                 # Skip hidden namelists
                 if is_set(groups.get('.hide')):
@@ -587,27 +588,27 @@ for subjob, subconfig in jobs_config.iteritems():
 
 move_file_to_backup(os.path.join(script_dir, 'README'),
                     os.path.join(backup_dir, 'README'))
-readme_file = open_utf8(os.path.join(script_dir, 'README'), 'w')
-readme_file.write(config['EXP_DESCRIPTION'] + '\n')
+readme_file = io.open(os.path.join(script_dir, 'README'), 'w')
+readme_file.write(config['EXP_DESCRIPTION'] + u'\n')
 readme_file.close()
 
 # Create update script from experiment description
 
 move_file_to_backup(os.path.join(script_dir, 'update'),
                     os.path.join(backup_dir, 'update'))
-update_file = open_utf8(os.path.join(script_dir, 'update'), 'w')
-update_file.write('#! /bin/sh\n')
-update_file.write('#\n')
-update_file.write('# Regenerate all files with identical configuration\n')
-update_file.write('#\n')
-update_file.write('# ' + extra_dict['mkexp_input'].replace('$$', '$') + '\n')
-update_file.write('#\n')
-update_file.write('cd ' + quote(os.environ.get('PWD', os.getcwd())) + '\n')
-update_file.write('PATH=' + quote(os.environ.get('PATH', '')) + '\n')
-update_file.write('PYTHONPATH=' + quote(os.environ.get('PYTHONPATH', '')) + '\n')
-update_file.write('MKEXP_PATH=' + quote(os.environ.get('MKEXP_PATH', '')) + '\n')
-update_file.write('export PATH PYTHONPATH MKEXP_PATH\n')
-update_file.write('echo ' + ' '.join(map(quote, sys.argv)) + ' "$@" >&2\n')
-update_file.write('exec ' + ' '.join(map(quote, sys.argv)) + ' "$@"\n')
+update_file = io.open(os.path.join(script_dir, 'update'), 'w')
+update_file.write(u'#! /bin/sh\n')
+update_file.write(u'#\n')
+update_file.write(u'# Regenerate all files with identical configuration\n')
+update_file.write(u'#\n')
+update_file.write(u'# ' + extra_dict['mkexp_input'].replace('$$', '$') + '\n')
+update_file.write(u'#\n')
+update_file.write(u'cd ' + quote(os.environ.get('PWD', os.getcwd())) + '\n')
+update_file.write(u'PATH=' + quote(os.environ.get('PATH', '')) + '\n')
+update_file.write(u'PYTHONPATH=' + quote(os.environ.get('PYTHONPATH', '')) + '\n')
+update_file.write(u'MKEXP_PATH=' + quote(os.environ.get('MKEXP_PATH', '')) + '\n')
+update_file.write(u'export PATH PYTHONPATH MKEXP_PATH\n')
+update_file.write(u'echo ' + ' '.join(map(quote, sys.argv)) + ' "$@" >&2\n')
+update_file.write(u'exec ' + ' '.join(map(quote, sys.argv)) + ' "$@"\n')
 update_file.close()
 chmod_plus_x(os.path.join(script_dir, 'update'))
diff --git a/rmexp b/rmexp
index 79ac102ba56c6f588c571ede5ba11eefa915d75b..7d11bccfa9507ed69c302d61c29716f5493be910 100755
--- a/rmexp
+++ b/rmexp
@@ -9,6 +9,9 @@ PROGRAM=`basename $0`
 BINDIR=`dirname $0`
 PATH="$BINDIR:$PATH"
 
+PYTHONIOENCODING=$(locale -c charmap | tail -1)
+export PYTHONIOENCODING
+
 die () {
     echo "$@" >&2
     exit 1
diff --git a/selconfig b/selconfig
index ea9822121a9fbc681646389f7decc3dd34914fd2..3ba0c35490acec4e85a3b9272be9e36a239acf3c 100755
--- a/selconfig
+++ b/selconfig
@@ -5,12 +5,14 @@ Select the given section of a config file
 $Id$
 '''
 
+from __future__ import print_function
+
 import argparse
+import io
 import re
 import sys
-import StringIO
 
-from configobj import ConfigObj
+from expconfig import ConfigObj
 
 from expargparse import assigns_to_dicts, get_key_chain
 from feedback import die
@@ -51,28 +53,31 @@ except IOError as error:
 
 selected_data = ConfigObj(interpolation=False, write_empty_values=True,
                           indent_type='  ')
-config = config_data
-selected = selected_data
-for section in reversed(get_key_chain(args.section)):
-    if section in config.comments:
-        selected.comments[section] = config.comments[section]
-    if section in config.inline_comments:
-        selected.inline_comments[section] = config.inline_comments[section]
-    config = config[section]
-    selected[section] = {}
-    selected = selected[section]
-# Replace the empty leaf section by the original section to be selected
-selected.parent[section] = config
+if args.section:
+    config = config_data
+    selected = selected_data
+    for section in reversed(get_key_chain(args.section)):
+        if section in config.comments:
+            selected.comments[section] = config.comments[section]
+        if section in config.inline_comments:
+            selected.inline_comments[section] = config.inline_comments[section]
+        config = config[section]
+        selected[section] = {}
+        selected = selected[section]
+    # Replace the empty leaf section by the original section to be selected
+    selected.parent[section] = config
+else:
+    selected_data.merge(config_data)
 
 # Ready to roll out
 
-lines = StringIO.StringIO()
+lines = io.BytesIO()
 selected_data.write(lines)
 
 lines.seek(0)
-for line in lines:
+for line in io.TextIOWrapper(lines):
     if args.inline_comments: line = re.sub(r' = (.*?)  #', r' = \1 #', line)
     if args.trailing_space:
         print(line.rstrip())
     else:
-        sys.stdout.write(line)
+        print(line, end='')
diff --git a/setconfig b/setconfig
index d174d04496ce66389b8d1034e399e745b07d8678..6060a0552a76d66b55cca4de92751562513de5c0 100755
--- a/setconfig
+++ b/setconfig
@@ -1,16 +1,18 @@
 #! /usr/bin/env python
-#
-# Change configuration using command line
-#
-# $Id$
-#
+'''\
+Change configuration using command line
+
+$Id$
+'''
+
+from __future__ import print_function
 
 import argparse
+import io
 import re
 import sys
-import StringIO
 
-from configobj import ConfigObj
+from expconfig import ConfigObj
 
 from expargparse import assigns_to_dicts, get_key_chain
 from feedback import die
@@ -22,8 +24,7 @@ import package_info
 
 # Check command line
 
-command_line = argparse.ArgumentParser(description=
-    'Change configuration using command line.')
+command_line = argparse.ArgumentParser(description=__doc__.split('\n', 1)[0])
 command_line.add_argument('config', nargs='?', default='-', 
                           help='original configuration file name [%(default)s]')
 command_line.add_argument('assigns', metavar='key=value', nargs='*',
@@ -45,6 +46,7 @@ command_line.add_argument('--trailing-space' , '-t', action='store_true',
 args = command_line.parse_args()
 
 # File handling
+
 try:
     config_file = args.config
     if config_file == '-':
@@ -94,12 +96,13 @@ for line in back_plate:
 
 # Ready to roll out
 
-lines = StringIO.StringIO()
+lines = io.BytesIO()
 config_data.write(lines)
+
 lines.seek(0)
-for line in lines:
+for line in io.TextIOWrapper(lines):
     if args.inline_comments: line = re.sub(r' = (.*?)  #', r' = \1 #', line)
     if args.trailing_space:
         print(line.rstrip())
     else:
-        sys.stdout.write(line)
+        print(line, end='')
diff --git a/test.py b/test.py
index c06e83adfe046eed2dae198e0c471f280781ec40..4988533034500b9ef300a1750a9615045e2a4187 100644
--- a/test.py
+++ b/test.py
@@ -1,35 +1,53 @@
+# -*- coding: utf-8 -*-
+
+import io
+import locale
 import os
 import re
+import subprocess
 import sys
 import unittest
 
 from os.path import join
 
 
+_preferred_encoding = locale.getpreferredencoding()
 
 def align(string):
     return re.sub(r'\n\s*', '\n', string.lstrip())
 
-def script(string):
-    return align("""
+def script(string, set_encoding=False):
+    text = u"""
         set -e
         unset CDPATH
         cd test
-        PATH=..:$PATH
+        PATH=..:.:$PATH
         MKEXP_PATH=
-    """) + align(string)
+    """
+    if set_encoding and sys.getdefaultencoding() == 'ascii':
+        text += u"""
+            PYTHONIOENCODING={0}
+            export PYTHONIOENCODING
+        """.format(_preferred_encoding)
+    text += string
+    return align(text)
 
 def output(command):
-    (ignore, stream) = os.popen4(command)
-    return stream.read()
+    p = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    (result, ignore) = p.communicate()
+    try: result = str(result, _preferred_encoding)
+    except TypeError: pass
+    ### print("DEBUG:\n" + result) ###
+    return result
 
 def readfile(filename):
-    stream = open(filename)
-    return stream.read()
+    with io.open(filename) as stream:
+        return stream.read()
 
 def writefile(filename, string):
-    stream = open(filename, 'w')
-    stream.write(string)
+    with io.open(filename, 'w') as stream:
+        stream.write(string)
 
 def writeconfig(exp_id, string):
     writefile(join("test", exp_id+".config"), string)
@@ -41,12 +59,12 @@ def writetemplate(exp_id, job_id, string):
 
 class MkexpTestCase(unittest.TestCase):
 
-    script_clean = script("""
+    script_clean = script(u"""
         rm -rf experiments
         rm -f test_* SETUP.config
     """)
 
-    script_run = script("""
+    script_run = script(u"""
         mkexp test0001.config
     """)
 
@@ -65,11 +83,11 @@ class MkexpSimpleTestCase(MkexpTestCase):
         MkexpTestCase.setUp(self)
 
     def run_test(self, template, expected, additional=''):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
-            """+additional+"""
+            """+additional+u"""
             [jobs]
-              [["""+self.job_id+"""]]
+              [["""+self.job_id+u"""]]
         """)
         writetemplate(self.exp_id, self.job_id, template)
         expected = align(expected)
@@ -80,11 +98,11 @@ class MkexpSimpleTestCase(MkexpTestCase):
         self.assertMultiLineEqual(expected, result)
 
     def run_no_template(self, result_path, expected, additional=''):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
-            """+additional+"""
+            """+additional+u"""
             [jobs]
-              [["""+self.job_id+"""]]
+              [["""+self.job_id+u"""]]
         """)
         expected = align(expected)
         ignore = output(script("mkexp "+self.exp_id+".config"))
@@ -101,7 +119,7 @@ class RunningTestCase(MkexpTestCase):
         self.assertIn('error: too few arguments', result)
 
     def test_clean_run(self):
-        expected = align("""
+        expected = align(u"""
             Script directory: 'experiments/test0001'
             Data directory: 'experiments/test0001'
         """)
@@ -118,7 +136,7 @@ class RunningTestCase(MkexpTestCase):
 class CommandLineTestCase(MkexpTestCase):
 
     def test_pass_section_variables(self):
-        script_section = script("""
+        script_section = script(u"""
             mkexp test0001.config \
                 namelists.namelist..echam.runctl.dt_start=2345,01,23,12,34,56 \
                 namelists.namelist..echam.runctl.some_file=abcdefgh.ijk
@@ -136,7 +154,7 @@ class CommandLineTestCase(MkexpTestCase):
         # Should exist, otherwise exception is thrown
 
     def test_options(self):
-        script_option = script("""
+        script_option = script(u"""
             mkexp test0001.config EXP_OPTIONS=option1
         """)
         expected = "default_output = .false."
@@ -145,12 +163,12 @@ class CommandLineTestCase(MkexpTestCase):
         self.assertIn(expected, result)
 
     def test_getexp_vv(self):
-        script_getexp = script("""
+        script_getexp = script(u"""
             mkexp test0001.config
             mv experiments/test0001 experiments/test0001.orig
             getexp -vv test0001.config MODEL_DIR=. > test_getexp.dump
             mkexp --getexp test_getexp.dump
-        """)
+        """, set_encoding=True)
         ignore = output(script_getexp)
         expected = readfile('test/experiments/test0001.orig/test0001.run')
         result = readfile('test/experiments/test0001/test0001.run')
@@ -158,7 +176,7 @@ class CommandLineTestCase(MkexpTestCase):
 
     def test_getexp_k(self):
         result = output(script('getexp -k VAR1 test0001.config'))
-        expected = align("""
+        expected = align(u"""
             Note: data for experiment 'test0001' does not exist
             value1
         """)
@@ -166,7 +184,7 @@ class CommandLineTestCase(MkexpTestCase):
 
     def test_getexp_k_k(self):
         result = output(script('getexp -k VAR1 -k VAR2 test0001.config'))
-        expected = align("""
+        expected = align(u"""
             Note: data for experiment 'test0001' does not exist
             value1
             value1
@@ -175,25 +193,55 @@ class CommandLineTestCase(MkexpTestCase):
 
     def test_getexp_s(self):
         result = output(script('getexp -s -k VAR1 test0001.config'))
-        expected = align("""
+        expected = align(u"""
             Note: data for experiment 'test0001' does not exist
             VAR1='value1'
         """)
         self.assertMultiLineEqual(expected, result)
 
     def test_getconfig(self):
-        ignore = output(script("""
+        ignore = output(script(u"""
             mkexp test0001.config VAR4=value4 jobs.run.time_limit=12:34:56
         """))
-        result = output(script('getconfig experiments/test0001/update'))
+        result = output(script('getconfig experiments/test0001/update',
+                               set_encoding=True))
         self.assertIn('VAR4 = value4', result)
         self.assertIn('time_limit = 12:34:56', result)
 
+    def test_setconfig(self):
+        result = output(script(u"""
+            setconfig test0001.config VAR4=value4 jobs.run.time_limit=12:34:56
+        """, set_encoding=True))
+        self.assertIn('VAR4 = value4', result)
+        self.assertIn('time_limit = 12:34:56', result)
+
+    def test_selconfig(self):
+        result = output(script(u"""
+            selconfig VAR1 test0001.config
+        """))
+        self.assertIn('VAR1 = value1', result)
+        self.assertNotIn('VAR2', result)
+
+    def test_rmexp(self):
+        script_getexp = script(u"""
+            mkexp test0001.config
+            (echo n; echo y) | rmexp test0001.config
+        """)
+        result = output(script_getexp)
+        self.assertIn("Script directory: 'experiments/test0001'", result)
+        self.assertIn("Data directory: 'experiments/test0001'", result)
+        self.assertIn("Info for test0001's working directory:", result)
+        self.assertIn("rmexp: remove test0001's working directory and its contents [no]? Info for test0001's script directory:", result)
+        self.assertNotIn("rmexp: remove test0001's working directory and its contents [no]? rmexp: removed 'experiments/test0001'", result)
+        self.assertIn("rmexp: remove test0001's script directory and its contents [no]? rmexp: removed 'experiments/test0001'", result)
+        self.assertNotIn("rmexp: remove test0001's script directory and its contents [no]? Info for test0001's data directory:", result)
+        self.assertNotIn("rmexp: remove test0001's data directory and its contents [no]?", result)
+
 class ContentTestCase(MkexpSimpleTestCase):
 
     def test_job_override(self):
         exp_id = "test_job_override"
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE =
             [jobs]
               key1 = global
@@ -201,7 +249,7 @@ class ContentTestCase(MkexpSimpleTestCase):
               [[job1]]
                 key1 = local
         """)
-        writetemplate(exp_id, "job1", """
+        writetemplate(exp_id, "job1", u"""
             key1 = %{JOB.key1}
             key2 = %{JOB.key2}
         """)
@@ -213,7 +261,7 @@ class ContentTestCase(MkexpSimpleTestCase):
     def test_var_list_in_context(self):
         exp_id = "test_var_list_in_context"
         job_id = "job"
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE =
             VAR1 = value1
             GLOBAL1 = $${VAR1} # Initialized
@@ -221,14 +269,14 @@ class ContentTestCase(MkexpSimpleTestCase):
             GLOBAL3 = $${VAR1} # Used twice, may only be listed once
             GLOBAL${FOUR} = 4  # (Uninitialized) Variable in key
             [jobs]
-              [["""+job_id+"""]]
+              [["""+job_id+u"""]]
         """)
-        writetemplate(exp_id, job_id, """
-            #% for var in VARIABLES_:
+        writetemplate(exp_id, job_id, u"""
+            #% for var in VARIABLES_|sort:
             %{var}=%{context(var)}
             #% endfor
         """)
-        expected = align("""
+        expected = align(u"""
             FOUR=
             VAR1=value1
             VAR2=
@@ -241,20 +289,20 @@ class ContentTestCase(MkexpSimpleTestCase):
     def test_split_date(self):
         exp_id = 'test_split_date'
         job_id = 'job'
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE =
             DATE_ISO = 1234-05-06
             DATE_RAW = 12340506
             DATE_LIST_ISO = split_date($DATE_ISO)
             DATE_LIST_RAW = split_date($DATE_RAW)
             [jobs]
-              [["""+job_id+"""]]
+              [["""+job_id+u"""]]
         """)
-        writetemplate(exp_id, job_id, """
+        writetemplate(exp_id, job_id, u"""
             %{DATE_LIST_ISO|join(',')}
             %{DATE_LIST_RAW|join(',')}
         """)
-        expected = align("""
+        expected = align(u"""
             1234,5,6,0,0,0
             1234,05,06,0,0,0
         """)
@@ -266,7 +314,7 @@ class ContentTestCase(MkexpSimpleTestCase):
     def test_add_years(self):
         exp_id = 'test_add_years'
         job_id = 'job'
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE =
             DATE = 1234-05-06
             NEXT_DATE = 'add_years($DATE, 1)'
@@ -274,15 +322,15 @@ class ContentTestCase(MkexpSimpleTestCase):
             NEGATIVE_DATE = 'add_years($DATE, -2000)'
             LONGYEAR_DATE = 'add_years($DATE, 10000)'
             [jobs]
-              [["""+job_id+"""]]
+              [["""+job_id+u"""]]
         """)
-        writetemplate(exp_id, job_id, """
+        writetemplate(exp_id, job_id, u"""
             %{NEXT_DATE}
             %{PREVIOUS_DATE}
             %{NEGATIVE_DATE}
             %{LONGYEAR_DATE}
         """)
-        expected = align("""
+        expected = align(u"""
             1235-05-06
             1233-05-06
             -0766-05-06
@@ -296,7 +344,7 @@ class ContentTestCase(MkexpSimpleTestCase):
     def test_add_days(self):
         exp_id = 'test_add_days'
         job_id = 'job'
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE =
             DATE = 1234-05-06
             NEXT_DATE = 'add_days($DATE, 1)'
@@ -308,9 +356,9 @@ class ContentTestCase(MkexpSimpleTestCase):
             EARLY_DATE = 0000-01-01
             EARLIER_DATE = 'add_days($EARLY_DATE, -1)'
             [jobs]
-              [["""+job_id+"""]]
+              [["""+job_id+u"""]]
         """)
-        writetemplate(exp_id, job_id, """
+        writetemplate(exp_id, job_id, u"""
             %{NEXT_DATE}
             %{PREVIOUS_DATE}
             %{NEGATIVE_DATE}
@@ -318,7 +366,7 @@ class ContentTestCase(MkexpSimpleTestCase):
             %{LATER_DATE}
             %{EARLIER_DATE}
         """)
-        expected = align("""
+        expected = align(u"""
             1234-05-07
             1234-05-05
             1228-11-13
@@ -332,37 +380,37 @@ class ContentTestCase(MkexpSimpleTestCase):
         self.assertMultiLineEqual(expected, result)
 
     def test_eval(self):
-        self.run_test("""
+        self.run_test(u"""
             %{VALUE}
-        """, """
+        """, u"""
             42
-        """, """
+        """, u"""
             VALUE = eval(5*8+2)
         """)
 
     def test_eval_time(self):
-        self.run_test("""
+        self.run_test(u"""
             %{VALUE}
-        """, """
+        """, u"""
             1970-01-01
-        """, """
+        """, u"""
             VALUE = "eval(time.strftime('%Y-%m-%d', time.gmtime(0)))"
         """)
 
     def test_eval_is_set(self):
-        self.run_test("""
+        self.run_test(u"""
             %{TRUE}
             %{FALSE}
-        """, """
+        """, u"""
             True
             False
-        """, """
+        """, u"""
             TRUE = eval(is_set('.true.'))
             FALSE = eval(is_set('F'))
         """)
 
     def test_initial_comment_boilerplate(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             ######
             #    #
             # 42
@@ -372,7 +420,7 @@ class ContentTestCase(MkexpSimpleTestCase):
             [jobs]
               [["""+self.job_id+"""]]
         """)
-        writetemplate(self.exp_id, self.job_id, """
+        writetemplate(self.exp_id, self.job_id, u"""
             %{EXP_DESCRIPTION}
         """)
         expected = align("""
@@ -387,9 +435,9 @@ class ContentTestCase(MkexpSimpleTestCase):
 class NamelistTestCase(MkexpSimpleTestCase):
 
     def test_namelist_comments(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        ""","""
+        """,u"""
             ! Comment group 1
             ! var_1c = 'test'
             &group_1
@@ -402,7 +450,7 @@ class NamelistTestCase(MkexpSimpleTestCase):
                 ! Comment for var 2b
                 var_2b = 21 ! Inline comment for var 2b
             /
-        ""","""
+        """,u"""
             [namelists]
               [[namelist]]
                 # Comment group 1
@@ -419,9 +467,9 @@ class NamelistTestCase(MkexpSimpleTestCase):
         """)
 
     def test_var_in_namelist(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        ""","""
+        """,u"""
             &group
                 var_1 = $value_1
                 var_2 = ${value_2}
@@ -429,7 +477,7 @@ class NamelistTestCase(MkexpSimpleTestCase):
                 var_4 = 'a$value_4'
                 var_5 = '${value_5}b'
             /
-        ""","""
+        """,u"""
             [namelists]
               [[namelist]]
                 [[[group]]]
@@ -441,9 +489,9 @@ class NamelistTestCase(MkexpSimpleTestCase):
         """)
 
     def test_namelist_multi_groups(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             &group ! '1'
             /
             &group ! ' 1'
@@ -452,7 +500,7 @@ class NamelistTestCase(MkexpSimpleTestCase):
             /
             &group ! 'i i i'
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 [[[group 1]]]
@@ -462,14 +510,14 @@ class NamelistTestCase(MkexpSimpleTestCase):
         """)
 
     def test_namelist_case_twist(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             &group
                 value = 41
                 value = 42
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 [[[group]]]
@@ -478,11 +526,11 @@ class NamelistTestCase(MkexpSimpleTestCase):
         """)
 
     def test_namelist_format(self):
-        self.run_test("""
+        self.run_test(u"""
             %{format_namelist(namelists.namelist)}
             %{format_namelist(namelists.namelist, 'group2')}
             %{format_namelist(namelists.namelist, 'no such group')}
-        """, """
+        """, u"""
             &group1
                 value = 41
             /
@@ -492,7 +540,7 @@ class NamelistTestCase(MkexpSimpleTestCase):
             &group2
                 value = 42
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 .remove = group3
@@ -505,11 +553,11 @@ class NamelistTestCase(MkexpSimpleTestCase):
         """)
 
     def test_namelist_with_template(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             42
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 .use_template = true
@@ -520,16 +568,16 @@ class NamelistTestCase(MkexpSimpleTestCase):
 class NamelistHiddenTestCase(MkexpSimpleTestCase):
 
     def test_namelist_hide(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             &group1
                 value = 41
             /
             &group3
                 value = 43
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 [[[group1]]]
@@ -543,10 +591,10 @@ class NamelistHiddenTestCase(MkexpSimpleTestCase):
         """)
 
     def test_hidden_namelist_file(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
-        """, """
+        """, u"""
+        """, u"""
             [namelists]
               [[namelist]]
                 .hide = true
@@ -555,10 +603,10 @@ class NamelistHiddenTestCase(MkexpSimpleTestCase):
         """)
 
     def test_hidden_namelist_with_template(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
-        """, """
+        """, u"""
+        """, u"""
             [namelists]
               [[namelist]]
                 .hide = true
@@ -570,12 +618,12 @@ class NamelistHiddenTestCase(MkexpSimpleTestCase):
 class NamelistDefaultValueTestCase(MkexpSimpleTestCase):
 
     def test_standard_default_value(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             &group
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 [[[group]]]
@@ -583,13 +631,13 @@ class NamelistDefaultValueTestCase(MkexpSimpleTestCase):
         """)
 
     def test_custom_default_value(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST}
-        """, """
+        """, u"""
             &group
                 value1 = ''
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 .default = <DEFAULT>
@@ -599,16 +647,16 @@ class NamelistDefaultValueTestCase(MkexpSimpleTestCase):
         """)
 
     def test_namelist_default_value(self):
-        self.run_test("""
+        self.run_test(u"""
             %{NAMELIST1}
             %{NAMELIST2}
-        """, """
+        """, u"""
             &group
             /
             &group
                 value = '<DEFAULT>'
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist1]]
                 .default = <DEFAULT>
@@ -620,12 +668,12 @@ class NamelistDefaultValueTestCase(MkexpSimpleTestCase):
         """)
 
     def test_global_default_value(self):
-        self.run_test("""
+        self.run_test(u"""
             %{format_namelist(namelists.namelist, default_value='<DEFAULT>')}
-        """, """
+        """, u"""
             &group
             /
-        """, """
+        """, u"""
             [namelists]
               [[namelist]]
                 [[[group]]]
@@ -635,17 +683,17 @@ class NamelistDefaultValueTestCase(MkexpSimpleTestCase):
 class JinjaTemplateTestCase(MkexpSimpleTestCase):
 
     def test_ignore_blocks(self):
-        self.run_test("""
+        self.run_test(u"""
             {% set answer = 42 %}
-        """, """
+        """, u"""
             {% set answer = 42 %}
         """)
 
     def test_ignore_comments(self):
-        self.run_test("""
+        self.run_test(u"""
             {# no comment #}
             ${#ARRAY}
-        """, """
+        """, u"""
             {# no comment #}
             ${#ARRAY}
         """)
@@ -653,111 +701,111 @@ class JinjaTemplateTestCase(MkexpSimpleTestCase):
 class DefaultEnvironmentTestCase(MkexpSimpleTestCase):
 
     def test_basic(self):
-       self.run_test("""
+       self.run_test(u"""
            %{ENVIRONMENT}
-       """, """
+       """, u"""
            DEFAULT
        """)
 
     def test_explicit(self):
-       self.run_test("""
+       self.run_test(u"""
            %{ENVIRONMENT}
-       """, """
+       """, u"""
            green
-       """, """
+       """, u"""
            ENVIRONMENT = green
        """)
 
     def test_setup(self):
-       writeconfig('SETUP', """
+       writeconfig('SETUP', u"""
            ENVIRONMENT = 
        """)
-       self.run_test("""
+       self.run_test(u"""
            %{ENVIRONMENT}
-       """, """
+       """, u"""
            DEFAULT
        """)
 
 class SetupConfigTestCase(MkexpSimpleTestCase):
 
     def test_system_options(self):
-       writeconfig('SETUP', """
+       writeconfig('SETUP', u"""
            SETUP_OPTIONS = option1
        """)
-       self.run_test("""
+       self.run_test(u"""
            %{NAMELIST_ECHAM}
-       """, """
+       """, u"""
            &runctl
              default_output = .false.
            /
-       """, """
+       """, u"""
            EXP_OPTIONS =
        """)
            
 class MatchTestCase(MkexpSimpleTestCase):
 
     def test_basic(self):
-       self.run_test("""
+       self.run_test(u"""
            %{'Douglas Adams'|match('Adam')}
-       """, """
+       """, u"""
            Douglas Adams
        """)
 
     def test_no_match(self):
-       self.run_test("""
+       self.run_test(u"""
            %{'Douglas Adams'|match('Eva')}
-       """, """
+       """, u"""
            
        """)
 
     def test_with_default(self):
-       self.run_test("""
+       self.run_test(u"""
            %{'Douglas Adams'|match('Abel', 'Kain')}
-       """, """
+       """, u"""
            Kain
        """)
 
     def test_with_group(self):
-       self.run_test("""
+       self.run_test(u"""
            %{'Douglas Adams'|match('l(.*)m')}
-       """, """
+       """, u"""
            as Ada
        """)
 
 class SplitTestCase(MkexpSimpleTestCase):
 
     def test_basic(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'Douglas Noel  Adams'|split(' ')}
             %{'Douglas Noel  Adams'|split('  ')}
-        ""","""
+        """,u"""
             ['Douglas', 'Noel', '', 'Adams']
             ['Douglas Noel', 'Adams']
         """)
 
     def test_max_split(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'Douglas Noel  Adams'|split(' ', 2)}
             %{'Douglas Noel  Adams'|split(' ', 1)}
-        ""","""
+        """,u"""
             ['Douglas', 'Noel', ' Adams']
             ['Douglas', 'Noel  Adams']
         """)
 
     def test_default_separator(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'Douglas Noel  Adams'|split()}
             %{'Douglas Noel  Adams'|split(none)}
-        ""","""
+        """,u"""
             ['Douglas', 'Noel', 'Adams']
             ['Douglas', 'Noel', 'Adams']
         """)
 
     def test_max_split_and_default_separator(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'Douglas Noel  Adams'|split(m=2)}
             %{'Douglas Noel  Adams'|split(m=1)}
-        ""","""
+        """,u"""
             ['Douglas', 'Noel', 'Adams']
             ['Douglas', 'Noel  Adams']
         """)
@@ -765,18 +813,18 @@ class SplitTestCase(MkexpSimpleTestCase):
 class FilterTestCase(MkexpSimpleTestCase):
 
     def test_basic(self):
-        self.run_test("""
+        self.run_test(u"""
             %{['Douglas', 'Noel', '', 'Adams']|filter}
-        ""","""
+        """,u"""
             ['Douglas', 'Noel', 'Adams']
         """)
 
 class WordwrapTestCase(MkexpSimpleTestCase):
 
     def test_basic(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'long-arbitrarilyhyphenated textlike-message'|wordwrap(15)}
-        """, """
+        """, u"""
             long-arbitraril
             yhyphenated
             textlike-
@@ -784,9 +832,9 @@ class WordwrapTestCase(MkexpSimpleTestCase):
         """)
 
     def test_keep_long(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'long-arbitrarilyhyphenated textlike-message'|wordwrap(15,false)}
-        """, """
+        """, u"""
             long-
             arbitrarilyhyphenated
             textlike-
@@ -794,17 +842,17 @@ class WordwrapTestCase(MkexpSimpleTestCase):
         """)
 
     def test_keep_long_hyphens(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'long-arbitrarilyhyphenated textlike-message'|wordwrap(15,false,false)}
-        """, """
+        """, u"""
             long-arbitrarilyhyphenated
             textlike-message
         """)
 
     def test_keep_hyphens(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'long-arbitrarilyhyphenated textlike-message'|wordwrap(15,true,false)}
-        """, """
+        """, u"""
             long-arbitraril
             yhyphenated tex
             tlike-message
@@ -813,159 +861,159 @@ class WordwrapTestCase(MkexpSimpleTestCase):
 class ListTestCase(MkexpSimpleTestCase):
 
     def test_list_on_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'first'|list}
-        """, """
+        """, u"""
             ['first']
         """)
 
     def test_list_on_empty_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{''|list}
-        """, """
+        """, u"""
             []
         """)
 
     def test_list_keep_empty_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{''|list(true)}
-        """, """
+        """, u"""
             ['']
         """)
 
     def test_list_on_list(self):
-        self.run_test("""
+        self.run_test(u"""
             %{['first', 'second', 'third']|list}
-        """, """
+        """, u"""
             ['first', 'second', 'third']
         """)
 
     def test_list_on_int(self):
-        self.run_test("""
+        self.run_test(u"""
             %{42|list}
-        """, """
+        """, u"""
             [42]
         """)
 
     def test_list_on_tuple(self):
-        self.run_test("""
+        self.run_test(u"""
             %{('first', 'second', 'third')|list}
-        """, """
+        """, u"""
              ['first', 'second', 'third']
         """)
 
 class JoinTestCase(MkexpSimpleTestCase):
 
     def test_join_on_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'first'|join(', ')}
-        """, """
+        """, u"""
             first
         """)
 
     def test_join_on_empty_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{''|join}
-        """, """
+        """, u"""
         """)
 
     def test_join_on_list(self):
-        self.run_test("""
+        self.run_test(u"""
             %{['first', 'second', 'third']|join(', ')}
-        """, """
+        """, u"""
             first, second, third
         """)
 
     def test_join_on_int(self):
-        self.run_test("""
+        self.run_test(u"""
             %{42|join(', ')}
-        """, """
+        """, u"""
             42
         """)
 
     def test_join_on_tuple(self):
-        self.run_test("""
+        self.run_test(u"""
             %{('first', 'second', 'third')|join(', ')}
-        """, """
+        """, u"""
              first, second, third
         """)
 
 class IsSetTestCase(MkexpSimpleTestCase):
 
     def test_empty_string(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'' is set}
-        """, """
+        """, u"""
             False
         """)
 
     def test_true(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'true' is set}
-        """, """
+        """, u"""
             True
         """)
 
     def test_namelist_true(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'.true.' is set}
-        """, """
+        """, u"""
             True
         """)
 
     def test_false(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'false' is set}
-        """, """
+        """, u"""
             False
         """)
 
     def test_test(self):
-        self.run_test("""
+        self.run_test(u"""
             %{'.test.' is set}
-        """, """
+        """, u"""
             True
         """)
 
     def test_undefined(self):
-        self.run_test("""
+        self.run_test(u"""
             %{undefined_variable_name is set}
-        """, """
+        """, u"""
             False
         """)
 
     def test_undefined_with_true_default(self):
-        self.run_test("""
+        self.run_test(u"""
             %{undefined_variable_name|d('t') is set}
-        """, """
+        """, u"""
             True
         """)
 
 class FilesTestCase(MkexpSimpleTestCase):
 
     def test_get_file_simple(self):
-        self.run_test("""
+        self.run_test(u"""
             %{get_file(files, 'target.txt')}
             %{get_file(files, 'broken.txt')}
-        """, """
+        """, u"""
             source.txt
             .
-        """, """
+        """, u"""
             [files]
                 target.txt = source.txt
                 broken.txt = .
         """)
 
     def test_get_file_path(self):
-        self.run_test("""
+        self.run_test(u"""
             %{get_file(files, 'target.txt')}
             %{get_file(files, 'path.txt')}
             %{get_file(files.subdir, 'target.txt')}
-        """, """
+        """, u"""
             /path/to/source/source.txt
             /just/this/one/source.txt
             /path/to/source/subdir/source.txt
-        """, """
+        """, u"""
             [files]
                 .base_dir = /path/to/source
                 target.txt = source.txt
@@ -976,15 +1024,17 @@ class FilesTestCase(MkexpSimpleTestCase):
         """)
 
     def test_get_file_variable(self):
-        self.run_test("""
+        self.run_test(u"""
+            %{JOB.id}
             %{get_file(files, 'target.txt')}
             %{get_file(files, 'broken.txt')}
             %{get_file(files, 'incomplete.txt')}
-        """, """
+        """, u"""
+            job
             source.txt
             $BASENAME.txt
             ${DOES_NOT_EXIST}.txt
-        """, """
+        """, u"""
             BASENAME = source
             [files]
                 target.txt = $${BASENAME}.txt
@@ -993,13 +1043,13 @@ class FilesTestCase(MkexpSimpleTestCase):
         """)
 
     def test_get_dir(self):
-        self.run_test("""
+        self.run_test(u"""
             %{get_dir(files)}
             %{get_dir(files.subdir)}
-        """, """
+        """, u"""
             /path/to/source
             /path/to/source/subdir
-        """, """
+        """, u"""
             [files]
                 .base_dir = /path/to/source
                 [[subdir]]
@@ -1010,65 +1060,65 @@ class GetTemplatesTestCase(MkexpSimpleTestCase):
 
     def test_by_config_file_name(self):
         other_exp_id = 'test_something_completely_different'
-        writetemplate(self.exp_id, self.job_id, """
+        writetemplate(self.exp_id, self.job_id, u"""
             selected by config file name
         """)
         self.run_no_template(join(other_exp_id, other_exp_id+'.'+self.job_id),
-        """
+        u"""
             selected by config file name
-        """, """
-            EXP_ID = """+other_exp_id+"""
+        """, u"""
+            EXP_ID = """+other_exp_id+u"""
         """)
 
     def test_by_exp_id(self):
         other_exp_id = 'test_something_completely_different'
-        writetemplate(other_exp_id, self.job_id, """
+        writetemplate(other_exp_id, self.job_id, u"""
             selected by EXP_ID
         """)
         self.run_no_template(join(other_exp_id, other_exp_id+'.'+self.job_id),
-        """
+        u"""
             selected by EXP_ID
-        """, """
-            EXP_ID = """+other_exp_id+"""
+        """, u"""
+            EXP_ID = """+other_exp_id+u"""
         """)
 
 class DelimiterTestCase(MkexpSimpleTestCase):
 
     def test_statement(self):
-        self.run_test("""
+        self.run_test(u"""
             {%__mkexp__
                 set x = 'Hello, world!'
             %}
             %{x}
-        """, """
+        """, u"""
             Hello, world!
         """)
 
     def test_comment(self):
-        self.run_test("""
+        self.run_test(u"""
             {#__mkexp__
                 Now you see me - now you don't
             #}
-        """, """
+        """, u"""
         """)
 
 class InheritanceTestCase(MkexpSimpleTestCase):
 
     def test_child_template(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [jobs]
               [[job1]]
               [[job2]]
                 .extends = job1
         """)
-        writetemplate(self.exp_id, 'job1', """
+        writetemplate(self.exp_id, 'job1', u"""
             %{JOB.id} as in job1
         """)
-        writetemplate(self.exp_id, 'job2', """
+        writetemplate(self.exp_id, 'job2', u"""
             %{JOB.id} as in job2
         """)
-        expected = align("""
+        expected = align(u"""
             job2 as in job2
         """)
         ignore = output(script("mkexp "+self.exp_id+".config"))
@@ -1078,17 +1128,17 @@ class InheritanceTestCase(MkexpSimpleTestCase):
         self.assertMultiLineEqual(expected, result)
 
     def test_parent_template(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [jobs]
               [[job1]]
               [[job2]]
                 .extends = job1
         """)
-        writetemplate(self.exp_id, 'job1', """
+        writetemplate(self.exp_id, 'job1', u"""
             %{JOB.id} as in job1
         """)
-        expected = align("""
+        expected = align(u"""
             job2 as in job1
         """)
         ignore = output(script("mkexp "+self.exp_id+".config"))
@@ -1098,7 +1148,7 @@ class InheritanceTestCase(MkexpSimpleTestCase):
         self.assertMultiLineEqual(expected, result)
 
     def test_grandparent_template(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [jobs]
               [[job1]]
@@ -1107,10 +1157,10 @@ class InheritanceTestCase(MkexpSimpleTestCase):
               [[job3]]
                 .extends = job2
         """)
-        writetemplate(self.exp_id, 'job1', """
+        writetemplate(self.exp_id, 'job1', u"""
             %{JOB.id} as in job1
         """)
-        expected = align("""
+        expected = align(u"""
             job3 as in job1
         """)
         ignore = output(script("mkexp "+self.exp_id+".config"))
@@ -1120,7 +1170,7 @@ class InheritanceTestCase(MkexpSimpleTestCase):
         self.assertMultiLineEqual(expected, result)
 
     def test_variable_ancestry(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [jobs]
               var_0 = from jobs
@@ -1137,35 +1187,35 @@ class InheritanceTestCase(MkexpSimpleTestCase):
                 var_0 = not needed
                 var_3 = from job3
         """)
-        writetemplate(self.exp_id, 'job1', """
+        writetemplate(self.exp_id, 'job1', u"""
             %{JOB.id}
             %{JOB.var_0}
             %{JOB.var_1}
             %{JOB.var_2}
             %{JOB.var_3}
         """)
-        expecteds = map(align, (
-            """
+        expecteds = list(map(align, (
+            u"""
                 job1
                 from jobs
                 from job1
                 from job1
                 from job1
             """,
-            """
+            u"""
                 job2
                 from jobs
                 from job1
                 from job2
                 from job2
             """,
-            """
+            u"""
                 job3
                 not needed
                 from job1
                 from job2
                 from job3
-            """))
+            """)))
         ignore = output(script("mkexp "+self.exp_id+".config"))
         for i in (1, 2, 3):
             result = readfile(join("test", "experiments", self.exp_id,
@@ -1174,7 +1224,7 @@ class InheritanceTestCase(MkexpSimpleTestCase):
             self.assertMultiLineEqual(expecteds[i-1], result)
 
     def test_namelist_override(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [namelists]
               [[namelist]]
@@ -1195,21 +1245,21 @@ class InheritanceTestCase(MkexpSimpleTestCase):
                     [[[[[group]]]]]
                       var = 2
         """)
-        writetemplate(self.exp_id, 'job', """
+        writetemplate(self.exp_id, 'job', u"""
             %{NAMELIST}
         """)
         expecteds = {
-            'job':  align("""
+            'job':  align(u"""
                         &group
                             var = 999
                         /
                     """),
-            'job1': align("""
+            'job1': align(u"""
                         &group
                             var = 1
                         /
                     """),
-            'job2': align("""
+            'job2': align(u"""
                         &group
                             var = 2
                         /
@@ -1225,7 +1275,7 @@ class InheritanceTestCase(MkexpSimpleTestCase):
 class JobSiblingsTestCase(MkexpSimpleTestCase):
 
     def test_sibling_lookup(self):
-        writeconfig(self.exp_id, """
+        writeconfig(self.exp_id, u"""
             EXP_TYPE =
             [jobs]
               [[job1]]
@@ -1233,17 +1283,17 @@ class JobSiblingsTestCase(MkexpSimpleTestCase):
               [[job2]]
                 seniority = younger
         """)
-        writetemplate(self.exp_id, 'job1', """
+        writetemplate(self.exp_id, 'job1', u"""
             %{JOB.id}: %{JOB.seniority}
             %{jobs.job1.id}: %{jobs.job1.seniority}
             %{jobs.job2.id}: %{jobs.job2.seniority}
         """)
-        writetemplate(self.exp_id, 'job2', """
+        writetemplate(self.exp_id, 'job2', u"""
             %{JOB.id}: %{JOB.seniority}
             %{jobs.job2.id}: %{jobs.job2.seniority}
             %{jobs.job1.id}: %{jobs.job1.seniority}
         """)
-        expected = align("""
+        expected = align(u"""
             job1: elder
             job1: elder
             job2: younger
@@ -1264,7 +1314,7 @@ class NativeVariableTestCase(MkexpSimpleTestCase):
     def test_var_statement(self):
         exp_id = "test_var_statement"
         job_id = "job"
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE = 
             GLOBAL1 = 123$${VAR1}456
             GLOBAL2 = $${VAR2}$${VAR3}
@@ -1275,17 +1325,17 @@ class NativeVariableTestCase(MkexpSimpleTestCase):
                 [[[group]]]
                   key = abc$${var}def
             [jobs]
-              [["""+job_id+"""]]
+              [["""+job_id+u"""]]
                 .var_format = <<<%s>>>
         """)
-        writetemplate(exp_id, job_id, """
+        writetemplate(exp_id, job_id, u"""
             GLOBAL1=%{GLOBAL1}
             GLOBAL2=%{GLOBAL2}
             GLOBAL3='%{GLOBAL3|join(" ")}'
             GLOBAL4=%{context("GLOBAL<<<FOUR>>>")}
             %{NAMELIST}
         """)
-        expected = align("""
+        expected = align(u"""
             GLOBAL1=123<<<VAR1>>>456
             GLOBAL2=<<<VAR2>>><<<VAR3>>>
             GLOBAL3='1 <<<VAR2>>> 3'
@@ -1301,7 +1351,7 @@ class NativeVariableTestCase(MkexpSimpleTestCase):
 
     def test_var_separation(self):
         exp_id = "test_var_separation"
-        writeconfig(exp_id, """
+        writeconfig(exp_id, u"""
             EXP_TYPE = 
             [jobs]
               use_native_var = $${native_var}
@@ -1309,16 +1359,16 @@ class NativeVariableTestCase(MkexpSimpleTestCase):
                 .var_format = <<<%s>>>
               [[job2]]
         """)
-        writetemplate(exp_id, "job1", """
+        writetemplate(exp_id, "job1", u"""
             %{JOB.use_native_var}
         """)
-        writetemplate(exp_id, "job2", """
+        writetemplate(exp_id, "job2", u"""
             %{JOB.use_native_var}
         """)
-        expected1 = align("""
+        expected1 = align(u"""
             <<<native_var>>>
         """)
-        expected2 = align("""
+        expected2 = align(u"""
             ${native_var}
         """)
         ignore = output(script("mkexp "+exp_id+".config"))
@@ -1329,5 +1379,17 @@ class NativeVariableTestCase(MkexpSimpleTestCase):
         self.assertMultiLineEqual(expected1, result1)
         self.assertMultiLineEqual(expected2, result2)
 
+class UnicodeTestCase(MkexpSimpleTestCase):
+
+    def test_value(self):
+        self.run_test(u"""
+            %{VAR}
+        """, u"""
+            ÄÖÜäöüß😉
+        """, u"""
+            VAR = ÄÖÜäöüß😉
+        """)
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/test0001.config b/test/test0001.config
index c616561c490eb9dff0ac0bd0e32beaf8f780aa38..b78434dddd364d588086e8f2d161ba3f76d8467b 100644
--- a/test/test0001.config
+++ b/test/test0001.config
@@ -1,3 +1,5 @@
+# Basic unicode check: ÄÖÜäöüß😉
+
 EXP_TYPE = DEFAULT
 
 VAR1 = value1