Repository: sciunto-org/python-bibtexparser
Pull request #254 (2020-02-27 17:13:38)

Added .editorconfig


Patch:
diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000..40335f7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset=utf-8
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+end_of_line = lf
+
+[*.{yaml,yml}]
+indent_size = 2
diff --git a/.travis.yml b/.travis.yml
index e2c47ee..e35ba6a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,6 @@ dist: trusty
 language: python
 matrix:
   include:
-    - python: "2.7"
-      env: TEST_SUITE=suite_2_7
     - python: "3.3"
       env: TEST_SUITE=suite_3_3
     - python: "3.4"
@@ -16,8 +14,6 @@ matrix:
       dist: xenial # Required for Python 3.7
       sudo: true   # travis-ci/travis-ci#9069
       env: TEST_SUITE=suite_3_7
-    - python: "pypy-5.7.1"
-      env: TEST_SUITE=suite_pypy
     - python: "pypy3.5-5.8.0"
       env: TEST_SUITE=suite_pypy3
 install:
diff --git a/CHANGELOG b/CHANGELOG
index a1b888e..87914a1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,15 +1,24 @@
-v1.xxx
+v1.2.0
 ======
 
+* Support for python 3 only
+
 v1.1.0
 ======
 
+* Handles declarations on lines starting with spaces after comments (#199)
+* accept extra characters in @string (#148)
+* Add support for BibLaTeX annotations (#208)
+* Strip the latex command str for latex_to_unicode() (#182)
+* Add comma_last to BibTexWriter (#219)
+* Feature: crossref Support (#216)
 * BUGFIX: Fix for pyparsing 2.3.1 (#226)
 * NEW: Add support for BibLaTeX annotations (#208)
 * NEW: Feature: crossref Support (#216)
 * ENH: Handles declarations on lines starting with spaces after comments (#199)
 * ENH: Checks for empty citekeys and whitespaces (#213)
 
+
 v1.0.1
 ======
 
diff --git a/README.rst b/README.rst
index d7a7996..e9ce8a5 100644
--- a/README.rst
+++ b/README.rst
@@ -9,7 +9,7 @@ IMPORTANT: the library is looking for new maintainers. Please, manifest yourself
 .. contents::
 
 
-Bibtexparser relies on `pyparsing <https://pypi.python.org/pypi/pyparsing>`_ and is compatible with Python 2.7 and 3.3 or newer.
+Bibtexparser relies on `pyparsing <https://pypi.python.org/pypi/pyparsing>`_ and is compatible with Python 3.3 or newer.
 
 Documentation
 -------------
diff --git a/bibtexparser/__init__.py b/bibtexparser/__init__.py
index f0ef20f..2c75560 100644
--- a/bibtexparser/__init__.py
+++ b/bibtexparser/__init__.py
@@ -25,9 +25,7 @@ __all__ = [
     'loads', 'load', 'dumps', 'dump', 'bibdatabase',
     'bparser', 'bwriter', 'bibtexexpression', 'latexenc', 'customization',
 ]
-__version__ = '1.1.0'
-
-import sys
+__version__ = '1.2.0'
 
 from . import bibdatabase, bibtexexpression, bparser, bwriter, latexenc, customization
 
@@ -107,8 +105,4 @@ def dump(bib_database, bibtex_file, writer=None):
     """
     if writer is None:
         writer = bwriter.BibTexWriter()
-    if sys.version_info >= (3, 0):
-        bibtex_file.write(writer.write(bib_database))
-    else:
-        # Encode to UTF-8
-        bibtex_file.write(writer.write(bib_database).encode("utf-8"))
+    bibtex_file.write(writer.write(bib_database))
diff --git a/bibtexparser/bibdatabase.py b/bibtexparser/bibdatabase.py
index 2857d25..75600b7 100644
--- a/bibtexparser/bibdatabase.py
+++ b/bibtexparser/bibdatabase.py
@@ -1,17 +1,10 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 from collections import OrderedDict
-import sys
 import logging
 
 logger = logging.getLogger(__name__)
 
-if sys.version_info >= (3, 0):
-    ustr = str
-else:
-    ustr = unicode
-
 
 STANDARD_TYPES = set([
     'article',
@@ -90,7 +83,7 @@ class BibDatabase(object):
     def entry_sort_key(entry, fields):
         result = []
         for field in fields:
-            result.append(ustr(entry.get(field, '')).lower())  # Sorting always as string
+            result.append(str(entry.get(field, '')).lower())  # Sorting always as string
         return tuple(result)
 
     def _make_entries_dict(self):
@@ -276,4 +269,4 @@ def as_text(text_string_or_expression):
                   (BibDataString, BibDataStringExpression)):
         return text_string_or_expression.get_value()
     else:
-        return ustr(text_string_or_expression)
+        return str(text_string_or_expression)
diff --git a/bibtexparser/bibtexexpression.py b/bibtexparser/bibtexexpression.py
index cf8bdd1..855d2e8 100644
--- a/bibtexparser/bibtexexpression.py
+++ b/bibtexparser/bibtexexpression.py
@@ -99,6 +99,8 @@ class BibtexExpression(object):
     ParseException = pp.ParseException
 
     def __init__(self):
+        # Init parse action functions
+        self.set_string_name_parse_action(lambda s, l, t: None)
 
         # Bibtex keywords
 
@@ -141,7 +143,6 @@ class BibtexExpression(object):
         string_expr = pp.delimitedList(
             (quoted_value | braced_value | string_name), delim='#'
             )('StringExpression')
-        self.set_string_expression_parse_action(lambda s, l, t: None)
         string_expr.addParseAction(self._string_expr_parse_action)
 
         value = (integer | string_expr)('Value')
@@ -270,17 +271,8 @@ class BibtexExpression(object):
     def _string_name_parse_action(self, s, l, t):
         return self._string_name_parse_action_fun(s, l, t)
 
-    def set_string_expression_parse_action(self, fun):
-        """Set the parseAction for string_expression expression.
-
-        .. Note::
-
-            See set_string_name_parse_action.
-        """
-        self._string_expr_parse_action_fun = fun
-
     def _string_expr_parse_action(self, s, l, t):
-        return self._string_expr_parse_action_fun(s, l, t)
+        return BibDataStringExpression.expression_if_needed(t)
 
     def parseFile(self, file_obj):
         return self.main_expression.parseFile(file_obj, parseAll=True)
diff --git a/bibtexparser/bparser.py b/bibtexparser/bparser.py
index c34ba8a..133b6cb 100644
--- a/bibtexparser/bparser.py
+++ b/bibtexparser/bparser.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 # Original source: github.com/okfn/bibserver
@@ -7,7 +6,6 @@
 # Etienne Posthumus (epoz)
 # Francois Boulogne <fboulogne at april dot org>
 
-import sys
 import io
 import logging
 
@@ -20,12 +18,6 @@ logger = logging.getLogger(__name__)
 __all__ = ['BibTexParser']
 
 
-if sys.version_info >= (3, 0):
-    ustr = str
-else:
-    ustr = unicode
-
-
 def parse(data, *args, **kwargs):
     parser = BibTexParser(*args, **kwargs)
     return parser.parse(data)
@@ -186,14 +178,6 @@ 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)))
 
         # Add notice to logger
         self._expr.add_log_function(logger.debug)
@@ -220,12 +204,13 @@ class BibTexParser(object):
     def _bibtex_file_obj(self, bibtex_str):
         # Some files have Byte-order marks inserted at the start
         byte = b'\xef\xbb\xbf'
-        if isinstance(bibtex_str, ustr):
-            byte = ustr(byte, self.encoding, 'ignore')
-            if bibtex_str[0] == byte:
+
+        if isinstance(bibtex_str, str):
+            byte = str(byte, self.encoding, 'ignore')
+            if len(bibtex_str) >= 1 and bibtex_str[0] == byte:
                 bibtex_str = bibtex_str[1:]
         else:
-            if bibtex_str[:3] == byte:
+            if len(bibtex_str) >= 3 and bibtex_str[:3] == byte:
                 bibtex_str = bibtex_str[3:]
             bibtex_str = bibtex_str.decode(encoding=self.encoding)
         return io.StringIO(bibtex_str)
@@ -239,7 +224,10 @@ class BibTexParser(object):
         """
         if not val or val == "{}":
             return ''
-        return val
+        elif self.interpolate_strings:
+            return as_text(val)
+        else:
+            return val
 
     def _clean_key(self, key):
         """ Lowercase a key and return as unicode.
@@ -249,8 +237,8 @@ class BibTexParser(object):
         :returns: (unicode) string -- value
         """
         key = key.lower()
-        if not isinstance(key, ustr):
-            return ustr(key, 'utf-8')
+        if not isinstance(key, str):
+            return str(key, 'utf-8')
         else:
             return key
 
diff --git a/bibtexparser/bwriter.py b/bibtexparser/bwriter.py
index 9ccbea2..e028147 100644
--- a/bibtexparser/bwriter.py
+++ b/bibtexparser/bwriter.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 # Author: Francois Boulogne
 # License:
diff --git a/bibtexparser/customization.py b/bibtexparser/customization.py
index 1376f14..3e7447d 100644
--- a/bibtexparser/customization.py
+++ b/bibtexparser/customization.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 """
diff --git a/bibtexparser/latexenc.py b/bibtexparser/latexenc.py
index e192fc4..c6a2cfb 100644
--- a/bibtexparser/latexenc.py
+++ b/bibtexparser/latexenc.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 # Original source: github.com/okfn/bibserver
@@ -9,7 +8,6 @@
 
 import itertools
 import re
-import sys
 import unicodedata
 
 __all__ = ['string_to_latex', 'latex_to_unicode', 'protect_uppercase',
@@ -2686,16 +2684,10 @@ def prepare_unicode_to_latex():
         ("\uD7FF", "\\mathtt{9}"),
     )
 
-    if sys.version_info >= (3, 0):
-        unicode_to_latex = to_latex
-        unicode_to_crappy_latex1 = to_crappy1
-        unicode_to_crappy_latex2 = to_crappy2
-        unicode_to_latex_map = dict(unicode_to_latex)
-    else:
-        unicode_to_latex = tuple((k.decode('unicode-escape'), v) for k, v in to_latex)
-        unicode_to_crappy_latex1 = tuple((k.decode('unicode-escape'), v) for k, v in to_crappy1)
-        unicode_to_crappy_latex2 = tuple((k.decode('unicode-escape'), v) for k, v in to_crappy2)
-        unicode_to_latex_map = dict(unicode_to_latex)
+    unicode_to_latex = to_latex
+    unicode_to_crappy_latex1 = to_crappy1
+    unicode_to_crappy_latex2 = to_crappy2
+    unicode_to_latex_map = dict(unicode_to_latex)
 
 
 prepare_unicode_to_latex()
diff --git a/docs/source/demo.py b/docs/source/demo.py
new file mode 100644
index 0000000..10c89b6
--- /dev/null
+++ b/docs/source/demo.py
@@ -0,0 +1,53 @@
+import logging
+import logging.config
+import io
+
+logger = logging.getLogger(__name__)
+
+logging.config.dictConfig({
+    'version': 1,
+    'disable_existing_loggers': False,
+    'formatters': {
+        'standard': {
+            'format': '%(asctime)s [%(levelname)s] %(name)s %(funcName)s:%(lineno)d: %(message)s'
+        },
+    },
+    'handlers': {
+        'default': {
+            'level':'DEBUG',
+            'formatter': 'standard',
+            'class':'logging.StreamHandler',
+        },
+    },
+    'loggers': {
+        '': {
+            'handlers': ['default'],
+            'level': 'DEBUG',
+            'formatter': 'standard',
+            'propagate': True
+        }
+    }
+})
+
+
+if __name__ == '__main__':
+    bibtex_source = """@ARTICLE{Cesar2013,
+      author = {Jean César},
+      title = {An amazing title},
+      year = {2013},
+      month = {1},
+      volume = {12},
+      pages = {12--23},
+      journal = {Nice Journal},
+      abstract = {This is an abstract. This line should be long enough to test
+    	 multilines...},
+      comments = {A comment},
+      keywords = {keyword1, keyword2},
+    }
+    """
+
+    from bibtexparser.bparser import BibTexParser
+
+    with io.StringIO(bibtex_source) as f:
+        bp = BibTexParser(f.read())
+        print(bp.get_entry_list())
diff --git a/docs/source/who.rst b/docs/source/who.rst
index 8068f1f..1750d0c 100644
--- a/docs/source/who.rst
+++ b/docs/source/who.rst
@@ -3,6 +3,8 @@ Who uses BibtexParser?
 
 If your project uses BibtexParser, you can ask for the addition of a link in this list.
 
+* https://pypi.org/project/vitae/
+* https://github.com/pubs/pubs
 * http://timotheepoisot.fr/2013/11/10/shared-bibtex-file-markdown/
 * https://github.com/Phyks/BMC
 * http://aurelien.naldi.info/research/publications.html


Test patch:
diff --git a/bibtexparser/tests/test_bparser.py b/bibtexparser/tests/test_bparser.py
index 516411a..dd6f6e1 100644
--- a/bibtexparser/tests/test_bparser.py
+++ b/bibtexparser/tests/test_bparser.py
@@ -53,6 +53,13 @@ def customizations_latex(record):
 
 class TestBibtexParserList(unittest.TestCase):
 
+    def test_empty_string(self):
+        bib = BibTexParser("")
+        self.assertEqual(bib.entries, [])
+        self.assertEqual(bib.comments, [])
+        self.assertEqual(bib.preambles, [])
+        self.assertEqual(bib.strings, {})
+
     ###########
     # ARTICLE
     ###########
@@ -612,6 +619,21 @@ class TestBibtexParserList(unittest.TestCase):
         self.assertEqual(res_dict, expected_dict)
         self.assertEqual(bib.preambles, ["Blah blah"])
 
+    def test_does_not_fail_on_non_bibtex_with_partial(self):
+        bibraw = '''@misc{this looks,
+          like = a = bibtex file but
+              , is not a real one!
+        '''
+        parser = BibTexParser()
+        bib = parser.parse(bibraw, partial=False)
+        self.assertEqual(bib.entries, [])
+        self.assertEqual(bib.preambles, [])
+        self.assertEqual(bib.strings, {})
+        self.assertEqual(bib.comments, [
+            '@misc{this looks,\n'
+            '          like = a = bibtex file but\n'
+            '              , is not a real one!'])
+
     def test_no_citekey_parsed_as_comment(self):
         bib = BibTexParser('@BOOK{, title = "bla"}')
         self.assertEqual(bib.entries, [])
diff --git a/bibtexparser/tests/test_bwriter.py b/bibtexparser/tests/test_bwriter.py
index 688182f..d34b40b 100644
--- a/bibtexparser/tests/test_bwriter.py
+++ b/bibtexparser/tests/test_bwriter.py
@@ -8,7 +8,6 @@ from __future__ import unicode_literals
 import unittest
 import os
 import io
-import sys
 
 from bibtexparser.bparser import BibTexParser
 from bibtexparser.bwriter import BibTexWriter, to_bibtex
diff --git a/bibtexparser/tests/test_crossref_resolving.py b/bibtexparser/tests/test_crossref_resolving.py
index eae99f4..f5cd6e5 100644
--- a/bibtexparser/tests/test_crossref_resolving.py
+++ b/bibtexparser/tests/test_crossref_resolving.py
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+    import unittest2 as unittest
+except ImportError:
+    import unittest
 from bibtexparser.bibdatabase import BibDatabase
 from bibtexparser.bparser import BibTexParser
 
diff --git a/bibtexparser/tests/test_customization.py b/bibtexparser/tests/test_customization.py
index 2d97538..77450e7 100644
--- a/bibtexparser/tests/test_customization.py
+++ b/bibtexparser/tests/test_customization.py
@@ -42,7 +42,7 @@ class TestBibtexParserMethod(unittest.TestCase):
 
     @unittest.skip('Bug #9')
     def test_getnames_braces(self):
-        names = ['A. {Delgado de Molina}', 'M. Vign{\\\'e}']
+        names = ['A. {Delgado de Molina}', r'M. Vign{\'e}']
         result = getnames(names)
         expected = ['Delgado de Molina, A.', 'Vigné, M.']
         self.assertEqual(result, expected)
@@ -78,40 +78,40 @@ class TestBibtexParserMethod(unittest.TestCase):
     # convert to unicode
     ###########
     def test_convert_to_unicode(self):
-        record = {'toto': '{\`a} \`{a}'}
+        record = {'toto': r'{\`a} \`{a}'}
         result = convert_to_unicode(record)
-        expected = {'toto': 'à à'}
+        expected = {'toto': r'à à'}
         self.assertEqual(result, expected)
-        record = {'toto': '{\\"u} \\"{u}'}
+        record = {'toto': r'{\"u} \"{u}'}
         result = convert_to_unicode(record)
-        expected = {'toto': 'ü ü'}
+        expected = {'toto': r'ü ü'}
         self.assertEqual(result, expected)
         # From issue 121
-        record = {'title': '{Two Gedenk\\"uberlieferung der Angelsachsen}'}
+        record = {'title': r'{Two Gedenk\"uberlieferung der Angelsachsen}'}
         result = convert_to_unicode(record)
-        expected = {'title': 'Two Gedenküberlieferung der Angelsachsen'}
+        expected = {'title': r'Two Gedenküberlieferung der Angelsachsen'}
         self.assertEqual(result, expected)
         # From issue 161
         record = {'title': r"p\^{a}t\'{e}"}
         result = convert_to_unicode(record)
-        expected = {'title': "pâté"}
+        expected = {'title': r"pâté"}
         self.assertEqual(result, expected)
         record = {'title': r"\^{i}le"}
         result = convert_to_unicode(record)
-        expected = {'title': "île"}
+        expected = {'title': r"île"}
         self.assertEqual(result, expected)
         record = {'title': r"\texttimes{}{\texttimes}\texttimes"}
         result = convert_to_unicode(record)
-        expected = {'title': "×××"}
+        expected = {'title': r"×××"}
         self.assertEqual(result, expected)
 
     ###########
     # homogenize
     ###########
     def test_homogenize(self):
-        record = {'toto': 'à {\`a} \`{a}'}
+        record = {'toto': r'à {\`a} \`{a}'}
         result = homogenize_latex_encoding(record)
-        expected = {'toto': '{\`a} {\`a} {\`a}'}
+        expected = {'toto': r'{\`a} {\`a} {\`a}'}
         self.assertEqual(result, expected)
 
     ###########
@@ -119,7 +119,7 @@ class TestBibtexParserMethod(unittest.TestCase):
     ###########
     def test_add_plaintext_fields(self):
         record = {
-            'title': 'On-line {Recognition} of {Handwritten} {Mathematical} {Symbols}',
+            'title': r'On-line {Recognition} of {Handwritten} {Mathematical} {Symbols}',
             'foobar': ['{FFT} {Foobar}', '{foobar}'],
             'foobar2': {'item1': '{FFT} {Foobar}', 'item2': '{foobar}'}
         }