Best Python code snippet using fMBT_python
test_parsers.py
Source:test_parsers.py  
1# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License"). You4# may not use this file except in compliance with the License. A copy of5# the License is located at6#7# http://aws.amazon.com/apache2.0/8#9# or in the "license" file accompanying this file. This file is10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF11# ANY KIND, either express or implied. See the License for the specific12# language governing permissions and limitations under the License.13import datetime14import itertools15import pytest16from dateutil.tz import tzutc17from botocore import model, parsers18from botocore.compat import MutableMapping, json19from tests import RawResponse, unittest20# HTTP responses will typically return a custom HTTP21# dict.  We want to ensure we're able to work with any22# kind of mutable mapping implementation.23class CustomHeaderDict(MutableMapping):24    def __init__(self, original_dict):25        self._d = original_dict26    def __getitem__(self, item):27        return self._d[item]28    def __setitem__(self, item, value):29        self._d[item] = value30    def __delitem__(self, item):31        del self._d[item]32    def __iter__(self):33        return iter(self._d)34    def __len__(self):35        return len(self._d)36# These tests contain botocore specific tests that either37# don't make sense in the protocol tests or haven't been added38# yet.39class TestResponseMetadataParsed(unittest.TestCase):40    def test_response_metadata_parsed_for_query_service(self):41        parser = parsers.QueryParser()42        response = (43            b'<OperationNameResponse>'44            b'  <OperationNameResult><Str>myname</Str></OperationNameResult>'45            b'  <ResponseMetadata>'46            b'    <RequestId>request-id</RequestId>'47            b'  </ResponseMetadata>'48            b'</OperationNameResponse>'49        )50        output_shape = model.StructureShape(51            'OutputShape',52            {53                'type': 'structure',54                'resultWrapper': 'OperationNameResult',55                'members': {56                    'Str': {57                        'shape': 'StringType',58                    },59                    'Num': {60                        'shape': 'IntegerType',61                    },62                },63            },64            model.ShapeResolver(65                {66                    'StringType': {67                        'type': 'string',68                    },69                    'IntegerType': {70                        'type': 'integer',71                    },72                }73            ),74        )75        parsed = parser.parse(76            {'body': response, 'headers': {}, 'status_code': 200}, output_shape77        )78        self.assertEqual(79            parsed,80            {81                'Str': 'myname',82                'ResponseMetadata': {83                    'RequestId': 'request-id',84                    'HTTPStatusCode': 200,85                    'HTTPHeaders': {},86                },87            },88        )89    def test_metadata_always_exists_for_query(self):90        # ResponseMetadata is used for more than just the request id. It91        # should always get populated, even if the request doesn't seem to92        # have an id.93        parser = parsers.QueryParser()94        response = (95            b'<OperationNameResponse>'96            b'  <OperationNameResult><Str>myname</Str></OperationNameResult>'97            b'</OperationNameResponse>'98        )99        output_shape = model.StructureShape(100            'OutputShape',101            {102                'type': 'structure',103                'resultWrapper': 'OperationNameResult',104                'members': {105                    'Str': {106                        'shape': 'StringType',107                    },108                    'Num': {109                        'shape': 'IntegerType',110                    },111                },112            },113            model.ShapeResolver(114                {115                    'StringType': {116                        'type': 'string',117                    },118                    'IntegerType': {119                        'type': 'integer',120                    },121                }122            ),123        )124        parsed = parser.parse(125            {'body': response, 'headers': {}, 'status_code': 200}, output_shape126        )127        expected = {128            'Str': 'myname',129            'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': {}},130        }131        self.assertEqual(parsed, expected)132    def test_response_metadata_parsed_for_ec2(self):133        parser = parsers.EC2QueryParser()134        response = (135            b'<OperationNameResponse>'136            b'  <Str>myname</Str>'137            b'  <requestId>request-id</requestId>'138            b'</OperationNameResponse>'139        )140        output_shape = model.StructureShape(141            'OutputShape',142            {143                'type': 'structure',144                'members': {145                    'Str': {146                        'shape': 'StringType',147                    }148                },149            },150            model.ShapeResolver({'StringType': {'type': 'string'}}),151        )152        parsed = parser.parse(153            {'headers': {}, 'body': response, 'status_code': 200}, output_shape154        )155        # Note that the response metadata is normalized to match the query156        # protocol, even though this is not how it appears in the output.157        self.assertEqual(158            parsed,159            {160                'Str': 'myname',161                'ResponseMetadata': {162                    'RequestId': 'request-id',163                    'HTTPStatusCode': 200,164                    'HTTPHeaders': {},165                },166            },167        )168    def test_metadata_always_exists_for_ec2(self):169        # ResponseMetadata is used for more than just the request id. It170        # should always get populated, even if the request doesn't seem to171        # have an id.172        parser = parsers.EC2QueryParser()173        response = (174            b'<OperationNameResponse>'175            b'  <Str>myname</Str>'176            b'</OperationNameResponse>'177        )178        output_shape = model.StructureShape(179            'OutputShape',180            {181                'type': 'structure',182                'members': {183                    'Str': {184                        'shape': 'StringType',185                    }186                },187            },188            model.ShapeResolver({'StringType': {'type': 'string'}}),189        )190        parsed = parser.parse(191            {'headers': {}, 'body': response, 'status_code': 200}, output_shape192        )193        expected = {194            'Str': 'myname',195            'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': {}},196        }197        self.assertEqual(parsed, expected)198    def test_response_metadata_on_json_request(self):199        parser = parsers.JSONParser()200        response = b'{"Str": "mystring"}'201        headers = {'x-amzn-requestid': 'request-id'}202        output_shape = model.StructureShape(203            'OutputShape',204            {205                'type': 'structure',206                'members': {207                    'Str': {208                        'shape': 'StringType',209                    }210                },211            },212            model.ShapeResolver({'StringType': {'type': 'string'}}),213        )214        parsed = parser.parse(215            {'body': response, 'headers': headers, 'status_code': 200},216            output_shape,217        )218        # Note that the response metadata is normalized to match the query219        # protocol, even though this is not how it appears in the output.220        self.assertEqual(221            parsed,222            {223                'Str': 'mystring',224                'ResponseMetadata': {225                    'RequestId': 'request-id',226                    'HTTPStatusCode': 200,227                    'HTTPHeaders': headers,228                },229            },230        )231    def test_response_no_initial_event_stream(self):232        parser = parsers.JSONParser()233        output_shape = model.StructureShape(234            'OutputShape',235            {236                'type': 'structure',237                'members': {'Payload': {'shape': 'Payload'}},238            },239            model.ShapeResolver(240                {241                    'Payload': {242                        'type': 'structure',243                        'members': [],244                        'eventstream': True,245                    }246                }247            ),248        )249        with self.assertRaises(parsers.ResponseParserError):250            response_dict = {251                'status_code': 200,252                'headers': {},253                'body': RawResponse(b''),254                'context': {'operation_name': 'TestOperation'},255            }256            parser.parse(response_dict, output_shape)257    def test_metadata_always_exists_for_json(self):258        # ResponseMetadata is used for more than just the request id. It259        # should always get populated, even if the request doesn't seem to260        # have an id.261        parser = parsers.JSONParser()262        response = b'{"Str": "mystring"}'263        headers = {}264        output_shape = model.StructureShape(265            'OutputShape',266            {267                'type': 'structure',268                'members': {269                    'Str': {270                        'shape': 'StringType',271                    }272                },273            },274            model.ShapeResolver({'StringType': {'type': 'string'}}),275        )276        parsed = parser.parse(277            {'body': response, 'headers': headers, 'status_code': 200},278            output_shape,279        )280        expected = {281            'Str': 'mystring',282            'ResponseMetadata': {283                'HTTPStatusCode': 200,284                'HTTPHeaders': headers,285            },286        }287        self.assertEqual(parsed, expected)288    def test_response_metadata_on_rest_json_response(self):289        parser = parsers.RestJSONParser()290        response = b'{"Str": "mystring"}'291        headers = {'x-amzn-requestid': 'request-id'}292        output_shape = model.StructureShape(293            'OutputShape',294            {295                'type': 'structure',296                'members': {297                    'Str': {298                        'shape': 'StringType',299                    }300                },301            },302            model.ShapeResolver({'StringType': {'type': 'string'}}),303        )304        parsed = parser.parse(305            {'body': response, 'headers': headers, 'status_code': 200},306            output_shape,307        )308        # Note that the response metadata is normalized to match the query309        # protocol, even though this is not how it appears in the output.310        self.assertEqual(311            parsed,312            {313                'Str': 'mystring',314                'ResponseMetadata': {315                    'RequestId': 'request-id',316                    'HTTPStatusCode': 200,317                    'HTTPHeaders': headers,318                },319            },320        )321    def test_metadata_always_exists_on_rest_json_response(self):322        # ResponseMetadata is used for more than just the request id. It323        # should always get populated, even if the request doesn't seem to324        # have an id.325        parser = parsers.RestJSONParser()326        response = b'{"Str": "mystring"}'327        headers = {}328        output_shape = model.StructureShape(329            'OutputShape',330            {331                'type': 'structure',332                'members': {333                    'Str': {334                        'shape': 'StringType',335                    }336                },337            },338            model.ShapeResolver({'StringType': {'type': 'string'}}),339        )340        parsed = parser.parse(341            {'body': response, 'headers': headers, 'status_code': 200},342            output_shape,343        )344        expected = {345            'Str': 'mystring',346            'ResponseMetadata': {347                'HTTPStatusCode': 200,348                'HTTPHeaders': headers,349            },350        }351        self.assertEqual(parsed, expected)352    def test_response_metadata_from_s3_response(self):353        # Even though s3 is a rest-xml service, it's response metadata354        # is slightly different.  It has two request ids, both come from355        # the response headers, are both are named differently from other356        # rest-xml responses.357        headers = {'x-amz-id-2': 'second-id', 'x-amz-request-id': 'request-id'}358        parser = parsers.RestXMLParser()359        parsed = parser.parse(360            {'body': '', 'headers': headers, 'status_code': 200}, None361        )362        self.assertEqual(363            parsed,364            {365                'ResponseMetadata': {366                    'RequestId': 'request-id',367                    'HostId': 'second-id',368                    'HTTPStatusCode': 200,369                    'HTTPHeaders': headers,370                }371            },372        )373    def test_metadata_always_exists_on_rest_xml_response(self):374        # ResponseMetadata is used for more than just the request id. It375        # should always get populated, even if the request doesn't seem to376        # have an id.377        headers = {}378        parser = parsers.RestXMLParser()379        parsed = parser.parse(380            {'body': '', 'headers': headers, 'status_code': 200}, None381        )382        expected = {383            'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': headers}384        }385        self.assertEqual(parsed, expected)386    def test_checksum_metadata_parsed_from_response_context(self):387        headers = {}388        response_dict = {389            'status_code': 200,390            'headers': headers,391            'body': b'',392            'context': {'checksum': {'response_algorithm': 'crc32'}},393        }394        parser = parsers.RestXMLParser()395        parsed = parser.parse(response_dict, None)396        expected_algorithm = 'crc32'397        actual_algorithm = parsed['ResponseMetadata']['ChecksumAlgorithm']398        self.assertEqual(actual_algorithm, expected_algorithm)399class TestTaggedUnions(unittest.TestCase):400    def assert_tagged_union_response_with_unknown_member(401        self,402        parser,403        response,404        output_shape,405        expected_parsed_response,406        expected_log,407    ):408        with self.assertLogs() as captured_log:409            parsed = parser.parse(response, output_shape)410            self.assertEqual(parsed, expected_parsed_response)411            self.assertEqual(len(captured_log.records), 1)412            self.assertIn(413                (414                    'Received a tagged union response with member '415                    'unknown to client'416                ),417                captured_log.records[0].getMessage(),418            )419    def test_base_json_parser_handles_unknown_member(self):420        parser = parsers.JSONParser()421        response = b'{"Foo": "mystring"}'422        headers = {'x-amzn-requestid': 'request-id'}423        output_shape = model.StructureShape(424            'OutputShape',425            {426                'type': 'structure',427                'union': True,428                'members': {429                    'Str': {430                        'shape': 'StringType',431                    }432                },433            },434            model.ShapeResolver({'StringType': {'type': 'string'}}),435        )436        response = {'body': response, 'headers': headers, 'status_code': 200}437        # Parsed response omits data from service since it is not438        # modeled in the client439        expected_parsed_response = {440            'SDK_UNKNOWN_MEMBER': {'name': 'Foo'},441            'ResponseMetadata': {442                'RequestId': 'request-id',443                'HTTPStatusCode': 200,444                'HTTPHeaders': {'x-amzn-requestid': 'request-id'},445            },446        }447        expected_log = "Received a response with an unknown member Foo set"448        self.assert_tagged_union_response_with_unknown_member(449            parser,450            response,451            output_shape,452            expected_parsed_response,453            expected_log,454        )455    def test_base_xml_parser_handles_unknown_member(self):456        parser = parsers.QueryParser()457        response = (458            b'<OperationNameResponse>'459            b'  <OperationNameResult><Foo>mystring</Foo></OperationNameResult>'460            b'  <ResponseMetadata>'461            b'    <RequestId>request-id</RequestId>'462            b'  </ResponseMetadata>'463            b'</OperationNameResponse>'464        )465        output_shape = model.StructureShape(466            'OutputShape',467            {468                'type': 'structure',469                'union': True,470                'resultWrapper': 'OperationNameResult',471                'members': {472                    'Str': {473                        'shape': 'StringType',474                    },475                },476            },477            model.ShapeResolver(478                {479                    'StringType': {480                        'type': 'string',481                    },482                }483            ),484        )485        response = {'body': response, 'headers': {}, 'status_code': 200}486        # Parsed response omits data from service since it is not487        # modeled in the client488        expected_parsed_response = {489            'SDK_UNKNOWN_MEMBER': {'name': 'Foo'},490            'ResponseMetadata': {491                'RequestId': 'request-id',492                'HTTPStatusCode': 200,493                'HTTPHeaders': {},494            },495        }496        expected_log = "Received a response with an unknown member Foo set"497        self.assert_tagged_union_response_with_unknown_member(498            parser,499            response,500            output_shape,501            expected_parsed_response,502            expected_log,503        )504    def test_parser_errors_out_when_multiple_members_set(self):505        parser = parsers.JSONParser()506        response = b'{"Foo": "mystring", "Bar": "mystring2"}'507        headers = {'x-amzn-requestid': 'request-id'}508        output_shape = model.StructureShape(509            'OutputShape',510            {511                'type': 'structure',512                'union': True,513                'members': {514                    'Foo': {515                        'shape': 'StringType',516                    },517                    'Bar': {518                        'shape': 'StringType',519                    },520                },521            },522            model.ShapeResolver({'StringType': {'type': 'string'}}),523        )524        response = {'body': response, 'headers': headers, 'status_code': 200}525        with self.assertRaises(parsers.ResponseParserError):526            parser.parse(response, output_shape)527class TestHeaderResponseInclusion(unittest.TestCase):528    def create_parser(self):529        return parsers.JSONParser()530    def create_arbitary_output_shape(self):531        output_shape = model.StructureShape(532            'OutputShape',533            {534                'type': 'structure',535                'members': {536                    'Str': {537                        'shape': 'StringType',538                    }539                },540            },541            model.ShapeResolver({'StringType': {'type': 'string'}}),542        )543        return output_shape544    def test_can_add_errors_into_response(self):545        parser = self.create_parser()546        headers = {547            'x-amzn-requestid': 'request-id',548            'Header1': 'foo',549            'Header2': 'bar',550        }551        output_shape = self.create_arbitary_output_shape()552        parsed = parser.parse(553            {'body': b'{}', 'headers': headers, 'status_code': 200},554            output_shape,555        )556        # The mapped header's keys should all be lower cased557        parsed_headers = {558            'x-amzn-requestid': 'request-id',559            'header1': 'foo',560            'header2': 'bar',561        }562        # Response headers should be mapped as HTTPHeaders.563        self.assertEqual(564            parsed['ResponseMetadata']['HTTPHeaders'], parsed_headers565        )566    def test_can_always_json_serialize_headers(self):567        parser = self.create_parser()568        original_headers = {569            'x-amzn-requestid': 'request-id',570            'Header1': 'foo',571        }572        headers = CustomHeaderDict(original_headers)573        output_shape = self.create_arbitary_output_shape()574        parsed = parser.parse(575            {'body': b'{}', 'headers': headers, 'status_code': 200},576            output_shape,577        )578        metadata = parsed['ResponseMetadata']579        # We've had the contract that you can json serialize a580        # response.  So we want to ensure that despite using a CustomHeaderDict581        # we can always JSON dumps the response metadata.582        self.assertEqual(583            json.loads(json.dumps(metadata))['HTTPHeaders']['header1'], 'foo'584        )585class TestResponseParsingDatetimes(unittest.TestCase):586    def test_can_parse_float_timestamps(self):587        # The type "timestamp" can come back as both an integer or as a float.588        # We need to make sure we handle the case where the timestamp comes589        # back as a float.  It might make sense to move this to protocol tests.590        output_shape = model.Shape(591            shape_name='datetime', shape_model={'type': 'timestamp'}592        )593        parser = parsers.JSONParser()594        timestamp_as_float = b'1407538750.49'595        expected_parsed = datetime.datetime(596            2014, 8, 8, 22, 59, 10, 490000, tzinfo=tzutc()597        )598        parsed = parser.parse(599            {'body': timestamp_as_float, 'headers': [], 'status_code': 200},600            output_shape,601        )602        self.assertEqual(parsed, expected_parsed)603class TestResponseParserFactory(unittest.TestCase):604    def setUp(self):605        self.factory = parsers.ResponseParserFactory()606    def test_rest_parser(self):607        parser = self.factory.create_parser('rest-xml')608        self.assertTrue(isinstance(parser, parsers.BaseRestParser))609        self.assertTrue(isinstance(parser, parsers.BaseXMLResponseParser))610    def test_json_parser(self):611        parser = self.factory.create_parser('json')612        self.assertTrue(isinstance(parser, parsers.BaseJSONParser))613class TestCanDecorateResponseParsing(unittest.TestCase):614    def setUp(self):615        self.factory = parsers.ResponseParserFactory()616    def create_request_dict(self, with_body):617        return {'body': with_body, 'headers': [], 'status_code': 200}618    def test_normal_blob_parsing(self):619        output_shape = model.Shape(620            shape_name='BlobType', shape_model={'type': 'blob'}621        )622        parser = self.factory.create_parser('json')623        hello_world_b64 = b'"aGVsbG8gd29ybGQ="'624        expected_parsed = b'hello world'625        parsed = parser.parse(626            self.create_request_dict(with_body=hello_world_b64), output_shape627        )628        self.assertEqual(parsed, expected_parsed)629    def test_can_decorate_scalar_parsing(self):630        output_shape = model.Shape(631            shape_name='BlobType', shape_model={'type': 'blob'}632        )633        # Here we're overriding the blob parser so that634        # we can change it to a noop parser.635        self.factory.set_parser_defaults(blob_parser=lambda x: x)636        parser = self.factory.create_parser('json')637        hello_world_b64 = b'"aGVsbG8gd29ybGQ="'638        expected_parsed = "aGVsbG8gd29ybGQ="639        parsed = parser.parse(640            self.create_request_dict(with_body=hello_world_b64), output_shape641        )642        self.assertEqual(parsed, expected_parsed)643    def test_can_decorate_timestamp_parser(self):644        output_shape = model.Shape(645            shape_name='datetime', shape_model={'type': 'timestamp'}646        )647        # Here we're overriding the timestamp parser so that648        # we can change it to just convert a string to an integer649        # instead of converting to a datetime.650        self.factory.set_parser_defaults(timestamp_parser=lambda x: int(x))651        parser = self.factory.create_parser('json')652        timestamp_as_int = b'1407538750'653        expected_parsed = int(timestamp_as_int)654        parsed = parser.parse(655            self.create_request_dict(with_body=timestamp_as_int), output_shape656        )657        self.assertEqual(parsed, expected_parsed)658class TestHandlesNoOutputShape(unittest.TestCase):659    """Verify that each protocol handles no output shape properly."""660    def test_empty_rest_json_response(self):661        headers = {'x-amzn-requestid': 'request-id'}662        parser = parsers.RestJSONParser()663        output_shape = None664        parsed = parser.parse(665            {'body': b'', 'headers': headers, 'status_code': 200}, output_shape666        )667        self.assertEqual(668            parsed,669            {670                'ResponseMetadata': {671                    'RequestId': 'request-id',672                    'HTTPStatusCode': 200,673                    'HTTPHeaders': headers,674                }675            },676        )677    def test_empty_rest_xml_response(self):678        # This is the format used by cloudfront, route53.679        headers = {'x-amzn-requestid': 'request-id'}680        parser = parsers.RestXMLParser()681        output_shape = None682        parsed = parser.parse(683            {'body': b'', 'headers': headers, 'status_code': 200}, output_shape684        )685        self.assertEqual(686            parsed,687            {688                'ResponseMetadata': {689                    'RequestId': 'request-id',690                    'HTTPStatusCode': 200,691                    'HTTPHeaders': headers,692                }693            },694        )695    def test_empty_query_response(self):696        body = (697            b'<DeleteTagsResponse xmlns="http://autoscaling.amazonaws.com/">'698            b'  <ResponseMetadata>'699            b'    <RequestId>request-id</RequestId>'700            b'  </ResponseMetadata>'701            b'</DeleteTagsResponse>'702        )703        parser = parsers.QueryParser()704        output_shape = None705        parsed = parser.parse(706            {'body': body, 'headers': {}, 'status_code': 200}, output_shape707        )708        self.assertEqual(709            parsed,710            {711                'ResponseMetadata': {712                    'RequestId': 'request-id',713                    'HTTPStatusCode': 200,714                    'HTTPHeaders': {},715                }716            },717        )718    def test_empty_json_response(self):719        headers = {'x-amzn-requestid': 'request-id'}720        # Output shape of None represents no output shape in the model.721        output_shape = None722        parser = parsers.JSONParser()723        parsed = parser.parse(724            {'body': b'', 'headers': headers, 'status_code': 200}, output_shape725        )726        self.assertEqual(727            parsed,728            {729                'ResponseMetadata': {730                    'RequestId': 'request-id',731                    'HTTPStatusCode': 200,732                    'HTTPHeaders': headers,733                }734            },735        )736class TestHandlesInvalidXMLResponses(unittest.TestCase):737    def test_invalid_xml_shown_in_error_message(self):738        # Missing the closing XML tags.739        invalid_xml = (740            b'<DeleteTagsResponse xmlns="http://autoscaling.amazonaws.com/">'741            b'  <ResponseMetadata>'742        )743        parser = parsers.QueryParser()744        output_shape = None745        # The XML body should be in the error message.746        with self.assertRaisesRegex(747            parsers.ResponseParserError, '<DeleteTagsResponse'748        ):749            parser.parse(750                {'body': invalid_xml, 'headers': {}, 'status_code': 200},751                output_shape,752            )753class TestRESTXMLResponses(unittest.TestCase):754    def test_multiple_structures_list_returns_struture(self):755        # This is to handle the scenario when something is modeled756        # as a structure and instead a list of structures is returned.757        # For this case, a single element from the list should be parsed758        # For botocore, this will be the first element.759        # Currently, this logic may happen in s3's GetBucketLifecycle760        # operation.761        headers = {}762        parser = parsers.RestXMLParser()763        body = (764            '<?xml version="1.0" ?>'765            '<OperationName xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'766            '	<Foo><Bar>first_value</Bar></Foo>'767            '	<Foo><Bar>middle_value</Bar></Foo>'768            '	<Foo><Bar>last_value</Bar></Foo>'769            '</OperationName>'770        )771        builder = model.DenormalizedStructureBuilder()772        output_shape = builder.with_members(773            {774                'Foo': {775                    'type': 'structure',776                    'members': {777                        'Bar': {778                            'type': 'string',779                        }780                    },781                }782            }783        ).build_model()784        parsed = parser.parse(785            {'body': body, 'headers': headers, 'status_code': 200},786            output_shape,787        )788        # Ensure the first element is used out of the list.789        self.assertEqual(parsed['Foo'], {'Bar': 'first_value'})790class TestEventStreamParsers(unittest.TestCase):791    def setUp(self):792        self.parser = parsers.EventStreamXMLParser()793        self.output_shape = model.StructureShape(794            'EventStream',795            {796                'eventstream': True,797                'type': 'structure',798                'members': {799                    'EventA': {'shape': 'EventAStructure'},800                    'EventB': {'shape': 'EventBStructure'},801                    'EventC': {'shape': 'EventCStructure'},802                    'EventD': {'shape': 'EventDStructure'},803                    'EventException': {'shape': 'ExceptionShape'},804                },805            },806            model.ShapeResolver(807                {808                    'EventAStructure': {809                        'event': True,810                        'type': 'structure',811                        'members': {812                            'Stats': {813                                'shape': 'StatsStructure',814                                'eventpayload': True,815                            },816                            'Header': {817                                'shape': 'IntShape',818                                'eventheader': True,819                            },820                        },821                    },822                    'EventBStructure': {823                        'event': True,824                        'type': 'structure',825                        'members': {826                            'Body': {827                                'shape': 'BlobShape',828                                'eventpayload': True,829                            }830                        },831                    },832                    'EventCStructure': {833                        'event': True,834                        'type': 'structure',835                        'members': {836                            'Body': {837                                'shape': 'StringShape',838                                'eventpayload': True,839                            }840                        },841                    },842                    'EventDStructure': {843                        'event': True,844                        'type': 'structure',845                        'members': {846                            'StringField': {'shape': 'StringShape'},847                            'IntField': {'shape': 'IntShape'},848                            'Header': {849                                'shape': 'IntShape',850                                'eventheader': True,851                            },852                        },853                    },854                    'StatsStructure': {855                        'type': 'structure',856                        'members': {857                            'StringField': {'shape': 'StringShape'},858                            'IntField': {'shape': 'IntShape'},859                        },860                    },861                    'BlobShape': {'type': 'blob'},862                    'StringShape': {'type': 'string'},863                    'IntShape': {'type': 'integer'},864                    'ExceptionShape': {865                        'exception': True,866                        'type': 'structure',867                        'members': {'message': {'shape': 'StringShape'}},868                    },869                }870            ),871        )872    def parse_event(self, headers=None, body=None, status_code=200):873        response_dict = {874            'body': body,875            'headers': headers,876            'status_code': status_code,877        }878        return self.parser.parse(response_dict, self.output_shape)879    def test_parses_event_xml(self):880        headers = {'Header': 123, ':event-type': 'EventA'}881        body = (882            b'<Stats xmlns="">'883            b'  <StringField>abcde</StringField>'884            b'  <IntField>1234</IntField>'885            b'</Stats>'886        )887        parsed = self.parse_event(headers, body)888        expected = {889            'EventA': {890                'Header': 123,891                'Stats': {'StringField': 'abcde', 'IntField': 1234},892            }893        }894        self.assertEqual(parsed, expected)895    def test_parses_event_bad_xml(self):896        headers = {'Header': 123, ':event-type': 'EventA'}897        parsed = self.parse_event(headers, b'')898        expected = {'EventA': {'Header': 123, 'Stats': {}}}899        self.assertEqual(parsed, expected)900    def test_parses_event_blob(self):901        headers = {':event-type': 'EventB'}902        parsed = self.parse_event(headers, b'blob')903        expected = {'EventB': {'Body': b'blob'}}904        self.assertEqual(parsed, expected)905    def test_parses_event_string(self):906        headers = {':event-type': 'EventC'}907        parsed = self.parse_event(headers, b'blob')908        expected = {'EventC': {'Body': 'blob'}}909        self.assertEqual(parsed, expected)910    def test_parses_payload_implicit(self):911        headers = {'Header': 123, ':event-type': 'EventD'}912        body = (913            b'<EventD xmlns="">'914            b'  <StringField>abcde</StringField>'915            b'  <IntField>1234</IntField>'916            b'</EventD>'917        )918        parsed = self.parse_event(headers, body)919        expected = {920            'EventD': {'Header': 123, 'StringField': 'abcde', 'IntField': 1234}921        }922        self.assertEqual(parsed, expected)923    def test_parses_error_event(self):924        error_code = 'client/SomeError'925        error_message = 'You did something wrong'926        headers = {927            ':message-type': 'error',928            ':error-code': error_code,929            ':error-message': error_message,930        }931        body = b''932        parsed = self.parse_event(headers, body, status_code=400)933        expected = {'Error': {'Code': error_code, 'Message': error_message}}934        self.assertEqual(parsed, expected)935    def test_parses_exception_event(self):936        self.parser = parsers.EventStreamJSONParser()937        error_code = 'EventException'938        headers = {939            ':message-type': 'exception',940            ':exception-type': error_code,941        }942        body = b'{"message": "You did something wrong"}'943        parsed = self.parse_event(headers, body, status_code=400)944        expected = {945            'Error': {'Code': error_code, 'Message': 'You did something wrong'}946        }947        self.assertEqual(parsed, expected)948    def test_parses_event_json(self):949        self.parser = parsers.EventStreamJSONParser()950        headers = {':event-type': 'EventD'}951        body = b'{' b'  "StringField": "abcde",' b'  "IntField": 1234' b'}'952        parsed = self.parse_event(headers, body)953        expected = {'EventD': {'StringField': 'abcde', 'IntField': 1234}}954        self.assertEqual(parsed, expected)955class TestParseErrorResponses(unittest.TestCase):956    # This class consolidates all the error parsing tests957    # across all the protocols.  We may potentially pull958    # this into the shared protocol tests in the future,959    # so consolidating them into a single class will make960    # this easier.961    def setUp(self):962        self.error_shape = model.StructureShape(963            'ErrorShape',964            {965                'type': 'structure',966                'exception': True,967                'members': {968                    'ModeledField': {969                        'shape': 'StringType',970                    }971                },972            },973            model.ShapeResolver({'StringType': {'type': 'string'}}),974        )975    def test_response_metadata_errors_for_json_protocol(self):976        parser = parsers.JSONParser()977        response = {978            "body": b"""979                {"__type":"amazon.foo.validate#ValidationException",980                 "message":"this is a message"}981                """,982            "status_code": 400,983            "headers": {"x-amzn-requestid": "request-id"},984        }985        parsed = parser.parse(response, None)986        # Even (especially) on an error condition, the987        # ResponseMetadata should be populated.988        self.assertIn('ResponseMetadata', parsed)989        self.assertEqual(parsed['ResponseMetadata']['RequestId'], 'request-id')990        self.assertIn('Error', parsed)991        self.assertEqual(parsed['Error']['Message'], 'this is a message')992        self.assertEqual(parsed['Error']['Code'], 'ValidationException')993    def test_response_metadata_errors_alternate_form_json_protocol(self):994        # Sometimes there is no '#' in the __type.  We need to be995        # able to parse this error message as well.996        parser = parsers.JSONParser()997        response = {998            "body": b"""999                {"__type":"ValidationException",1000                 "message":"this is a message"}1001                """,1002            "status_code": 400,1003            "headers": {"x-amzn-requestid": "request-id"},1004        }1005        parsed = parser.parse(response, None)1006        self.assertIn('Error', parsed)1007        self.assertEqual(parsed['Error']['Message'], 'this is a message')1008        self.assertEqual(parsed['Error']['Code'], 'ValidationException')1009    def test_parse_error_response_for_query_protocol(self):1010        body = (1011            b'<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">'1012            b'  <Error>'1013            b'    <Type>Sender</Type>'1014            b'    <Code>InvalidInput</Code>'1015            b'    <Message>ARN asdf is not valid.</Message>'1016            b'  </Error>'1017            b'  <RequestId>request-id</RequestId>'1018            b'</ErrorResponse>'1019        )1020        parser = parsers.QueryParser()1021        parsed = parser.parse(1022            {'body': body, 'headers': {}, 'status_code': 400}, None1023        )1024        self.assertIn('Error', parsed)1025        self.assertEqual(1026            parsed['Error'],1027            {1028                'Code': 'InvalidInput',1029                'Message': 'ARN asdf is not valid.',1030                'Type': 'Sender',1031            },1032        )1033    def test_can_parse_sdb_error_response_query_protocol(self):1034        body = (1035            b'<OperationNameResponse>'1036            b'    <Errors>'1037            b'        <Error>'1038            b'            <Code>1</Code>'1039            b'            <Message>msg</Message>'1040            b'        </Error>'1041            b'    </Errors>'1042            b'    <RequestId>abc-123</RequestId>'1043            b'</OperationNameResponse>'1044        )1045        parser = parsers.QueryParser()1046        parsed = parser.parse(1047            {'body': body, 'headers': {}, 'status_code': 500}, None1048        )1049        self.assertIn('Error', parsed)1050        self.assertEqual(parsed['Error'], {'Code': '1', 'Message': 'msg'})1051        self.assertEqual(1052            parsed['ResponseMetadata'],1053            {'RequestId': 'abc-123', 'HTTPStatusCode': 500, 'HTTPHeaders': {}},1054        )1055    def test_can_parser_ec2_errors(self):1056        body = (1057            b'<Response>'1058            b'  <Errors>'1059            b'    <Error>'1060            b'      <Code>InvalidInstanceID.NotFound</Code>'1061            b'      <Message>The instance ID i-12345 does not exist</Message>'1062            b'    </Error>'1063            b'  </Errors>'1064            b'  <RequestID>06f382b0-d521-4bb6-988c-ca49d5ae6070</RequestID>'1065            b'</Response>'1066        )1067        parser = parsers.EC2QueryParser()1068        parsed = parser.parse(1069            {'body': body, 'headers': {}, 'status_code': 400}, None1070        )1071        self.assertIn('Error', parsed)1072        self.assertEqual(1073            parsed['Error'],1074            {1075                'Code': 'InvalidInstanceID.NotFound',1076                'Message': 'The instance ID i-12345 does not exist',1077            },1078        )1079    def test_can_parse_rest_xml_errors(self):1080        body = (1081            b'<ErrorResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/">'1082            b'  <Error>'1083            b'    <Type>Sender</Type>'1084            b'    <Code>NoSuchHostedZone</Code>'1085            b'    <Message>No hosted zone found with ID: foobar</Message>'1086            b'  </Error>'1087            b'  <RequestId>bc269cf3-d44f-11e5-8779-2d21c30eb3f1</RequestId>'1088            b'</ErrorResponse>'1089        )1090        parser = parsers.RestXMLParser()1091        parsed = parser.parse(1092            {'body': body, 'headers': {}, 'status_code': 400}, None1093        )1094        self.assertIn('Error', parsed)1095        self.assertEqual(1096            parsed['Error'],1097            {1098                'Code': 'NoSuchHostedZone',1099                'Message': 'No hosted zone found with ID: foobar',1100                'Type': 'Sender',1101            },1102        )1103    def test_can_parse_rest_json_errors(self):1104        body = b'{"Message":"Function not found: foo","Type":"User"}'1105        headers = {1106            'x-amzn-requestid': 'request-id',1107            'x-amzn-errortype': 'ResourceNotFoundException:http://url/',1108        }1109        parser = parsers.RestJSONParser()1110        parsed = parser.parse(1111            {'body': body, 'headers': headers, 'status_code': 400}, None1112        )1113        self.assertIn('Error', parsed)1114        self.assertEqual(1115            parsed['Error'],1116            {1117                'Code': 'ResourceNotFoundException',1118                'Message': 'Function not found: foo',1119            },1120        )1121    def test_error_response_with_no_body_rest_json(self):1122        parser = parsers.RestJSONParser()1123        response = b''1124        headers = {'content-length': '0', 'connection': 'keep-alive'}1125        output_shape = None1126        parsed = parser.parse(1127            {'body': response, 'headers': headers, 'status_code': 504},1128            output_shape,1129        )1130        self.assertIn('Error', parsed)1131        self.assertEqual(1132            parsed['Error'], {'Code': '504', 'Message': 'Gateway Timeout'}1133        )1134        self.assertEqual(1135            parsed['ResponseMetadata'],1136            {'HTTPStatusCode': 504, 'HTTPHeaders': headers},1137        )1138    def test_error_response_with_string_body_rest_json(self):1139        parser = parsers.RestJSONParser()1140        response = b'HTTP content length exceeded 1049600 bytes.'1141        headers = {'content-length': '0', 'connection': 'keep-alive'}1142        output_shape = None1143        parsed = parser.parse(1144            {'body': response, 'headers': headers, 'status_code': 413},1145            output_shape,1146        )1147        self.assertIn('Error', parsed)1148        self.assertEqual(1149            parsed['Error'],1150            {'Code': '413', 'Message': response.decode('utf-8')},1151        )1152        self.assertEqual(1153            parsed['ResponseMetadata'],1154            {'HTTPStatusCode': 413, 'HTTPHeaders': headers},1155        )1156    def test_error_response_with_xml_body_rest_json(self):1157        parser = parsers.RestJSONParser()1158        response = (1159            b'<AccessDeniedException>'1160            b'   <Message>Unable to determine service/operation name to be authorized</Message>'1161            b'</AccessDeniedException>'1162        )1163        headers = {'content-length': '0', 'connection': 'keep-alive'}1164        output_shape = None1165        parsed = parser.parse(1166            {'body': response, 'headers': headers, 'status_code': 403},1167            output_shape,1168        )1169        self.assertIn('Error', parsed)1170        self.assertEqual(1171            parsed['Error'],1172            {'Code': '403', 'Message': response.decode('utf-8')},1173        )1174        self.assertEqual(1175            parsed['ResponseMetadata'],1176            {'HTTPStatusCode': 403, 'HTTPHeaders': headers},1177        )1178    def test_s3_error_response(self):1179        body = (1180            b'<Error>'1181            b'  <Code>NoSuchBucket</Code>'1182            b'  <Message>error message</Message>'1183            b'  <BucketName>asdf</BucketName>'1184            b'  <RequestId>EF1EF43A74415102</RequestId>'1185            b'  <HostId>hostid</HostId>'1186            b'</Error>'1187        )1188        headers = {'x-amz-id-2': 'second-id', 'x-amz-request-id': 'request-id'}1189        parser = parsers.RestXMLParser()1190        parsed = parser.parse(1191            {'body': body, 'headers': headers, 'status_code': 400}, None1192        )1193        self.assertIn('Error', parsed)1194        self.assertEqual(1195            parsed['Error'],1196            {1197                'Code': 'NoSuchBucket',1198                'Message': 'error message',1199                'BucketName': 'asdf',1200                # We don't want the RequestId/HostId because they're already1201                # present in the ResponseMetadata key.1202            },1203        )1204        self.assertEqual(1205            parsed['ResponseMetadata'],1206            {1207                'RequestId': 'request-id',1208                'HostId': 'second-id',1209                'HTTPStatusCode': 400,1210                'HTTPHeaders': headers,1211            },1212        )1213    def test_s3_error_response_with_no_body(self):1214        # If you try to HeadObject a key that does not exist,1215        # you will get an empty body.  When this happens1216        # we expect that we will use Code/Message from the1217        # HTTP status code.1218        body = ''1219        headers = {'x-amz-id-2': 'second-id', 'x-amz-request-id': 'request-id'}1220        parser = parsers.RestXMLParser()1221        parsed = parser.parse(1222            {'body': body, 'headers': headers, 'status_code': 404}, None1223        )1224        self.assertIn('Error', parsed)1225        self.assertEqual(1226            parsed['Error'],1227            {1228                'Code': '404',1229                'Message': 'Not Found',1230            },1231        )1232        self.assertEqual(1233            parsed['ResponseMetadata'],1234            {1235                'RequestId': 'request-id',1236                'HostId': 'second-id',1237                'HTTPStatusCode': 404,1238                'HTTPHeaders': headers,1239            },1240        )1241    def test_can_parse_glacier_error_response(self):1242        body = (1243            b'{"code":"AccessDeniedException","type":"Client","message":'1244            b'"Access denied"}'1245        )1246        headers = {'x-amzn-requestid': 'request-id'}1247        parser = parsers.RestJSONParser()1248        parsed = parser.parse(1249            {'body': body, 'headers': headers, 'status_code': 400}, None1250        )1251        self.assertEqual(1252            parsed['Error'],1253            {'Message': 'Access denied', 'Code': 'AccessDeniedException'},1254        )1255    def test_can_parse_restjson_error_code(self):1256        body = b'''{1257            "status": "error",1258            "errors": [{"message": "[*Deprecated*: blah"}],1259            "adds": 0,1260            "__type": "#WasUnableToParseThis",1261            "message": "blah",1262            "deletes": 0}'''1263        headers = {'x-amzn-requestid': 'request-id'}1264        parser = parsers.RestJSONParser()1265        parsed = parser.parse(1266            {'body': body, 'headers': headers, 'status_code': 400}, None1267        )1268        self.assertEqual(1269            parsed['Error'],1270            {'Message': 'blah', 'Code': 'WasUnableToParseThis'},1271        )1272    def test_can_parse_with_case_insensitive_keys(self):1273        body = (1274            b'{"Code":"AccessDeniedException","type":"Client","Message":'1275            b'"Access denied"}'1276        )1277        headers = {'x-amzn-requestid': 'request-id'}1278        parser = parsers.RestJSONParser()1279        parsed = parser.parse(1280            {'body': body, 'headers': headers, 'status_code': 400}, None1281        )1282        self.assertEqual(1283            parsed['Error'],1284            {'Message': 'Access denied', 'Code': 'AccessDeniedException'},1285        )1286    def test_can_parse_rest_json_modeled_fields(self):1287        body = (1288            b'{"ModeledField":"Some modeled field",'1289            b'"Message":"Some message"}'1290        )1291        parser = parsers.RestJSONParser()1292        response_dict = {1293            'status_code': 400,1294            'headers': {},1295            'body': body,1296        }1297        parsed = parser.parse(response_dict, self.error_shape)1298        expected_parsed = {1299            'ModeledField': 'Some modeled field',1300        }1301        self.assertEqual(parsed, expected_parsed)1302    def test_can_parse_rest_xml_modeled_fields(self):1303        parser = parsers.RestXMLParser()1304        body = (1305            b'<?xml version="1.0"?>\n<ErrorResponse xmlns="http://foo.bar">'1306            b'<Error><Type>Sender</Type><Code>NoSuchDistribution</Code>'1307            b'<Message>The specified distribution does not exist.</Message>'1308            b'<ModeledField>Some modeled field</ModeledField>'1309            b'</Error>'1310            b'</ErrorResponse>'1311        )1312        response_dict = {1313            'status_code': 400,1314            'headers': {},1315            'body': body,1316        }1317        parsed = parser.parse(response_dict, self.error_shape)1318        expected_parsed = {1319            'ModeledField': 'Some modeled field',1320        }1321        self.assertEqual(parsed, expected_parsed)1322    def test_can_parse_ec2_modeled_fields(self):1323        body = (1324            b'<Response><Errors><Error>'1325            b'<Code>ExceptionShape</Code>'1326            b'<Message>Foo message</Message>'1327            b'<ModeledField>Some modeled field</ModeledField>'1328            b'</Error></Errors></Response>'1329        )1330        parser = parsers.EC2QueryParser()1331        response_dict = {1332            'status_code': 400,1333            'headers': {},1334            'body': body,1335        }1336        parsed = parser.parse(response_dict, self.error_shape)1337        expected_parsed = {1338            'ModeledField': 'Some modeled field',1339        }1340        self.assertEqual(parsed, expected_parsed)1341    def test_can_parse_query_modeled_fields(self):1342        parser = parsers.QueryParser()1343        body = (1344            b'<?xml version="1.0"?>\n<ErrorResponse xmlns="http://foo.bar">'1345            b'<Error><Type>Sender</Type><Code>SomeCode</Code>'1346            b'<Message>A message</Message>'1347            b'<ModeledField>Some modeled field</ModeledField>'1348            b'</Error>'1349            b'</ErrorResponse>'1350        )1351        response_dict = {1352            'status_code': 400,1353            'headers': {},1354            'body': body,1355        }1356        parsed = parser.parse(response_dict, self.error_shape)1357        expected_parsed = {1358            'ModeledField': 'Some modeled field',1359        }1360        self.assertEqual(parsed, expected_parsed)1361    def test_can_parse_json_modeled_fields(self):1362        body = (1363            b'{"ModeledField":"Some modeled field",'1364            b'"Message":"Some message",'1365            b'"__type": "Prefix#SomeError"}'1366        )1367        parser = parsers.JSONParser()1368        response_dict = {1369            'status_code': 400,1370            'headers': {},1371            'body': body,1372        }1373        parsed = parser.parse(response_dict, self.error_shape)1374        expected_parsed = {1375            'ModeledField': 'Some modeled field',1376        }1377        self.assertEqual(parsed, expected_parsed)1378    def test_can_parse_route53_with_missing_message(self):1379        # The message isn't always in the XML response (or even the headers).1380        # We should be able to handle this gracefully and still at least1381        # populate a "Message" key so that consumers don't have to1382        # conditionally check for this.1383        body = (1384            b'<ErrorResponse>'1385            b'  <Error>'1386            b'    <Type>Sender</Type>'1387            b'    <Code>InvalidInput</Code>'1388            b'  </Error>'1389            b'  <RequestId>id</RequestId>'1390            b'</ErrorResponse>'1391        )1392        parser = parsers.RestXMLParser()1393        parsed = parser.parse(1394            {'body': body, 'headers': {}, 'status_code': 400}, None1395        )1396        error = parsed['Error']1397        self.assertEqual(error['Code'], 'InvalidInput')1398        # Even though there's no <Message /> we should1399        # still populate an empty string.1400        self.assertEqual(error['Message'], '')1401def _generic_test_bodies():1402    generic_html_body = (1403        b'<html><body><b>Http/1.1 Service Unavailable</b></body></html>'1404    )1405    empty_body = b''1406    none_body = None1407    return [generic_html_body, empty_body, none_body]1408@pytest.mark.parametrize(1409    "parser, body",1410    itertools.product(1411        parsers.PROTOCOL_PARSERS.values(), _generic_test_bodies()1412    ),1413)1414def test_can_handle_generic_error_message(parser, body):1415    # There are times when you can get a service to respond with a generic1416    # html error page.  We should be able to handle this case.1417    parsed = parser().parse(1418        {'body': body, 'headers': {}, 'status_code': 503}, None1419    )1420    assert parsed['Error'] == {'Code': '503', 'Message': 'Service Unavailable'}...options.js
Source:options.js  
1/*	Every input option is tested and parsed. This'll prevent2	endless validation in internal methods. These tests are3	structured with an item for every option available. An4	option can be marked as required by setting the 'r' flag.5	The testing function is provided with three arguments:6		- The provided value for the option;7		- A reference to the options object;8		- The name for the option;9	The testing function returns false when an error is detected,10	or true when everything is OK. It can also modify the option11	object, to make sure all values can be correctly looped elsewhere. */12	var defaultFormatter = { 'to': function( value ){13		return value !== undefined && value.toFixed(2);14	}, 'from': Number };15	function validateFormat ( entry ) {16		// Any object with a to and from method is supported.17		if ( isValidFormatter(entry) ) {18			return true;19		}20		throw new Error("noUiSlider (" + VERSION + "): 'format' requires 'to' and 'from' methods.");21	}22	function testStep ( parsed, entry ) {23		if ( !isNumeric( entry ) ) {24			throw new Error("noUiSlider (" + VERSION + "): 'step' is not numeric.");25		}26		// The step option can still be used to set stepping27		// for linear sliders. Overwritten if set in 'range'.28		parsed.singleStep = entry;29	}30	function testRange ( parsed, entry ) {31		// Filter incorrect input.32		if ( typeof entry !== 'object' || Array.isArray(entry) ) {33			throw new Error("noUiSlider (" + VERSION + "): 'range' is not an object.");34		}35		// Catch missing start or end.36		if ( entry.min === undefined || entry.max === undefined ) {37			throw new Error("noUiSlider (" + VERSION + "): Missing 'min' or 'max' in 'range'.");38		}39		// Catch equal start or end.40		if ( entry.min === entry.max ) {41			throw new Error("noUiSlider (" + VERSION + "): 'range' 'min' and 'max' cannot be equal.");42		}43		parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.singleStep);44	}45	function testStart ( parsed, entry ) {46		entry = asArray(entry);47		// Validate input. Values aren't tested, as the public .val method48		// will always provide a valid location.49		if ( !Array.isArray( entry ) || !entry.length ) {50			throw new Error("noUiSlider (" + VERSION + "): 'start' option is incorrect.");51		}52		// Store the number of handles.53		parsed.handles = entry.length;54		// When the slider is initialized, the .val method will55		// be called with the start options.56		parsed.start = entry;57	}58	function testSnap ( parsed, entry ) {59		// Enforce 100% stepping within subranges.60		parsed.snap = entry;61		if ( typeof entry !== 'boolean' ){62			throw new Error("noUiSlider (" + VERSION + "): 'snap' option must be a boolean.");63		}64	}65	function testAnimate ( parsed, entry ) {66		// Enforce 100% stepping within subranges.67		parsed.animate = entry;68		if ( typeof entry !== 'boolean' ){69			throw new Error("noUiSlider (" + VERSION + "): 'animate' option must be a boolean.");70		}71	}72	function testAnimationDuration ( parsed, entry ) {73		parsed.animationDuration = entry;74		if ( typeof entry !== 'number' ){75			throw new Error("noUiSlider (" + VERSION + "): 'animationDuration' option must be a number.");76		}77	}78	function testConnect ( parsed, entry ) {79		var connect = [false];80		var i;81		// Map legacy options82		if ( entry === 'lower' ) {83			entry = [true, false];84		}85		else if ( entry === 'upper' ) {86			entry = [false, true];87		}88		// Handle boolean options89		if ( entry === true || entry === false ) {90			for ( i = 1; i < parsed.handles; i++ ) {91				connect.push(entry);92			}93			connect.push(false);94		}95		// Reject invalid input96		else if ( !Array.isArray( entry ) || !entry.length || entry.length !== parsed.handles + 1 ) {97			throw new Error("noUiSlider (" + VERSION + "): 'connect' option doesn't match handle count.");98		}99		else {100			connect = entry;101		}102		parsed.connect = connect;103	}104	function testOrientation ( parsed, entry ) {105		// Set orientation to an a numerical value for easy106		// array selection.107		switch ( entry ){108		  case 'horizontal':109			parsed.ort = 0;110			break;111		  case 'vertical':112			parsed.ort = 1;113			break;114		  default:115			throw new Error("noUiSlider (" + VERSION + "): 'orientation' option is invalid.");116		}117	}118	function testMargin ( parsed, entry ) {119		if ( !isNumeric(entry) ){120			throw new Error("noUiSlider (" + VERSION + "): 'margin' option must be numeric.");121		}122		// Issue #582123		if ( entry === 0 ) {124			return;125		}126		parsed.margin = parsed.spectrum.getMargin(entry);127		if ( !parsed.margin ) {128			throw new Error("noUiSlider (" + VERSION + "): 'margin' option is only supported on linear sliders.");129		}130	}131	function testLimit ( parsed, entry ) {132		if ( !isNumeric(entry) ){133			throw new Error("noUiSlider (" + VERSION + "): 'limit' option must be numeric.");134		}135		parsed.limit = parsed.spectrum.getMargin(entry);136		if ( !parsed.limit || parsed.handles < 2 ) {137			throw new Error("noUiSlider (" + VERSION + "): 'limit' option is only supported on linear sliders with 2 or more handles.");138		}139	}140	function testPadding ( parsed, entry ) {141		if ( !isNumeric(entry) ){142			throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric.");143		}144		if ( entry === 0 ) {145			return;146		}147		parsed.padding = parsed.spectrum.getMargin(entry);148		if ( !parsed.padding ) {149			throw new Error("noUiSlider (" + VERSION + "): 'padding' option is only supported on linear sliders.");150		}151		if ( parsed.padding < 0 ) {152			throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be a positive number.");153		}154		if ( parsed.padding >= 50 ) {155			throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be less than half the range.");156		}157	}158	function testDirection ( parsed, entry ) {159		// Set direction as a numerical value for easy parsing.160		// Invert connection for RTL sliders, so that the proper161		// handles get the connect/background classes.162		switch ( entry ) {163		  case 'ltr':164			parsed.dir = 0;165			break;166		  case 'rtl':167			parsed.dir = 1;168			break;169		  default:170			throw new Error("noUiSlider (" + VERSION + "): 'direction' option was not recognized.");171		}172	}173	function testBehaviour ( parsed, entry ) {174		// Make sure the input is a string.175		if ( typeof entry !== 'string' ) {176			throw new Error("noUiSlider (" + VERSION + "): 'behaviour' must be a string containing options.");177		}178		// Check if the string contains any keywords.179		// None are required.180		var tap = entry.indexOf('tap') >= 0;181		var drag = entry.indexOf('drag') >= 0;182		var fixed = entry.indexOf('fixed') >= 0;183		var snap = entry.indexOf('snap') >= 0;184		var hover = entry.indexOf('hover') >= 0;185		if ( fixed ) {186			if ( parsed.handles !== 2 ) {187				throw new Error("noUiSlider (" + VERSION + "): 'fixed' behaviour must be used with 2 handles");188			}189			// Use margin to enforce fixed state190			testMargin(parsed, parsed.start[1] - parsed.start[0]);191		}192		parsed.events = {193			tap: tap || snap,194			drag: drag,195			fixed: fixed,196			snap: snap,197			hover: hover198		};199	}200	function testMultitouch ( parsed, entry ) {201		parsed.multitouch = entry;202		if ( typeof entry !== 'boolean' ){203			throw new Error("noUiSlider (" + VERSION + "): 'multitouch' option must be a boolean.");204		}205	}206	function testTooltips ( parsed, entry ) {207		if ( entry === false ) {208			return;209		}210		else if ( entry === true ) {211			parsed.tooltips = [];212			for ( var i = 0; i < parsed.handles; i++ ) {213				parsed.tooltips.push(true);214			}215		}216		else {217			parsed.tooltips = asArray(entry);218			if ( parsed.tooltips.length !== parsed.handles ) {219				throw new Error("noUiSlider (" + VERSION + "): must pass a formatter for all handles.");220			}221			parsed.tooltips.forEach(function(formatter){222				if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) {223					throw new Error("noUiSlider (" + VERSION + "): 'tooltips' must be passed a formatter or 'false'.");224				}225			});226		}227	}228	function testAriaFormat ( parsed, entry ) {229		parsed.ariaFormat = entry;230		validateFormat(entry);231	}232	function testFormat ( parsed, entry ) {233		parsed.format = entry;234		validateFormat(entry);235	}236	function testCssPrefix ( parsed, entry ) {237		if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) {238			throw new Error("noUiSlider (" + VERSION + "): 'cssPrefix' must be a string or `false`.");239		}240		parsed.cssPrefix = entry;241	}242	function testCssClasses ( parsed, entry ) {243		if ( entry !== undefined && typeof entry !== 'object' ) {244			throw new Error("noUiSlider (" + VERSION + "): 'cssClasses' must be an object.");245		}246		if ( typeof parsed.cssPrefix === 'string' ) {247			parsed.cssClasses = {};248			for ( var key in entry ) {249				if ( !entry.hasOwnProperty(key) ) { continue; }250				parsed.cssClasses[key] = parsed.cssPrefix + entry[key];251			}252		} else {253			parsed.cssClasses = entry;254		}255	}256	function testUseRaf ( parsed, entry ) {257		if ( entry === true || entry === false ) {258			parsed.useRequestAnimationFrame = entry;259		} else {260			throw new Error("noUiSlider (" + VERSION + "): 'useRequestAnimationFrame' option should be true (default) or false.");261		}262	}263	// Test all developer settings and parse to assumption-safe values.264	function testOptions ( options ) {265		// To prove a fix for #537, freeze options here.266		// If the object is modified, an error will be thrown.267		// Object.freeze(options);268		var parsed = {269			margin: 0,270			limit: 0,271			padding: 0,272			animate: true,273			animationDuration: 300,274			ariaFormat: defaultFormatter,275			format: defaultFormatter276		};277		// Tests are executed in the order they are presented here.278		var tests = {279			'step': { r: false, t: testStep },280			'start': { r: true, t: testStart },281			'connect': { r: true, t: testConnect },282			'direction': { r: true, t: testDirection },283			'snap': { r: false, t: testSnap },284			'animate': { r: false, t: testAnimate },285			'animationDuration': { r: false, t: testAnimationDuration },286			'range': { r: true, t: testRange },287			'orientation': { r: false, t: testOrientation },288			'margin': { r: false, t: testMargin },289			'limit': { r: false, t: testLimit },290			'padding': { r: false, t: testPadding },291			'behaviour': { r: true, t: testBehaviour },292			'multitouch': { r: true, t: testMultitouch },293			'ariaFormat': { r: false, t: testAriaFormat },294			'format': { r: false, t: testFormat },295			'tooltips': { r: false, t: testTooltips },296			'cssPrefix': { r: false, t: testCssPrefix },297			'cssClasses': { r: false, t: testCssClasses },298			'useRequestAnimationFrame': { r: false, t: testUseRaf }299		};300		var defaults = {301			'connect': false,302			'direction': 'ltr',303			'behaviour': 'tap',304			'multitouch': false,305			'orientation': 'horizontal',306			'cssPrefix' : 'noUi-',307			'cssClasses': {308				target: 'target',309				base: 'base',310				origin: 'origin',311				handle: 'handle',312				handleLower: 'handle-lower',313				handleUpper: 'handle-upper',314				horizontal: 'horizontal',315				vertical: 'vertical',316				background: 'background',317				connect: 'connect',318				ltr: 'ltr',319				rtl: 'rtl',320				draggable: 'draggable',321				drag: 'state-drag',322				tap: 'state-tap',323				active: 'active',324				tooltip: 'tooltip',325				pips: 'pips',326				pipsHorizontal: 'pips-horizontal',327				pipsVertical: 'pips-vertical',328				marker: 'marker',329				markerHorizontal: 'marker-horizontal',330				markerVertical: 'marker-vertical',331				markerNormal: 'marker-normal',332				markerLarge: 'marker-large',333				markerSub: 'marker-sub',334				value: 'value',335				valueHorizontal: 'value-horizontal',336				valueVertical: 'value-vertical',337				valueNormal: 'value-normal',338				valueLarge: 'value-large',339				valueSub: 'value-sub'340			},341			'useRequestAnimationFrame': true342		};343		// AriaFormat defaults to regular format, if any.344		if ( options.format && !options.ariaFormat ) {345			options.ariaFormat = options.format;346		}347		// Run all options through a testing mechanism to ensure correct348		// input. It should be noted that options might get modified to349		// be handled properly. E.g. wrapping integers in arrays.350		Object.keys(tests).forEach(function( name ){351			// If the option isn't set, but it is required, throw an error.352			if ( options[name] === undefined && defaults[name] === undefined ) {353				if ( tests[name].r ) {354					throw new Error("noUiSlider (" + VERSION + "): '" + name + "' is required.");355				}356				return true;357			}358			tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] );359		});360		// Forward pips options361		parsed.pips = options.pips;362		var styles = [['left', 'top'], ['right', 'bottom']];363		// Pre-define the styles.364		parsed.style = styles[parsed.dir][parsed.ort];365		parsed.styleOposite = styles[parsed.dir?0:1][parsed.ort];366		return parsed;...grammar.py
Source:grammar.py  
1import sys2from pyparsing import Word, alphas, Combine, nums, Regex, ParseException, string, Optional3class LogGrammar(object):4    """A class to define the format (grammar) of a log file. We heavily rely on pyparsing in this case.5    """6    def __init__(self, log_type=None):7        """The constructor of LogGrammar.8        """9        self.log_type = log_type10        if self.log_type == 'blue-gene':11            self.bluegene_grammar = self.__get_bluegene_grammar()12        elif self.log_type == 'spark':13            self.spark_grammar = self.__get_spark_grammar()14        elif self.log_type == 'windows':15            self.windows_grammar = self.__get_windows_grammar()16    @staticmethod17    def loading(number):18        if number % 1000 == 0:19            s = str(number) + ' ...'20            print(s, end='')21            print('\r', end='')22    @staticmethod23    def __get_bluegene_grammar():24        """The definition of BlueGene/L grammar.25        The BlueGene/L logs can be downloaded from [Useninx2006a]_ and26        this data was used in [Stearley2008]_.27        Returns28        -------29        bluegene_grammar    :30            Grammar for BlueGene/L supercomputer logs.31        References32        ----------33        .. [Usenix2006a]  The HPC4 data. URL: https://www.usenix.org/cfdr-data#hpc434        .. [Stearley2008] Stearley, J., & Oliner, A. J. Bad words: Finding faults in Spirit's syslogs.35                          In 8th IEEE International Symposium on Cluster Computing and the Grid, pp. 765-770.36        """37        ints = Word(nums)38        sock = Word(alphas + '-' + '_')39        number = ints40        date = Combine(ints + '.' + ints + '.' + ints)41        core1 = Word(alphas + nums + '-' + ':' + '_')42        datetime = Combine(ints + '-' + ints + '-' + ints + '-' + ints + '.' + ints + '.' + ints + '.' + ints)43        core2 = Word(alphas + nums + '-' + ':' + '_')44        source = Word(alphas + '(' + ')')45        service = Word(alphas + '_')46        info_type = Word(alphas)47        message = Regex('.*')48        # blue gene log grammar49        bluegene_grammar = sock + number + date + core1 + datetime + core2 + source + service + info_type + message50        return bluegene_grammar51    def parse_bluegenelog(self, log_line):52        """Parse the BlueGene/L logs based on defined grammar.53        Parameters54        ----------55        log_line    : str56            A log line to be parsed57        Returns58        -------59        parsed      : dict[str, str]60            A parsed BlueGene/L log.61        """62        parsed = dict()63        try:64            parsed_bluegenelog = self.bluegene_grammar.parseString(log_line)65            parsed['sock'] = parsed_bluegenelog[0]66            parsed['number'] = parsed_bluegenelog[1]67            parsed['date'] = parsed_bluegenelog[2]68            parsed['core1'] = parsed_bluegenelog[3]69            parsed['timestamp'] = parsed_bluegenelog[4]70            parsed['core2'] = parsed_bluegenelog[5]71            parsed['source'] = parsed_bluegenelog[6]72            parsed['service'] = parsed_bluegenelog[7]73            parsed['info_type'] = parsed_bluegenelog[8]74            parsed['message'] = parsed_bluegenelog[9]75        except ParseException as e:76            print(repr(e))77            print(log_line)78        return parsed    79    @staticmethod80    def __get_spark_grammar():81        ints = Word(nums)82        date = Optional(Combine(ints + '/' + ints + '/' + ints))83        time = Optional(Combine(ints + ":" + ints + ":" + ints))84        status = Optional(Word(string.ascii_uppercase))85        service = Optional(Word(alphas + nums + '/' + '-' + '_' + '.' + '[' + ']' + ':' + '$'))86        message = Regex('.*')87        spark_grammar = date.setResultsName('date') + time.setResultsName('time') + status.setResultsName('status') + \88            service.setResultsName('service') + message.setResultsName('message')89        return spark_grammar90    def parse_spark(self, log_line):91        parsed = dict()92        try:93            parsed_spark = self.spark_grammar.parseString(log_line)94            parsed['date'] = parsed_spark.date95            parsed['time'] = parsed_spark.time96            parsed['status'] = parsed_spark.status97            parsed['service'] = parsed_spark.service98            parsed['message'] = parsed_spark.message99        except ParseException as e:100            print(repr(e))101            print(log_line)102        return parsed103    @staticmethod104    def __get_windows_grammar():105        ints = Word(nums)106        date = Optional(Combine(ints + '-' + ints + '-' + ints))107        time = Optional(Combine(ints + ":" + ints + ":" + ints + ','))108        status = Optional(Word(string.ascii_uppercase + string.ascii_lowercase))109        service = Optional(Word(string.ascii_uppercase))110        message = Regex('.*')111        windows_grammar = date.setResultsName('date') + time.setResultsName('time') + \112            status.setResultsName('status') + service.setResultsName('service') + message.setResultsName('message')113        return windows_grammar114    def parse_windows(self, log_line):115        parsed = dict()116        try:117            parsed_windows = self.windows_grammar.parseString(log_line)118            parsed['date'] = parsed_windows.date119            parsed['time'] = parsed_windows.time120            parsed['status'] = parsed_windows.status121            parsed['service'] = parsed_windows.service122            parsed['message'] = parsed_windows.message123        except ParseException as e:124            print(repr(e))125            print(log_line)126        return parsed127if __name__ == '__main__':128    logtype = sys.argv[1]129    filename = '/home/hudan/Git/pylogsentiment/datasets/' + logtype + '/logs/' + logtype + '.log'130    lg = LogGrammar(logtype)131    index = 0132    with open(filename, 'r', encoding='utf-8-sig', errors='ignore') as f:133        for line in f:134            # get parsed line and print135            parsed_line = None            136            if logtype == 'bgl':137                parsed_line = lg.parse_bluegenelog(line)138            elif logtype == 'spark':139                parsed_line = lg.parse_spark(line)140            elif logtype == 'windows':141                parsed_line = lg.parse_windows(line)142            lg.loading(index)143            index += 1...utils_parser.py
Source:utils_parser.py  
...27        if self.short_tables:28            self.on_short_tables_parse(self.short_tables)29            for short_table in self.short_tables:30                self.on_short_table_parse(short_table)31                self.on_short_table_parsed(short_table)32            self.on_short_tables_parsed(self.short_tables)33        self.on_root_parsed(self.root)34    def _parse_topic(self, topic):35        """Parses a topic.36        """37        self._parse_topic_properties(topic.properties)38        for ps in topic.property_sets:39            self.on_property_set_parse(ps)40            self._parse_topic_properties(ps.properties)41            self.on_property_set_parsed(ps)42        for sp in topic[TYPE_KEY_SUBPROCESS]:43            self.on_subprocess_parse(sp)44            self._parse_topic(sp)45            self.on_subprocess_parsed(sp)46    def _parse_topic_properties(self, properties):47        """Parses a collection of properties associated with either a topic or a property-set.48        """49        for p in properties:50            self.on_property_parse(p)51            if p.enum:52                self.on_enum_parse(p.enum)53                for ec in p.enum.choices:54                    self.on_enum_choice_parse(ec)55                    self.on_enum_choice_parsed(ec)56                self.on_enum_parsed(p.enum)57            self.on_property_parsed(p)58    def on_root_parse(self, root):59        """On root parse event handler.60        """61        pass62    def on_root_parsed(self, root):63        """On root parsed event handler.64        """65        pass66    def on_grid_parse(self, grid):67        """On grid parse event handler.68        """69        pass70    def on_grid_parsed(self, grid):71        """On grid parsed event handler.72        """73        pass74    def on_keyprops_parse(self, key_props):75        """On key-properties parse event handler.76        """77        pass78    def on_keyprops_parsed(self, key_props):79        """On key-properties parsed event handler.80        """81        pass82    def on_process_parse(self, process):83        """On process parse event handler.84        """85        pass86    def on_process_parsed(self, process):87        """On process parsed event handler.88        """89        pass90    def on_subprocess_parse(self, subprocess):91        """On sub-process parse event handler.92        """93        pass94    def on_subprocess_parsed(self, subprocess):95        """On sub-process parsed event handler.96        """97        pass98    def on_property_set_parse(self, prop_set):99        """On property set parse event handler.100        """101        pass102    def on_property_set_parsed(self, prop_set):103        """On property set parsed event handler.104        """105        pass106    def on_property_parse(self, prop):107        """On property parse event handler.108        """109        pass110    def on_property_parsed(self, prop):111        """On property parsed event handler.112        """113        pass114    def on_enum_parse(self, enum):115        """On enum parse event handler.116        """117        pass118    def on_enum_parsed(self, enum):119        """On enum parsed event handler.120        """121        pass122    def on_enum_choice_parse(self, choice):123        """On enum choice parse event handler.124        """125        pass126    def on_enum_choice_parsed(self, choice):127        """On enum choice parsed event handler.128        """129        pass130    def on_short_tables_parse(self, short_tables):131        """On short tables parse event handler.132        """133        pass134    def on_short_tables_parsed(self, short_tables):135        """On short tables parsed event handler.136        """137        pass138    def on_short_table_parse(self, short_table):139        """On short table parse event handler.140        """141        pass142    def on_short_table_parsed(self, short_table):143        """On short table parsed event handler.144        """...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
