Repository: keleshev/schema

Issue:
Cannot install with pip3 -- README.rst contains non-ascii character.
```bash
$ pip3 install schema
Downloading/unpacking schema
  Downloading schema-0.3.1.tar.gz
  Running setup.py (path:/private/tmp/pip_build_bla/schema/setup.py) egg_info for package schema
    Traceback (most recent call last):
      File "<string>", line 17, in <module>
      File "/private/tmp/pip_build_bla/schema/setup.py", line 16, in <module>
        long_description=open('README.rst').read(),
      File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/encodings/ascii.py", line 26, in decode
        return codecs.ascii_decode(input, self.errors)[0]
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 2360: ordinal not in range(128)
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 17, in <module>

  File "/private/tmp/pip_build_bla/schema/setup.py", line 16, in <module>

    long_description=open('README.rst').read(),

  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/encodings/ascii.py", line 26, in decode

    return codecs.ascii_decode(input, self.errors)[0]

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 2360: ordinal not in range(128)

----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /private/tmp/pip_build_bla/schema
Storing debug log for failure in /Users/bla/.pip/pip.log
```

The culprit line in the readme is here:

```
Alternatively, you can just drop `schema.py` file into your project—it is self-contained.
```
(The m-width dash)

If I set LANG=utf-8, it works:

```bash
$ LANG=utf-8 pip install schema
Downloading/unpacking schema
  Downloading schema-0.3.1.tar.gz
  Running setup.py (path:/Users/bla/tmpvenv/build/schema/setup.py) egg_info for package schema

Installing collected packages: schema
  Running setup.py install for schema

Successfully installed schema
Cleaning up...
```

Discussion:

Patch:
diff --git a/README.rst b/README.rst
index b9d5d9d..b5a9ffd 100644
--- a/README.rst
+++ b/README.rst
@@ -85,7 +85,7 @@ otherwise it will raise ``SchemaError``.
     >>> Schema(int).validate('123')
     Traceback (most recent call last):
     ...
-    SchemaError: '123' should be instance of 'int'
+    SchemaError: '123' should be instance of <type 'int'>
 
     >>> Schema(object).validate('hai')
     'hai'
@@ -172,7 +172,7 @@ against schemas listed inside that container:
     Traceback (most recent call last):
     ...
     SchemaError: Or(<type 'int'>, <type 'float'>) did not validate 'not int or float here'
-    'not int or float here' should be instance of 'float'
+    'not int or float here' should be instance of <type 'float'>
 
 Dictionaries
 ~~~~~~~~~~~~
@@ -232,9 +232,8 @@ data matches:
 
     >>> from schema import Optional
     >>> Schema({Optional('color', default='blue'): str,
-    ...         str: str}).validate({'texture': 'furry'}
-    ...       ) == {'color': 'blue', 'texture': 'furry'}
-    True
+    ...         str: str}).validate({'texture': 'furry'})
+    {'color': 'blue', 'texture': 'furry'}
 
 Defaults are used verbatim, not passed through any validators specified in the
 value.
diff --git a/schema.py b/schema.py
index bd9d4dd..9158c68 100644
--- a/schema.py
+++ b/schema.py
@@ -140,15 +140,15 @@ class Schema(object):
                     new[nkey] = nvalue
                 elif skey is not None:
                     if x is not None:
-                        raise SchemaError(['Invalid value for key %r' % key] +
+                        raise SchemaError(['invalid value for key %r' % key] +
                                           x.autos, [e] + x.errors)
             required = set(k for k in s if type(k) is not Optional)
             if coverage != required:
-                raise SchemaError('Missing keys: %s' % ", ".join(required - coverage), e)
+                raise SchemaError('missed keys %r' % (required - coverage), e)
             if len(new) != len(data):
                 wrong_keys = set(data.keys()) - set(new.keys())
                 s_wrong_keys = ', '.join('%r' % (k,) for k in sorted(wrong_keys))
-                raise SchemaError('Wrong keys %s in %r' % (s_wrong_keys, data),
+                raise SchemaError('wrong keys %s in %r' % (s_wrong_keys, data),
                                   e)
 
             # Apply default-having optionals that haven't been used:
@@ -162,7 +162,7 @@ class Schema(object):
             if isinstance(data, s):
                 return data
             else:
-                raise SchemaError('%r should be instance of %r' % (data, s.__name__), e)
+                raise SchemaError('%r should be instance of %r' % (data, s), e)
         if flavor == VALIDATOR:
             try:
                 return s.validate(data)
diff --git a/setup.py b/setup.py
index a539f6e..1bfb248 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,6 @@
 from setuptools import setup
 
+import codecs
 import schema
 
 
@@ -13,7 +14,7 @@ setup(
     keywords="schema json validation",
     url="http://github.com/halst/schema",
     py_modules=['schema'],
-    long_description=open('README.rst').read(),
+    long_description=codecs.open('README.rst', 'r', 'utf-8').read(),
     classifiers=[
         "Development Status :: 3 - Alpha",
         "Topic :: Utilities",


Test patch:
diff --git a/test_schema.py b/test_schema.py
index aee25dc..4ec9993 100644
--- a/test_schema.py
+++ b/test_schema.py
@@ -106,33 +106,35 @@ def test_dict():
         try:
             Schema({'key': 5}).validate({})
         except SchemaError as e:
-            assert e.args[0] == "Missing keys: key"
+            assert e.args[0] in ["missed keys set(['key'])",
+                                 "missed keys {'key'}"]  # Python 3 style
             raise
     with SE:
         try:
             Schema({'key': 5}).validate({'n': 5})
         except SchemaError as e:
-            assert e.args[0] == "Missing keys: key"
+            assert e.args[0] in ["missed keys set(['key'])",
+                                 "missed keys {'key'}"]  # Python 3 style
             raise
     with SE:
         try:
             Schema({}).validate({'n': 5})
         except SchemaError as e:
-            assert e.args[0] == "Wrong keys 'n' in {'n': 5}"
+            assert e.args[0] == "wrong keys 'n' in {'n': 5}"
             raise
     with SE:
         try:
             Schema({'key': 5}).validate({'key': 5, 'bad': 5})
         except SchemaError as e:
-            assert e.args[0] in ["Wrong keys 'bad' in {'key': 5, 'bad': 5}",
-                                 "Wrong keys 'bad' in {'bad': 5, 'key': 5}"]
+            assert e.args[0] in ["wrong keys 'bad' in {'key': 5, 'bad': 5}",
+                                 "wrong keys 'bad' in {'bad': 5, 'key': 5}"]
             raise
     with SE:
         try:
             Schema({}).validate({'a': 5, 'b': 5})
         except SchemaError as e:
-            assert e.args[0] in ["Wrong keys 'a', 'b' in {'a': 5, 'b': 5}",
-                                 "Wrong keys 'a', 'b' in {'b': 5, 'a': 5}"]
+            assert e.args[0] in ["wrong keys 'a', 'b' in {'a': 5, 'b': 5}",
+                                 "wrong keys 'a', 'b' in {'b': 5, 'a': 5}"]
             raise