singer-python 5.13.2__tar.gz → 5.14.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {singer_python-5.13.2/singer_python.egg-info → singer_python-5.14.0}/PKG-INFO +1 -1
  2. {singer_python-5.13.2 → singer_python-5.14.0}/setup.py +1 -1
  3. singer_python-5.14.0/singer/schema_generation.py +92 -0
  4. {singer_python-5.13.2 → singer_python-5.14.0/singer_python.egg-info}/PKG-INFO +1 -1
  5. {singer_python-5.13.2 → singer_python-5.14.0}/singer_python.egg-info/SOURCES.txt +2 -0
  6. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_catalog.py +3 -3
  7. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_exceptions.py +12 -12
  8. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_schema.py +14 -14
  9. singer_python-5.14.0/tests/test_schema_generation.py +76 -0
  10. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_transform.py +24 -24
  11. {singer_python-5.13.2 → singer_python-5.14.0}/LICENSE +0 -0
  12. {singer_python-5.13.2 → singer_python-5.14.0}/README.md +0 -0
  13. {singer_python-5.13.2 → singer_python-5.14.0}/setup.cfg +0 -0
  14. {singer_python-5.13.2 → singer_python-5.14.0}/singer/__init__.py +0 -0
  15. {singer_python-5.13.2 → singer_python-5.14.0}/singer/bookmarks.py +0 -0
  16. {singer_python-5.13.2 → singer_python-5.14.0}/singer/catalog.py +0 -0
  17. {singer_python-5.13.2 → singer_python-5.14.0}/singer/exceptions.py +0 -0
  18. {singer_python-5.13.2 → singer_python-5.14.0}/singer/logger.py +0 -0
  19. {singer_python-5.13.2 → singer_python-5.14.0}/singer/logging.conf +0 -0
  20. {singer_python-5.13.2 → singer_python-5.14.0}/singer/messages.py +0 -0
  21. {singer_python-5.13.2 → singer_python-5.14.0}/singer/metadata.py +0 -0
  22. {singer_python-5.13.2 → singer_python-5.14.0}/singer/metrics.py +0 -0
  23. {singer_python-5.13.2 → singer_python-5.14.0}/singer/requests.py +0 -0
  24. {singer_python-5.13.2 → singer_python-5.14.0}/singer/schema.py +0 -0
  25. {singer_python-5.13.2 → singer_python-5.14.0}/singer/statediff.py +0 -0
  26. {singer_python-5.13.2 → singer_python-5.14.0}/singer/transform.py +0 -0
  27. {singer_python-5.13.2 → singer_python-5.14.0}/singer/utils.py +0 -0
  28. {singer_python-5.13.2 → singer_python-5.14.0}/singer_python.egg-info/dependency_links.txt +0 -0
  29. {singer_python-5.13.2 → singer_python-5.14.0}/singer_python.egg-info/requires.txt +0 -0
  30. {singer_python-5.13.2 → singer_python-5.14.0}/singer_python.egg-info/top_level.txt +0 -0
  31. {singer_python-5.13.2 → singer_python-5.14.0}/tests/__init__.py +0 -0
  32. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_bookmarks.py +0 -0
  33. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_metadata.py +0 -0
  34. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_metrics.py +0 -0
  35. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_singer.py +0 -0
  36. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_statediff.py +0 -0
  37. {singer_python-5.13.2 → singer_python-5.14.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: singer-python
3
- Version: 5.13.2
3
+ Version: 5.14.0
4
4
  Summary: Singer.io utility library
5
5
  Home-page: http://singer.io
6
6
  Author: Stitch
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
  import subprocess
5
5
 
6
6
  setup(name="singer-python",
7
- version='5.13.2',
7
+ version='5.14.0',
8
8
  description="Singer.io utility library",
9
9
  author="Stitch",
10
10
  classifiers=['Programming Language :: Python :: 3 :: Only'],
@@ -0,0 +1,92 @@
1
+ import dateutil.parser
2
+
3
+
4
+ def add_observation(acc, path):
5
+
6
+ node = acc
7
+ for i in range(0, len(path) - 1):
8
+ k = path[i]
9
+ if k not in node:
10
+ node[k] = {}
11
+ node = node[k]
12
+
13
+ node[path[-1]] = True
14
+
15
+ # pylint: disable=too-many-branches
16
+ def add_observations(acc, path, data):
17
+ if isinstance(data, dict):
18
+ for key in data:
19
+ add_observations(acc, path + ["object", key], data[key])
20
+ elif isinstance(data, list):
21
+ for item in data:
22
+ add_observations(acc, path + ["array"], item)
23
+ elif isinstance(data, str):
24
+ # If the string parses as a date, add an observation that its a date
25
+ try:
26
+ data = dateutil.parser.parse(data)
27
+ except (dateutil.parser.ParserError, OverflowError):
28
+ data = None
29
+ if data:
30
+ add_observation(acc, path + ["date"])
31
+ else:
32
+ add_observation(acc, path + ["string"])
33
+
34
+ elif isinstance(data, bool):
35
+ add_observation(acc, path + ["boolean"])
36
+ elif isinstance(data, int):
37
+ add_observation(acc, path + ["integer"])
38
+ elif isinstance(data, float):
39
+ add_observation(acc, path + ["number"])
40
+ elif data is None:
41
+ add_observation(acc, path + ["null"])
42
+ else:
43
+ raise Exception("Unexpected value " + repr(data) + " at path " + repr(path))
44
+
45
+ return acc
46
+
47
+ def to_json_schema(obs):
48
+ result = {'type': ['null']}
49
+
50
+ for key in obs:
51
+
52
+ if key == 'object':
53
+ result['type'] += ['object']
54
+ if 'properties' not in result:
55
+ result['properties'] = {}
56
+ for obj_key in obs['object']:
57
+ result['properties'][obj_key] = to_json_schema(obs['object'][obj_key])
58
+
59
+ elif key == 'array':
60
+ result['type'] += ['array']
61
+ result['items'] = to_json_schema(obs['array'])
62
+
63
+ elif key == 'date':
64
+ result['type'] += ['string']
65
+ result['format'] = 'date-time'
66
+ elif key == 'string':
67
+ result['type'] += ['string']
68
+
69
+ elif key == 'boolean':
70
+ result['type'] += ['boolean']
71
+
72
+ elif key == 'integer':
73
+ result['type'] += ['integer']
74
+
75
+ elif key == 'number':
76
+ # Use type=string, format=singer.decimal
77
+ result['type'] += ['string']
78
+ result['format'] = 'singer.decimal'
79
+
80
+ elif key == 'null':
81
+ pass
82
+
83
+ else:
84
+ raise Exception("Unexpected data type " + key)
85
+
86
+ return result
87
+
88
+ def generate_schema(records):
89
+ obs = {}
90
+ for record in records:
91
+ obs = add_observations(obs, [], record)
92
+ return to_json_schema(obs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: singer-python
3
- Version: 5.13.2
3
+ Version: 5.14.0
4
4
  Summary: Singer.io utility library
5
5
  Home-page: http://singer.io
6
6
  Author: Stitch
@@ -13,6 +13,7 @@ singer/metadata.py
13
13
  singer/metrics.py
14
14
  singer/requests.py
15
15
  singer/schema.py
16
+ singer/schema_generation.py
16
17
  singer/statediff.py
17
18
  singer/transform.py
18
19
  singer/utils.py
@@ -28,6 +29,7 @@ tests/test_exceptions.py
28
29
  tests/test_metadata.py
29
30
  tests/test_metrics.py
30
31
  tests/test_schema.py
32
+ tests/test_schema_generation.py
31
33
  tests/test_singer.py
32
34
  tests/test_statediff.py
33
35
  tests/test_transform.py
@@ -25,7 +25,7 @@ class TestGetSelectedStreams(unittest.TestCase):
25
25
  CatalogEntry(tap_stream_id='c',schema=Schema(),metadata=[])])
26
26
  state = {}
27
27
  selected_streams = catalog.get_selected_streams(state)
28
- self.assertEquals([e for e in selected_streams],[selected_entry])
28
+ self.assertEqual([e for e in selected_streams],[selected_entry])
29
29
 
30
30
  def test_resumes_currently_syncing_stream(self):
31
31
  selected_entry_a = CatalogEntry(tap_stream_id='a',
@@ -44,7 +44,7 @@ class TestGetSelectedStreams(unittest.TestCase):
44
44
  selected_entry_c])
45
45
  state = {'currently_syncing': 'c'}
46
46
  selected_streams = catalog.get_selected_streams(state)
47
- self.assertEquals([e for e in selected_streams][0],selected_entry_c)
47
+ self.assertEqual([e for e in selected_streams][0],selected_entry_c)
48
48
 
49
49
  class TestToDictAndFromDict(unittest.TestCase):
50
50
 
@@ -141,4 +141,4 @@ class TestGetStream(unittest.TestCase):
141
141
  CatalogEntry(tap_stream_id='b'),
142
142
  CatalogEntry(tap_stream_id='c')])
143
143
  entry = catalog.get_stream('b')
144
- self.assertEquals('b', entry.tap_stream_id)
144
+ self.assertEqual('b', entry.tap_stream_id)
@@ -14,8 +14,8 @@ class TestSingerErrors(unittest.TestCase):
14
14
  raise SingerError(error_text)
15
15
 
16
16
  expected_text = "SingerError\n" + error_text
17
- self.assertEquals(expected_text,
18
- str(test_run.exception))
17
+ self.assertEqual(expected_text,
18
+ str(test_run.exception))
19
19
 
20
20
  def test_SingerConfigurationError_prints_correctly(self):
21
21
  error_text = "An error occured"
@@ -24,8 +24,8 @@ class TestSingerErrors(unittest.TestCase):
24
24
  raise SingerConfigurationError(error_text)
25
25
 
26
26
  expected_text = "SingerConfigurationError\n" + error_text
27
- self.assertEquals(expected_text,
28
- str(test_run.exception))
27
+ self.assertEqual(expected_text,
28
+ str(test_run.exception))
29
29
 
30
30
  def test_SingerDiscoveryError_prints_correctly(self):
31
31
  error_text = "An error occured"
@@ -34,8 +34,8 @@ class TestSingerErrors(unittest.TestCase):
34
34
  raise SingerDiscoveryError(error_text)
35
35
 
36
36
  expected_text = "SingerDiscoveryError\n" + error_text
37
- self.assertEquals(expected_text,
38
- str(test_run.exception))
37
+ self.assertEqual(expected_text,
38
+ str(test_run.exception))
39
39
 
40
40
  def test_SingerSyncError_prints_correctly(self):
41
41
  error_text = "An error occured"
@@ -44,8 +44,8 @@ class TestSingerErrors(unittest.TestCase):
44
44
  raise SingerSyncError(error_text)
45
45
 
46
46
  expected_text = "SingerSyncError\n" + error_text
47
- self.assertEquals(expected_text,
48
- str(test_run.exception))
47
+ self.assertEqual(expected_text,
48
+ str(test_run.exception))
49
49
 
50
50
  def test_SingerRetryableRequestError_prints_correctly(self):
51
51
  error_text = "An error occured"
@@ -54,8 +54,8 @@ class TestSingerErrors(unittest.TestCase):
54
54
  raise SingerRetryableRequestError(error_text)
55
55
 
56
56
  expected_text = "SingerRetryableRequestError\n" + error_text
57
- self.assertEquals(expected_text,
58
- str(test_run.exception))
57
+ self.assertEqual(expected_text,
58
+ str(test_run.exception))
59
59
 
60
60
  def test_SingerError_prints_multiple_lines_correctly(self):
61
61
  error_text = "\n".join(["Line 1", "Line 2", "Line 3"])
@@ -64,5 +64,5 @@ class TestSingerErrors(unittest.TestCase):
64
64
  raise SingerError(error_text)
65
65
 
66
66
  expected_text = "SingerError\n" + error_text
67
- self.assertEquals(expected_text,
68
- str(test_run.exception))
67
+ self.assertEqual(expected_text,
68
+ str(test_run.exception))
@@ -44,38 +44,38 @@ class TestSchema(unittest.TestCase):
44
44
  additionalProperties=True)
45
45
 
46
46
  def test_string_to_dict(self):
47
- self.assertEquals(self.string_dict, self.string_obj.to_dict())
47
+ self.assertEqual(self.string_dict, self.string_obj.to_dict())
48
48
 
49
49
  def test_integer_to_dict(self):
50
- self.assertEquals(self.integer_dict, self.integer_obj.to_dict())
50
+ self.assertEqual(self.integer_dict, self.integer_obj.to_dict())
51
51
 
52
52
  def test_array_to_dict(self):
53
- self.assertEquals(self.array_dict, self.array_obj.to_dict())
53
+ self.assertEqual(self.array_dict, self.array_obj.to_dict())
54
54
 
55
55
  def test_object_to_dict(self):
56
- self.assertEquals(self.object_dict, self.object_obj.to_dict())
56
+ self.assertEqual(self.object_dict, self.object_obj.to_dict())
57
57
 
58
58
  def test_string_from_dict(self):
59
- self.assertEquals(self.string_obj, Schema.from_dict(self.string_dict))
59
+ self.assertEqual(self.string_obj, Schema.from_dict(self.string_dict))
60
60
 
61
61
  def test_integer_from_dict(self):
62
- self.assertEquals(self.integer_obj, Schema.from_dict(self.integer_dict))
62
+ self.assertEqual(self.integer_obj, Schema.from_dict(self.integer_dict))
63
63
 
64
64
  def test_array_from_dict(self):
65
- self.assertEquals(self.array_obj, Schema.from_dict(self.array_dict))
65
+ self.assertEqual(self.array_obj, Schema.from_dict(self.array_dict))
66
66
 
67
67
  def test_object_from_dict(self):
68
- self.assertEquals(self.object_obj, Schema.from_dict(self.object_dict))
68
+ self.assertEqual(self.object_obj, Schema.from_dict(self.object_dict))
69
69
 
70
70
  def test_repr_atomic(self):
71
- self.assertEquals(self.string_obj, eval(repr(self.string_obj)))
71
+ self.assertEqual(self.string_obj, eval(repr(self.string_obj)))
72
72
 
73
73
  def test_repr_recursive(self):
74
- self.assertEquals(self.object_obj, eval(repr(self.object_obj)))
74
+ self.assertEqual(self.object_obj, eval(repr(self.object_obj)))
75
75
 
76
76
  def test_object_from_dict_with_defaults(self):
77
77
  schema = Schema.from_dict(self.object_dict, inclusion='automatic')
78
- self.assertEquals('whatever', schema.inclusion,
79
- msg='The schema value should override the default')
80
- self.assertEquals('automatic', schema.properties['a_string'].inclusion)
81
- self.assertEquals('automatic', schema.properties['an_array'].items.inclusion)
78
+ self.assertEqual('whatever', schema.inclusion,
79
+ msg='The schema value should override the default')
80
+ self.assertEqual('automatic', schema.properties['a_string'].inclusion)
81
+ self.assertEqual('automatic', schema.properties['an_array'].items.inclusion)
@@ -0,0 +1,76 @@
1
+ import unittest
2
+ from singer.schema_generation import generate_schema
3
+
4
+ class TestSchemaGeneration(unittest.TestCase):
5
+ def test_simple_schema(self):
6
+ records = [{'a': 1, 'b': 'two', 'c': True, 'dt': '2000-01-01T00:11:22Z'}]
7
+ expected_schema = {
8
+ 'type': ['null', 'object'],
9
+ 'properties': {
10
+ 'a': {'type': ['null', 'integer']},
11
+ 'b': {'type': ['null', 'string']},
12
+ 'c': {'type': ['null', 'boolean']},
13
+ 'dt': {'type': ['null', 'string'], 'format': 'date-time'}
14
+ }
15
+ }
16
+ self.assertEqual(expected_schema, generate_schema(records))
17
+
18
+ def test_mix_n_match_records_schema(self):
19
+ records = [
20
+ {'a': 1, 'b': 'b'},
21
+ {'a': 'two', 'c': 7, 'd': [1, 'two']},
22
+ {'a': True, 'c': 7.7, 'd': {'one': 1, 'two': 'two'}}
23
+ ]
24
+ expected_schema = {
25
+ 'type': ['null', 'object'],
26
+ 'properties': {
27
+ 'a': {'type': {'null', 'integer', 'string', 'boolean'}},
28
+ 'b': {'type': ['null', 'string']},
29
+ 'c': {'type': {'null', 'integer', 'string'}, 'format': 'singer.decimal'},
30
+ 'd': {
31
+ 'type': {'null', 'array', 'object'},
32
+ 'items': {'type': {'null', 'integer', 'string'}},
33
+ 'properties': {'one': {'type': ['null', 'integer']},
34
+ 'two': {'type': ['null', 'string']}}
35
+
36
+ }
37
+ }
38
+ }
39
+ actual_schema = generate_schema(records)
40
+ actual_schema['properties']['a']['type'] = set(actual_schema['properties']['a']['type'])
41
+ actual_schema['properties']['c']['type'] = set(actual_schema['properties']['c']['type'])
42
+ actual_schema['properties']['d']['type'] = set(actual_schema['properties']['d']['type'])
43
+ actual_schema['properties']['d']['items']['type'] = set(actual_schema['properties']['d']['items']['type'])
44
+ self.assertEqual(expected_schema, actual_schema)
45
+
46
+ def test_nested_structue_schema(self):
47
+ records = [{'a': {'b': {'c': [{'d': 7}]}, 'e': [[1, 2, 3]]}}]
48
+ expected_schema = {
49
+ 'type': ['null', 'object'],
50
+ 'properties': {
51
+ 'a': {
52
+ 'type': ['null', 'object'],
53
+ 'properties': {
54
+ 'b': {
55
+ 'type': ['null', 'object'],
56
+ 'properties': {
57
+ 'c': {
58
+ 'type': ['null', 'array'],
59
+ 'items': {
60
+ 'type': ['null', 'object'],
61
+ 'properties': {'d': {'type': ['null', 'integer']}}
62
+ }
63
+ }
64
+ }
65
+ },
66
+ 'e': {
67
+ 'type': ['null', 'array'],
68
+ 'items': {
69
+ 'type': ['null', 'array'],
70
+ 'items': {'type': ['null', 'integer']}}
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ self.assertEqual(expected_schema, generate_schema(records))
@@ -264,11 +264,11 @@ class TestTransform(unittest.TestCase):
264
264
  nan = {'percentage': decimal.Decimal('NaN')}
265
265
  snan = {'percentage': decimal.Decimal('sNaN')}
266
266
 
267
- self.assertEquals(inf, transform(inf, schema))
268
- self.assertEquals(negative_inf, transform(negative_inf, schema))
269
- self.assertEquals({'percentage': '1.4142135623730951'}, transform(root2, schema))
270
- self.assertEquals({'percentage': 'NaN'}, transform(nan, schema))
271
- self.assertEquals({'percentage': 'NaN'}, transform(snan, schema))
267
+ self.assertEqual(inf, transform(inf, schema))
268
+ self.assertEqual(negative_inf, transform(negative_inf, schema))
269
+ self.assertEqual({'percentage': '1.4142135623730951'}, transform(root2, schema))
270
+ self.assertEqual({'percentage': 'NaN'}, transform(nan, schema))
271
+ self.assertEqual({'percentage': 'NaN'}, transform(snan, schema))
272
272
 
273
273
 
274
274
  str1 = {'percentage':'0.1'}
@@ -276,11 +276,11 @@ class TestTransform(unittest.TestCase):
276
276
  str3 = {'percentage': '1E+13'}
277
277
  str4 = {'percentage': '100'}
278
278
  str5 = {'percentage': '-100'}
279
- self.assertEquals(str1, transform(str1, schema))
280
- self.assertEquals({'percentage': '1E-13'}, transform(str2, schema))
281
- self.assertEquals({'percentage': '1E+13'}, transform(str3, schema))
282
- self.assertEquals({'percentage': '100'}, transform(str4, schema))
283
- self.assertEquals({'percentage': '-100'}, transform(str5, schema))
279
+ self.assertEqual(str1, transform(str1, schema))
280
+ self.assertEqual({'percentage': '1E-13'}, transform(str2, schema))
281
+ self.assertEqual({'percentage': '1E+13'}, transform(str3, schema))
282
+ self.assertEqual({'percentage': '100'}, transform(str4, schema))
283
+ self.assertEqual({'percentage': '-100'}, transform(str5, schema))
284
284
 
285
285
  float1 = {'percentage': 12.0000000000000000000000000001234556}
286
286
  float2 = {'percentage': 0.0123}
@@ -288,28 +288,28 @@ class TestTransform(unittest.TestCase):
288
288
  float4 = {'percentage': -100.0123}
289
289
  float5 = {'percentage': 0.000001}
290
290
  float6 = {'percentage': 0.0000001}
291
- self.assertEquals({'percentage':'12.0'}, transform(float1, schema))
292
- self.assertEquals({'percentage':'0.0123'}, transform(float2, schema))
293
- self.assertEquals({'percentage':'100.0123'}, transform(float3, schema))
294
- self.assertEquals({'percentage':'-100.0123'}, transform(float4, schema))
295
- self.assertEquals({'percentage':'0.000001'}, transform(float5, schema))
296
- self.assertEquals({'percentage':'1E-7'}, transform(float6, schema))
291
+ self.assertEqual({'percentage':'12.0'}, transform(float1, schema))
292
+ self.assertEqual({'percentage':'0.0123'}, transform(float2, schema))
293
+ self.assertEqual({'percentage':'100.0123'}, transform(float3, schema))
294
+ self.assertEqual({'percentage':'-100.0123'}, transform(float4, schema))
295
+ self.assertEqual({'percentage':'0.000001'}, transform(float5, schema))
296
+ self.assertEqual({'percentage':'1E-7'}, transform(float6, schema))
297
297
 
298
298
  int1 = {'percentage': 123}
299
299
  int2 = {'percentage': 0}
300
300
  int3 = {'percentage': -1000}
301
- self.assertEquals({'percentage':'123'}, transform(int1, schema))
302
- self.assertEquals({'percentage':'0'}, transform(int2, schema))
303
- self.assertEquals({'percentage':'-1000'}, transform(int3, schema))
301
+ self.assertEqual({'percentage':'123'}, transform(int1, schema))
302
+ self.assertEqual({'percentage':'0'}, transform(int2, schema))
303
+ self.assertEqual({'percentage':'-1000'}, transform(int3, schema))
304
304
 
305
305
  dec1 = {'percentage': decimal.Decimal('1.1010101')}
306
306
  dec2 = {'percentage': decimal.Decimal('.111111111111111111111111')}
307
307
  dec3 = {'percentage': decimal.Decimal('-.111111111111111111111111')}
308
308
  dec4 = {'percentage': decimal.Decimal('100')}
309
- self.assertEquals({'percentage':'1.1010101'}, transform(dec1, schema))
310
- self.assertEquals({'percentage':'0.111111111111111111111111'}, transform(dec2, schema))
311
- self.assertEquals({'percentage':'-0.111111111111111111111111'}, transform(dec3, schema))
312
- self.assertEquals({'percentage':'100'}, transform(dec4, schema))
309
+ self.assertEqual({'percentage':'1.1010101'}, transform(dec1, schema))
310
+ self.assertEqual({'percentage':'0.111111111111111111111111'}, transform(dec2, schema))
311
+ self.assertEqual({'percentage':'-0.111111111111111111111111'}, transform(dec3, schema))
312
+ self.assertEqual({'percentage':'100'}, transform(dec4, schema))
313
313
 
314
314
  bad1 = {'percentage': 'fsdkjl'}
315
315
  with self.assertRaises(SchemaMismatch):
@@ -317,7 +317,7 @@ class TestTransform(unittest.TestCase):
317
317
 
318
318
  badnull = {'percentage': None}
319
319
  with self.assertRaises(SchemaMismatch):
320
- self.assertEquals({'percentage':None}, transform(badnull, schema))
320
+ self.assertEqual({'percentage':None}, transform(badnull, schema))
321
321
 
322
322
  class TestTransformsWithMetadata(unittest.TestCase):
323
323
 
File without changes
File without changes
File without changes