Repository: nltk/nltk

Issue:
BllipParser: AttributeError: 'str' object has no attribute 'decode' on Python 3.5
When calling next(BllipParser.parse()) on Python 3.5, I receive the following error:

File "/home/andrew/.local/lib/python3.5/site-packages/nltk/parse/bllip.py", line 169, in parse
    _ensure_ascii(sentence)
  File "/home/andrew/.local/lib/python3.5/site-packages/nltk/parse/bllip.py", line 101, in _ensure_ascii
    word.decode('ascii')
AttributeError: 'str' object has no attribute 'decode'


Related to https://github.com/nltk/nltk/issues/507

NLTK v3.2.5
Python v3.5.2
OS: Ubuntu (16.04.3) running on WSL (16299.125)


Discussion:
Hey!
There are indeed differences since in Python 3 strings are no longer bytes arrays.
This problem might be solved by changing decode() to encode(), since they both check whether it's an _ascii_ string.

May I solve this?
So nobody ever solved this? Currently I have to wrap words in a dummy class with a decode method that does nothing. I'd love to remove that from my code.
Here is the traceback, happens when I use Bllip's `parse_one`:

```python
~/venv/3.7/lib/python3.7/site-packages/nltk-3.4.4-py3.7.egg/nltk/parse/api.py in parse_one(self, sent, *args, **kwargs)
     70     def parse_one(self, sent, *args, **kwargs):
     71         """:rtype: Tree or None"""
---> 72         return next(self.parse(sent, *args, **kwargs), None)

~/venv/3.7/lib/python3.7/site-packages/nltk-3.4.4-py3.7.egg/nltk/parse/bllip.py in parse(self, sentence)
    182         :rtype: iter(Tree)
    183         """
--> 184         _ensure_ascii(sentence)
    185         nbest_list = self.rrp.parse(sentence)
    186         for scored_parse in nbest_list:

~/venv/3.7/lib/python3.7/site-packages/nltk-3.4.4-py3.7.egg/nltk/parse/bllip.py in _ensure_ascii(words)
    103     try:
    104         for i, word in enumerate(words):
--> 105             word.decode('ascii')
    106     except UnicodeDecodeError:
    107         raise ValueError(

AttributeError: 'str' object has no attribute 'decode'

```


Resolving patch:
diff --git a/nltk/parse/bllip.py b/nltk/parse/bllip.py
--- a/nltk/parse/bllip.py
+++ b/nltk/parse/bllip.py
@@ -100,11 +100,11 @@ def _ensure_bllip_import_or_error(ie=ie):
 def _ensure_ascii(words):
     try:
         for i, word in enumerate(words):
-            word.decode("ascii")
-    except UnicodeDecodeError as e:
+            word.encode("ascii")
+    except UnicodeEncodeError as e:
         raise ValueError(
-            "Token %d (%r) is non-ASCII. BLLIP Parser "
-            "currently doesn't support non-ASCII inputs." % (i, word)
+            f"Token {i} ({word!r}) is non-ASCII. BLLIP Parser "
+            "currently doesn't support non-ASCII inputs."
         ) from e
 
 
@@ -163,7 +163,7 @@ def __init__(
             self.rrp.load_reranker_model(
                 features_filename=reranker_features,
                 weights_filename=reranker_weights,
-                **reranker_options
+                **reranker_options,
             )
 
     def parse(self, sentence):


Test patch:
diff --git a/nltk/test/unit/test_bllip.py b/nltk/test/unit/test_bllip.py
new file mode 100644
--- /dev/null
+++ b/nltk/test/unit/test_bllip.py
@@ -0,0 +1,42 @@
+import pytest
+
+from nltk.data import find
+from nltk.parse.bllip import BllipParser
+from nltk.tree import Tree
+
+
+@pytest.fixture(scope="module")
+def parser():
+    model_dir = find("models/bllip_wsj_no_aux").path
+    return BllipParser.from_unified_model_dir(model_dir)
+
+
+def setup_module():
+    pytest.importorskip("bllipparser")
+
+
+class TestBllipParser:
+    def test_parser_loads_a_valid_tree(self, parser):
+        parsed = parser.parse("I saw the man with the telescope")
+        tree = next(parsed)
+
+        assert isinstance(tree, Tree)
+        assert (
+            tree.pformat()
+            == """
+(S1
+  (S
+    (NP (PRP I))
+    (VP
+      (VBD saw)
+      (NP (DT the) (NN man))
+      (PP (IN with) (NP (DT the) (NN telescope))))))
+""".strip()
+        )
+
+    def test_tagged_parse_finds_matching_element(self, parser):
+        parsed = parser.parse("I saw the man with the telescope")
+        tagged_tree = next(parser.tagged_parse([("telescope", "NN")]))
+
+        assert isinstance(tagged_tree, Tree)
+        assert tagged_tree.pformat() == "(S1 (NP (NN telescope)))"