Repository: sciunto-org/python-bibtexparser
Pull request #173 (2017-07-31 22:14:08)

Fix: url replaced to link on homogenize_fields (#171)
- `urls`, `link`, and `links` are now replaced by `url`,
- adds some test to homogenize_fields.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/12630454/badge)](https://coveralls.io/builds/12630454)

Coverage decreased (-0.6%) to 96.417% when pulling **343e7052b12d6564340cf6daff61df64a3c32e80 on omangin:fix/171** into **e49276b0c7da9d83b3b389b3fc72ab6c4fb705ff on sciunto-org:master**.


Patch:
diff --git a/.travis.yml b/.travis.yml
index 20f2ef9..6c08ac7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,3 @@
-dist: trusty
 language: python
 matrix:
   include:
@@ -12,10 +11,8 @@ matrix:
       env: TEST_SUITE=suite_3_5
     - python: "3.6"
       env: TEST_SUITE=suite_3_6
-    - python: "pypy-5.7.1"
+    - python: "pypy"
       env: TEST_SUITE=suite_pypy
-    - python: "pypy3.5-5.8.0"
-      env: TEST_SUITE=suite_pypy3
 install:
   - if [[ $TEST_SUITE == suite_3_6 ]]; then
         pip install sphinx;
diff --git a/bibtexparser/bibdatabase.py b/bibtexparser/bibdatabase.py
index 6004de5..79da290 100644
--- a/bibtexparser/bibdatabase.py
+++ b/bibtexparser/bibdatabase.py
@@ -23,31 +23,26 @@ STANDARD_TYPES = set([
     'proceedings',
     'techreport',
     'unpublished'])
-COMMON_STRINGS = OrderedDict([
-    ('jan', 'January'),
-    ('feb', 'February'),
-    ('mar', 'March'),
-    ('apr', 'April'),
-    ('may', 'May'),
-    ('jun', 'June'),
-    ('jul', 'July'),
-    ('aug', 'August'),
-    ('sep', 'September'),
-    ('oct', 'October'),
-    ('nov', 'November'),
-    ('dec', 'December'),
-    ])
-
-
-class UndefinedString(KeyError):
-    pass
+COMMON_STRINGS = {
+    'jan': 'January',
+    'feb': 'February',
+    'mar': 'March',
+    'apr': 'April',
+    'may': 'May',
+    'jun': 'June',
+    'jul': 'July',
+    'aug': 'August',
+    'sep': 'September',
+    'oct': 'October',
+    'nov': 'November',
+    'dec': 'December',
+    }
 
 
 class BibDatabase(object):
     """
     Bibliographic database object that follows the data structure of a BibTeX file.
     """
-
     def __init__(self):
         #: List of BibTeX entries, for example `@book{...}`, `@article{...}`, etc. Each entry is a simple dict with
         #: BibTeX field-value pairs, for example `'author': 'Bird, R.B. and Armstrong, R.C. and Hassager, O.'` Each
@@ -98,17 +93,16 @@ class BibDatabase(object):
 
     def expand_string(self, name):
         try:
-            return BibDataStringExpression.expand_if_expression(
-                self.strings[name])
+            return self.strings[name]
         except KeyError:
-            raise(UndefinedString(name))
+            raise(KeyError("Unknown string: {}.".format(name)))
 
 
 class BibDataString(object):
     """
     Represents a bibtex string.
 
-    This object enables maintaining string expressions as list of strings
+    This object enables mainting string expressions as list of strings
     and BibDataString. Can be interpolated from Bibdatabase.
     """
 
@@ -116,9 +110,6 @@ class BibDataString(object):
         self._bibdatabase = bibdatabase
         self.name = name.lower()
 
-    def __eq__(self, other):
-        return isinstance(other, BibDataString) and self.name == other.name
-
     def __repr__(self):
         return "BibDataString({})".format(self.name.__repr__())
 
@@ -129,97 +120,3 @@ class BibDataString(object):
         :returns: string
         """
         return self._bibdatabase.expand_string(self.name)
-
-    def get_dependencies(self, known_dependencies=set()):
-        """Recursively tracks strings on which the expression depends.
-
-        :param kown_dependencies: dependencies to ignore
-        """
-        raise NotImplementedError
-
-    @staticmethod
-    def expand_string(string_or_bibdatastring):
-        """
-        Eventually replaces a bibdatastring by its value.
-
-        :param string_or_bibdatastring: the parsed token
-        :type string_expr: string or BibDataString
-        :returns: string
-        """
-        if isinstance(string_or_bibdatastring, BibDataString):
-            return string_or_bibdatastring.get_value()
-        else:
-            return string_or_bibdatastring
-
-
-class BibDataStringExpression(object):
-    """
-    Represents a bibtex string expression.
-
-    String expressions are sequences of regular strings and bibtex strings.
-    This object enables maintaining string expressions as list of strings.
-    The expression are represented as lists of regular strings and
-    BibDataStrings. They can be interpolated from Bibdatabase.
-
-    BibDataStringExpression(e)
-
-    :param e: list of strings and BibDataStrings
-    """
-
-    def __init__(self, expression):
-        self.expr = expression
-
-    def __eq__(self, other):
-        return isinstance(other, BibDataStringExpression) and self.expr == other.expr
-
-    def __repr__(self):
-        return "BibDataStringExpression({})".format(self.expr.__repr__())
-
-    def get_value(self):
-        """
-        Replaces bibdatastrings by their values in the expression.
-
-        :returns: string
-        """
-        return ''.join([BibDataString.expand_string(s) for s in self.expr])
-
-    def apply_on_strings(self, fun):
-        """
-        Maps a function on strings in expression, keeping unchanged
-        BibDataStrings.
-
-        :param fun: function from strings to strings
-        """
-        self.expr = [s if isinstance(s, BibDataString) else fun(s)
-                     for s in self.expr]
-
-    @staticmethod
-    def expand_if_expression(string_or_expression):
-        """
-        Eventually replaces a BibDataStringExpression by its value.
-
-        :param string_or_expression: the object to expand
-        :type string_expr: string or BibDataStringExpression
-        :returns: string
-        """
-        if isinstance(string_or_expression, BibDataStringExpression):
-            return string_or_expression.get_value()
-        else:
-            return string_or_expression
-
-    @staticmethod
-    def expression_if_needed(tokens):
-        """Build expression only if tokens are not a regular value.
-        """
-        if len(tokens) == 1 and not isinstance(tokens[0], BibDataString):
-            return tokens[0]
-        else:
-            return BibDataStringExpression(tokens)
-
-
-def as_text(text_string_or_expression):
-    if isinstance(text_string_or_expression,
-                  (BibDataString, BibDataStringExpression)):
-        return text_string_or_expression.get_value()
-    else:
-        return TEXT_TYPE(text_string_or_expression)
diff --git a/bibtexparser/bibtexexpression.py b/bibtexparser/bibtexexpression.py
index 28747dd..857ad7c 100644
--- a/bibtexparser/bibtexexpression.py
+++ b/bibtexparser/bibtexexpression.py
@@ -1,11 +1,9 @@
 import pyparsing as pp
 
-from .bibdatabase import BibDataStringExpression
-
 
 # General helpers
 
-def _strip_after_new_lines(s):
+def strip_after_new_lines(s):
     """Removes leading and trailing whitespaces in all but first line."""
     lines = s.splitlines()
     if len(lines) > 1:
@@ -13,18 +11,6 @@ def _strip_after_new_lines(s):
     return '\n'.join(lines)
 
 
-def strip_after_new_lines(s):
-    """Removes leading and trailing whitespaces in all but first line.
-
-    :param s: string or BibDataStringExpression
-    """
-    if isinstance(s, BibDataStringExpression):
-        s.apply_on_strings(_strip_after_new_lines)
-        return s
-    else:
-        return _strip_after_new_lines(s)
-
-
 def add_logger_parse_action(expr, log_func):
     """Register a callback on expression parsing with the adequate message."""
     def action(s, l, t):
@@ -64,6 +50,8 @@ def field_to_pair(s, l, t):
     :returns: (name, value).
     """
     f = t.get('Field')
+    # Not sure it is desirable here to strip but it is for conformance
+    # to previous implementation
     return (f.get('FieldName'),
             strip_after_new_lines(f.get('Value')))
 
diff --git a/bibtexparser/bparser.py b/bibtexparser/bparser.py
index 2019d0a..a675c6f 100644
--- a/bibtexparser/bparser.py
+++ b/bibtexparser/bparser.py
@@ -11,8 +11,7 @@ import sys
 import io
 import logging
 
-from bibtexparser.bibdatabase import (BibDatabase, BibDataString, as_text,
-                                      BibDataStringExpression, STANDARD_TYPES)
+from bibtexparser.bibdatabase import BibDatabase, BibDataString, STANDARD_TYPES
 from bibtexparser.bibtexexpression import BibtexExpression
 
 logger = logging.getLogger(__name__)
@@ -66,7 +65,6 @@ class BibTexParser(object):
                  customization=None,
                  ignore_nonstandard_types=True,
                  homogenize_fields=False,
-                 interpolate_strings=True,
                  common_strings=False):
         """
         Creates a parser for rading BibTeX files
@@ -97,9 +95,6 @@ class BibTexParser(object):
         #: Default: `False`.
         self.homogenize_fields = homogenize_fields
 
-        #: Interpolate Bibtex Strings or keep the structure
-        self.interpolate_strings = interpolate_strings
-
         # On some sample data files, the character encoding detection simply
         # hangs We are going to default to utf8, and mandate it.
         self.encoding = 'utf8'
@@ -110,9 +105,9 @@ class BibTexParser(object):
             'keywords': u'keyword',
             'authors': u'author',
             'editors': u'editor',
-            'url': u'link',
-            'urls': u'link',
-            'links': u'link',
+            'urls': u'url',
+            'link': u'url',
+            'links': u'url',
             'subjects': u'subject'
         }
 
@@ -162,14 +157,9 @@ class BibTexParser(object):
         self._expr.set_string_name_parse_action(
             lambda s, l, t:
                 BibDataString(self.bib_database, t[0]))
-        if self.interpolate_strings:
-            maybe_interpolate = lambda expr: as_text(expr)
-        else:
-            maybe_interpolate = lambda expr: expr
         self._expr.set_string_expression_parse_action(
             lambda s, l, t:
-                maybe_interpolate(
-                    BibDataStringExpression.expression_if_needed(t)))
+                self._interpolate_string_expression(t))
 
         # Add notice to logger
         self._expr.add_log_function(logger.debug)
@@ -292,9 +282,31 @@ class BibTexParser(object):
         if string_key in self.bib_database.strings:
             logger.warning('Overwritting existing string for key: %s.',
                            string_key)
-        logger.debug(u'Store string: {} -> {}'.format(string_key, string))
+        logger.debug('Store string: {} -> {}'.format(string_key, string))
         self.bib_database.strings[string_key] = self._clean_val(string)
 
+    def _interpolate_string_expression(self, string_expr):
+        """
+        Replaces bibdatastrings by their values in an expression.
+
+        :param string_expr: the parsed string as a list
+        :type string_expr: list
+        """
+        return ''.join([self._expand_string(s) for s in string_expr])
+
+    def _expand_string(self, string_or_bibdatastring):
+        """
+        Eventually replaces a bibdatastring by its value.
+
+        :param string_or_bibdatastring: the parsed token
+        :type string_expr: string or BibDataString
+        :returns: string
+        """
+        if isinstance(string_or_bibdatastring, BibDataString):
+            return string_or_bibdatastring.get_value()
+        else:
+            return string_or_bibdatastring
+
     def _add_preamble(self, preamble):
         """
         Stores a preamble.
diff --git a/bibtexparser/bwriter.py b/bibtexparser/bwriter.py
index 428d116..365f977 100644
--- a/bibtexparser/bwriter.py
+++ b/bibtexparser/bwriter.py
@@ -3,12 +3,8 @@
 # Author: Francois Boulogne
 # License:
 
-
 import logging
-from bibtexparser.bibdatabase import (BibDatabase, COMMON_STRINGS,
-                                      BibDataString,
-                                      BibDataStringExpression)
-
+from bibtexparser.bibdatabase import BibDatabase
 
 logger = logging.getLogger(__name__)
 
@@ -22,15 +18,6 @@ def to_bibtex(parsed):
     return BibTexWriter().write(parsed)
 
 
-def _str_or_expr_to_bibtex(e):
-    if isinstance(e, BibDataStringExpression):
-        return ' # '.join([_str_or_expr_to_bibtex(s) for s in e.expr])
-    elif isinstance(e, BibDataString):
-        return e.name
-    else:
-        return '{' + e + '}'
-
-
 class BibTexWriter(object):
     """
     Writer to convert a :class:`BibDatabase` object to a string or file formatted as a BibTeX file.
@@ -51,7 +38,7 @@ class BibTexWriter(object):
 
     _valid_contents = ['entries', 'comments', 'preambles', 'strings']
 
-    def __init__(self, write_common_strings=False):
+    def __init__(self):
         #: List of BibTeX elements to write, valid values are `entries`, `comments`, `preambles`, `strings`.
         self.contents = ['comments', 'preambles', 'strings', 'entries']
         #: Character(s) for indenting BibTeX field-value pairs. Default: single space.
@@ -70,10 +57,10 @@ class BibTexWriter(object):
         #: (common in functional languages), use this to enable
         #: comma first syntax as the bwritter output
         self.comma_first = False
+
         #: internal variable used if self.align_values = True
         self._max_field_width = 0
-        #: Whether common strings are written
-        self.common_strings = write_common_strings
+
 
     def write(self, bib_database):
         """
@@ -120,19 +107,16 @@ class BibTexWriter(object):
         # first those keys which are both in self.display_order and in entry.keys
         display_order = [i for i in self.display_order if i in entry]
         # then all the other fields sorted alphabetically
+        more_fields = [i for i in sorted(entry) if i not in self.display_order]
         display_order += [i for i in sorted(entry) if i not in self.display_order]
-        if self.comma_first:
-            field_fmt = u"\n{indent}, {field:<{field_max_w}} = {value}"
-        else:
-            field_fmt = u",\n{indent}{field:<{field_max_w}} = {value}"
+
         # Write field = value lines
         for field in [i for i in display_order if i not in ['ENTRYTYPE', 'ID']]:
             try:
-                bibtex += field_fmt.format(
-                    indent=self.indent,
-                    field=field,
-                    field_max_w=self._max_field_width,
-                    value=_str_or_expr_to_bibtex(entry[field]))
+                if self.comma_first:
+                    bibtex += "\n" + self.indent + ", " + "{0:<{1}}".format(field, self._max_field_width) + " = {" + entry[field] + "}"
+                else:
+                    bibtex += ",\n" + self.indent + "{0:<{1}}".format(field, self._max_field_width) + " = {" + entry[field] + "}"
             except TypeError:
                 raise TypeError(u"The field %s in entry %s must be a string"
                                 % (field, entry['ID']))
@@ -148,13 +132,5 @@ class BibTexWriter(object):
                         for preamble in bib_database.preambles])
 
     def _strings_to_bibtex(self, bib_database):
-        return ''.join([
-            u'@string{{{name} = {value}}}\n{sep}'.format(
-                name=name,
-                value=_str_or_expr_to_bibtex(value),
-                sep=self.entry_separator)
-            for name, value in bib_database.strings.items()
-            if (self.common_strings or
-                name not in COMMON_STRINGS or  # user defined string
-                value != COMMON_STRINGS[name]  # string has been updated
-                )])
+        return ''.join(['@string{{{0} = "{1}"}}\n{2}'.format(name, value, self.entry_separator)
+                        for name, value in bib_database.strings.items()])
diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst
index e93ecf3..1bd9a76 100644
--- a/docs/source/tutorial.rst
+++ b/docs/source/tutorial.rst
@@ -338,50 +338,3 @@ They are sometimes coded like this ``\'{e}`` but this is not the correct way, ``
 .. Note::
 
     If you want to mix different customization functions, you can write your own function.
-
-
-Using bibtex strings
---------------------
-
-.. Warning:: support for bibtex strings representation is still an experimental feature; the way strings are represented is likely to change in future releases.
-
-Bibtex strings and string expressions are expanded by default into the value they represent.
-This behavior is controlled by the ``interpolate_string`` argument of the BibTexParser. It defaults to ``True`` but can be set to ``False``, in which case bibtex strings and string expressions from input files are represented with the :class:`bibdatabase.BibDataString` and :class:`bibdatabase.BibDataStringExpression` from the :mod:`bibdatabase` module. Both classes retain the intrinsic structure of the string or expression so that they can be written to a new file, the same way. Each instance provides a :func:`get_value` method to interpolate the string or expression and the module also provide an :func:`bibdatabase.as_text` helper to expand a string or an expression when needed.
-
-Using the code would yield the following output.
-
-.. code-block:: python
-
-    from bibtexparser.bparser import BibTexParser
-    from bibtexparser.bibdatabase import as_text
-
-
-    bibtex = """@STRING{ jean = "Jean"}
-    
-    @ARTICLE{Cesar2013,
-      author = jean # { César},
-      title = {An amazing title},
-      year = {2013},
-      month = jan,
-      volume = {12},
-      pages = {12--23},
-      journal = {Nice Journal},
-    }
-    """
-
-    bp = BibTexParser(interpolate_strings=False)
-    bib_database = bp.parse(bibtex)
-    bib_database.entries[0]
-    as_text(bd.entries[0]['author'])
-
-.. code-block:: python
-
-    {'ENTRYTYPE': 'article',
-     'ID': 'Cesar2013',
-     'author': BibDataStringExpression([BibDataString('jean'), ' César']),
-     'journal': 'Nice Journal',
-     'month': BibDataStringExpression([BibDataString('jan')]),
-     'pages': '12--23',
-     'title': 'An amazing title',
-     }
-    'Jean César'


Test patch:
diff --git a/bibtexparser/tests/data/article_homogenize.bib b/bibtexparser/tests/data/article_homogenize.bib
new file mode 100644
index 0000000..06a21d4
--- /dev/null
+++ b/bibtexparser/tests/data/article_homogenize.bib
@@ -0,0 +1,16 @@
+@ARTICLE{Cesar2013,
+  authors = {Jean César},
+  title = {An amazing title},
+  year = {2013},
+  month = "jan",
+  volume = {12},
+  pages = {12-23},
+  journal = {Nice Journal},
+  abstract = {This is an abstract. This line should be long enough to test
+multilines... and with a french érudit word},
+  comments = {A comment},
+  editors = {Edith Or},
+  keywords = {keyword1, keyword2},
+  links = {http://my.link/to-content},
+  subjects = "Some topic of interest",
+}
diff --git a/bibtexparser/tests/data/article_with_strings.bib b/bibtexparser/tests/data/article_with_strings.bib
deleted file mode 100644
index 744163d..0000000
--- a/bibtexparser/tests/data/article_with_strings.bib
+++ /dev/null
@@ -1,15 +0,0 @@
-@STRING{ nice_journal = "Nice Journal" }
-@STRING ( jean={Jean} )
-@STRING{cesar = {César}}
-
-@ARTICLE{Cesar2013,
-  author = jean # " " # cesar,
-  title = {An amazing title},
-  year = {2013},
-  month = jan,
-  volume = {12},
-  pages = {12-23},
-  journal = nice_journal,
-  comments = {A comment},
-  keyword = {keyword1, keyword2},
-}
diff --git a/bibtexparser/tests/data/article_with_strings_output.bib b/bibtexparser/tests/data/article_with_strings_output.bib
deleted file mode 100644
index 0c70dbf..0000000
--- a/bibtexparser/tests/data/article_with_strings_output.bib
+++ /dev/null
@@ -1,18 +0,0 @@
-@string{nice_journal = {Nice Journal}}
-
-@string{jean = {Jean}}
-
-@string{cesar = {César}}
-
-@article{Cesar2013,
- author = jean # { } # cesar,
- comments = {A comment},
- journal = nice_journal,
- keyword = {keyword1, keyword2},
- month = jan,
- pages = {12-23},
- title = {An amazing title},
- volume = {12},
- year = {2013}
-}
-
diff --git a/bibtexparser/tests/data/common_strings.bib b/bibtexparser/tests/data/common_strings.bib
deleted file mode 100644
index a0c386d..0000000
--- a/bibtexparser/tests/data/common_strings.bib
+++ /dev/null
@@ -1,24 +0,0 @@
-@string{jan = {January}}
-
-@string{feb = {February}}
-
-@string{mar = {March}}
-
-@string{apr = {April}}
-
-@string{may = {May}}
-
-@string{jun = {June}}
-
-@string{jul = {July}}
-
-@string{aug = {August}}
-
-@string{sep = {September}}
-
-@string{oct = {October}}
-
-@string{nov = {November}}
-
-@string{dec = {December}}
-
diff --git a/bibtexparser/tests/data/website.bib b/bibtexparser/tests/data/website.bib
index ad4d1a5..22d2761 100644
--- a/bibtexparser/tests/data/website.bib
+++ b/bibtexparser/tests/data/website.bib
@@ -1,6 +1,6 @@
 @misc{feder2006,
  title = {BibTeX},
  author = {Alexander Feder},
- url = {http://bibtex.org},
+ link = {http://bibtex.org},
  year = {2006}
 }
diff --git a/bibtexparser/tests/test_bibdatabase.py b/bibtexparser/tests/test_bibdatabase.py
index 964109b..c4296da 100644
--- a/bibtexparser/tests/test_bibdatabase.py
+++ b/bibtexparser/tests/test_bibdatabase.py
@@ -1,6 +1,5 @@
 import unittest
-from bibtexparser.bibdatabase import (BibDatabase, BibDataString,
-                                      BibDataStringExpression)
+from bibtexparser.bibdatabase import BibDatabase
 
 
 class TestBibDatabase(unittest.TestCase):
@@ -12,7 +11,7 @@ class TestBibDatabase(unittest.TestCase):
                 'volume': '1',
                 'title': 'Dynamics of Polymeric Liquid',
                 'author': 'Bird, R.B. and Armstrong, R.C. and Hassager, O.'
-                }]
+               }]
 
     def test_entries_list_method(self):
         bib_db = BibDatabase()
@@ -25,77 +24,5 @@ class TestBibDatabase(unittest.TestCase):
         self.assertEqual(bib_db.entries_dict, bib_db.get_entry_dict())
 
 
-class TestBibDataString(unittest.TestCase):
-
-    def setUp(self):
-        self.bd = BibDatabase()
-
-    def test_name_is_lower(self):
-        bds = BibDataString(self.bd, 'nAmE')
-        self.assertTrue(bds.name.islower())
-
-    def test_raises_KeyError(self):
-        bds = BibDataString(self.bd, 'name')
-        with self.assertRaises(KeyError):
-            bds.get_value()
-
-    def test_get_value(self):
-        bds = BibDataString(self.bd, 'name')
-        self.bd.strings['name'] = 'value'
-        self.assertEqual(bds.get_value(), 'value')
-
-    def test_expand_string(self):
-        bds = BibDataString(self.bd, 'name')
-        self.bd.strings['name'] = 'value'
-        self.assertEqual(BibDataString.expand_string('name'), 'name')
-        self.assertEqual(BibDataString.expand_string(bds), 'value')
-
-    def test_get_value_string_is_defined_by_expression(self):
-        self.bd.strings['name'] = 'string'
-        exp = BibDataStringExpression(['this is a ',
-                                       BibDataString(self.bd, 'name')])
-        self.bd.strings['exp'] = exp
-        bds = BibDataString(self.bd, 'exp')
-        self.assertEqual(bds.get_value(), 'this is a string')
-
-    def test_strings_are_equal_iif_name_is_equal(self):
-        self.bd.strings['a'] = 'foo'
-        self.bd.strings['b'] = 'foo'
-        a1 = BibDataString(self.bd, 'a')
-        a2 = BibDataString(self.bd, 'a')
-        b = BibDataString(self.bd, 'b')
-        self.assertEqual(a1, a2)
-        self.assertNotEqual(a1, b)
-        self.assertNotEqual(a1, b)
-        self.assertNotEqual(a1, "foo")
-
-
-class TestBibDataStringExpression(unittest.TestCase):
-
-    def setUp(self):
-        self.bd = BibDatabase()
-        self.bd.strings['name'] = 'value'
-        self.bds = BibDataString(self.bd, 'name')
-
-    def test_get_value(self):
-        exp = BibDataStringExpression(
-            ["The string has value: ", self.bds, '.'])
-        self.assertEqual(exp.get_value(), 'The string has value: value.')
-
-    def test_raises_KeyError(self):
-        bds = BibDataString(self.bd, 'unknown')
-        exp = BibDataStringExpression([bds, self.bds, 'text'])
-        with self.assertRaises(KeyError):
-            exp.get_value()
-
-    def test_equations_are_equal_iif_same(self):
-        a1 = BibDataString(self.bd, 'a')
-        a2 = BibDataString(self.bd, 'a')
-        exp = BibDataStringExpression([a1, self.bds, 'text'])
-        self.assertEqual(exp, BibDataStringExpression([a2, self.bds, 'text']))
-        self.assertNotEqual(exp, BibDataStringExpression(['foo', self.bds, 'text']))
-        self.assertNotEqual(exp, 'foovaluetext')
-
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/bibtexparser/tests/test_bibtex_strings.py b/bibtexparser/tests/test_bibtex_strings.py
index 3a70ab4..775ba27 100644
--- a/bibtexparser/tests/test_bibtex_strings.py
+++ b/bibtexparser/tests/test_bibtex_strings.py
@@ -1,16 +1,12 @@
-import io
 import unittest
 import codecs
 import bibtexparser
-from bibtexparser.bibdatabase import (BibDatabase, BibDataString,
-                                      BibDataStringExpression)
+from bibtexparser.bibdatabase import BibDatabase
 from bibtexparser.bparser import BibTexParser
-from bibtexparser.bwriter import BibTexWriter
 from collections import OrderedDict
 
 
 class TestStringParse(unittest.TestCase):
-
     def test_single_string_parse_count(self):
         bibtex_str = '@string{name1 = "value1"}\n\n'
         bib_database = bibtexparser.loads(bibtex_str)
@@ -50,13 +46,13 @@ class TestStringParse(unittest.TestCase):
         self.assertEqual(res, expected)
 
 
-class TestStringWrite(unittest.TestCase):
 
+class TestStringWrite(unittest.TestCase):
     def test_single_string_write(self):
         bib_database = BibDatabase()
         bib_database.strings['name1'] = 'value1'
         result = bibtexparser.dumps(bib_database)
-        expected = '@string{name1 = {value1}}\n\n'
+        expected = '@string{name1 = "value1"}\n\n'
         self.assertEqual(result, expected)
 
     def test_multiple_string_write(self):
@@ -64,36 +60,5 @@ class TestStringWrite(unittest.TestCase):
         bib_database.strings['name1'] = 'value1'
         bib_database.strings['name2'] = 'value2'  # Order is important!
         result = bibtexparser.dumps(bib_database)
-        expected = '@string{name1 = {value1}}\n\n@string{name2 = {value2}}\n\n'
-        self.assertEqual(result, expected)
-
-    def test_ignore_common_strings(self):
-        bib_database = BibDatabase()
-        bib_database.load_common_strings()
-        result = bibtexparser.dumps(bib_database)
-        self.assertEqual(result, '')
-
-    def test_ignore_common_strings_only_if_not_overloaded(self):
-        bib_database = BibDatabase()
-        bib_database.load_common_strings()
-        bib_database.strings['jan'] = 'Janvier'
-        result = bibtexparser.dumps(bib_database)
-        self.assertEqual(result, '@string{jan = {Janvier}}\n\n')
-
-    def test_write_common_strings(self):
-        bib_database = BibDatabase()
-        bib_database.load_common_strings()
-        writer = BibTexWriter(write_common_strings=True)
-        result = bibtexparser.dumps(bib_database, writer=writer)
-        with io.open('bibtexparser/tests/data/common_strings.bib') as f:
-            expected = f.read()
-        self.assertEqual(result, expected)
-
-    def test_write_dependent_strings(self):
-        bib_database = BibDatabase()
-        bib_database.strings['title'] = 'Mr'
-        expr = BibDataStringExpression([BibDataString(bib_database, 'title'), 'Smith'])
-        bib_database.strings['name'] = expr
-        result = bibtexparser.dumps(bib_database)
-        expected = '@string{title = {Mr}}\n\n@string{name = title # {Smith}}\n\n'
+        expected = '@string{name1 = "value1"}\n\n@string{name2 = "value2"}\n\n'
         self.assertEqual(result, expected)
diff --git a/bibtexparser/tests/test_bparser.py b/bibtexparser/tests/test_bparser.py
index 33cfd3f..ebc83d0 100644
--- a/bibtexparser/tests/test_bparser.py
+++ b/bibtexparser/tests/test_bparser.py
@@ -6,8 +6,6 @@ import unittest
 import codecs
 
 from bibtexparser.bparser import BibTexParser
-from bibtexparser.bibdatabase import (COMMON_STRINGS, BibDataStringExpression,
-                                      BibDataString)
 from bibtexparser.customization import *
 from bibtexparser import customization
 
@@ -520,53 +518,5 @@ class TestBibtexParserList(unittest.TestCase):
             }]
         self.assertEqual(res, expected)
 
-    def test_string_definitions(self):
-        with open('bibtexparser/tests/data/article_with_strings.bib', 'r') as bibfile:
-            bib = BibTexParser(bibfile.read(), common_strings=True)
-        res = dict(bib.strings)
-        expected = COMMON_STRINGS.copy()
-        expected.update({
-                'nice_journal': 'Nice Journal',
-                'jean': 'Jean',
-                'cesar': "César",
-                })
-        self.assertEqual(res, expected)
-
-    def test_string_is_interpolated(self):
-        with open('bibtexparser/tests/data/article_with_strings.bib', 'r') as bibfile:
-            bib = BibTexParser(bibfile.read(), common_strings=True,
-                               interpolate_strings=True)
-        res = bib.get_entry_list()
-        expected = [{
-            'keyword': 'keyword1, keyword2',
-            'ENTRYTYPE': 'article',
-            'year': '2013',
-            'month': 'January',
-            'journal': 'Nice Journal',
-            'ID': 'Cesar2013',
-            'pages': '12-23',
-            'title': 'An amazing title',
-            'comments': 'A comment',
-            'author': 'Jean César',
-            'volume': '12',
-            }]
-        self.assertEqual(res, expected)
-
-    def test_string_is_not_interpolated(self):
-        with open('bibtexparser/tests/data/article_with_strings.bib', 'r') as bibfile:
-            bib = BibTexParser(bibfile.read(), common_strings=True,
-                               interpolate_strings=False)
-        res = bib.get_entry_list()[0]
-        self.assertIsInstance(res['month'], BibDataStringExpression)
-        self.assertEqual(len(res['month'].expr), 1)
-        self.assertEqual(res['month'].get_value(), 'January')
-        self.assertIsInstance(res['author'], BibDataStringExpression)
-        self.assertEqual(len(res['author'].expr), 3)
-        self.assertEqual(res['author'].get_value(), 'Jean César')
-        self.assertIsInstance(res['journal'], BibDataStringExpression)
-        self.assertEqual(len(res['journal'].expr), 1)
-        self.assertEqual(res['journal'].get_value(), 'Nice Journal')
-
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/bibtexparser/tests/test_bwriter.py b/bibtexparser/tests/test_bwriter.py
index c06a670..c5d0262 100644
--- a/bibtexparser/tests/test_bwriter.py
+++ b/bibtexparser/tests/test_bwriter.py
@@ -6,8 +6,6 @@
 from __future__ import unicode_literals
 
 import unittest
-import os
-import io
 import sys
 
 from bibtexparser.bparser import BibTexParser
@@ -15,37 +13,45 @@ from bibtexparser.bwriter import BibTexWriter, to_bibtex
 from bibtexparser.customization import author
 
 
-def _data_path(filename):
-    return os.path.join('bibtexparser/tests/data', filename)
-
-
 class TestBibtexWriterList(unittest.TestCase):
 
+    ###########
+    # ARTICLE
+    ###########
     def test_article(self):
-        with io.open(_data_path('article.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/article.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read())
 
-        with io.open(_data_path('article_output.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/article_output.bib', 'r') as bibfile:
             expected = bibfile.read()
         result = to_bibtex(bib)
+        if not sys.version_info >= (3, 0):
+            if isinstance(result, unicode):
+                result = result.encode('utf-8')
         self.maxDiff = None
         self.assertEqual(expected, result)
 
+    ###########
+    # BOOK
+    ###########
     def test_book(self):
-        with io.open(_data_path('book.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/book.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read())
 
-        with io.open(_data_path('book_output.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/book_output.bib', 'r') as bibfile:
             expected = bibfile.read()
         result = to_bibtex(bib)
         self.maxDiff = None
         self.assertEqual(expected, result)
 
+    ###########
+    # COMMA FIRST
+    ###########
     def test_comma_first(self):
-        with io.open(_data_path('book.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/book.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read())
 
-        with io.open(_data_path('book_comma_first.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/book_comma_first.bib', 'r') as bibfile:
             expected = bibfile.read()
         writer = BibTexWriter()
         writer.indent = '   '
@@ -54,28 +60,24 @@ class TestBibtexWriterList(unittest.TestCase):
         self.maxDiff = None
         self.assertEqual(expected, result)
 
+    ###########
+    # MULTIPLE
+    ###########
     def test_multiple(self):
-        with io.open(_data_path('multiple_entries.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/multiple_entries.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read())
 
-        with io.open(_data_path('multiple_entries_output.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/multiple_entries_output.bib', 'r') as bibfile:
             expected = bibfile.read()
         result = to_bibtex(bib)
         self.maxDiff = None
         self.assertEqual(expected, result)
 
+    ###########
+    # Exception
+    ###########
     def test_exception_typeerror(self):
-        with io.open(_data_path('article.bib'), 'r') as bibfile:
+        with open('bibtexparser/tests/data/article.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read(), customization=author)
         self.assertRaises(TypeError, to_bibtex, bib)
 
-    def test_with_strings(self):
-        with io.open(_data_path('article_with_strings.bib'), 'r') as bibfile:
-            bib = BibTexParser(bibfile.read(), common_strings=True,
-                               interpolate_strings=False)
-        with io.open(_data_path(
-                'article_with_strings_output.bib'), 'r') as bibfile:
-            expected = bibfile.read()
-        result = to_bibtex(bib)
-        self.maxDiff = None
-        self.assertEqual(expected, result)
diff --git a/bibtexparser/tests/test_homogenise_fields.py b/bibtexparser/tests/test_homogenise_fields.py
index 5edcdd5..b27f9a7 100644
--- a/bibtexparser/tests/test_homogenise_fields.py
+++ b/bibtexparser/tests/test_homogenise_fields.py
@@ -1,25 +1,58 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+import io
 import unittest
 from bibtexparser.bparser import BibTexParser
 
 
 class TestHomogenizeFields(unittest.TestCase):
+
     def test_homogenize_default(self):
         with open('bibtexparser/tests/data/website.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read())
             entries = bib.get_entry_list()
-            self.assertNotIn('link', entries[0])
-            self.assertIn('url', entries[0])
+            self.assertNotIn('url', entries[0])
+            self.assertIn('link', entries[0])
 
     def test_homogenize_on(self):
         with open('bibtexparser/tests/data/website.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read(), homogenize_fields=True)
             entries = bib.get_entry_list()
-            self.assertIn('link', entries[0])
-            self.assertNotIn('url', entries[0])
+            self.assertIn('url', entries[0])
+            self.assertNotIn('link', entries[0])
 
     def test_homogenize_off(self):
         with open('bibtexparser/tests/data/website.bib', 'r') as bibfile:
             bib = BibTexParser(bibfile.read(), homogenize_fields=False)
             entries = bib.get_entry_list()
-            self.assertNotIn('link', entries[0])
-            self.assertIn('url', entries[0])
+            self.assertNotIn('url', entries[0])
+            self.assertIn('link', entries[0])
+
+    def test_homogenizes_fields(self):
+        self.maxDiff = None
+        with io.open('bibtexparser/tests/data/article_homogenize.bib',
+                     'r', encoding='utf-8') as bibfile:
+            bib = BibTexParser(bibfile.read(), homogenize_fields=True)
+            expected_dict = {
+                'Cesar2013': {
+                    'keyword': 'keyword1, keyword2',
+                    'ENTRYTYPE': 'article',
+                    'abstract': 'This is an abstract. This line should be '
+                                'long enough to test\nmultilines... and with '
+                                'a french érudit word',
+                    'year': '2013',
+                    'journal': 'Nice Journal',
+                    'ID': 'Cesar2013',
+                    'pages': '12-23',
+                    'title': 'An amazing title',
+                    'comments': 'A comment',
+                    'author': 'Jean César',
+                    'volume': '12',
+                    'month': 'jan',
+                    'url': "http://my.link/to-content",
+                    'subject': "Some topic of interest",
+                    'editor': "Edith Or",
+                }
+            }
+            self.assertEqual(bib.get_entry_dict(), expected_dict)