We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Duplicate properties on a resource can cause unhandled exceptions
*cfn-lint version: (`cfn-lint --version`)*
0.48.3

*Description of issue.*
Duplicate properties can cause unhandled exceptions

Please provide as much information as possible:
* Template linting issues:
  * Please provide a CloudFormation sample that generated the issue.
  * If present, please add links to the (official) documentation for clarification.
  * Validate if the issue still exists with the latest version of `cfn-lint` and/or the latest Spec files

e.g.
```yaml
  PublicHttpsListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      LoadBalancerArn: !Ref PublicLoadBalancer
      Port: 443
      Protocol: HTTPS
      Certificates: !Ref LoadBalancerCertificateArn
      DefaultActions:
      - Type: fixed-response
        FixedResponseConfig:
          StatusCode: 404
      Port: 443
      Protocol: HTTPS
```
results in:
```bash
Traceback (most recent call last):
  File "/Users/nick.chadwick/Projects/msd/miniconda3/bin/cfn-lint", line 10, in <module>
    sys.exit(main())
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/__main__.py", line 28, in main
    (template, rules, errors) = cfnlint.core.get_template_rules(filename, args)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/core.py", line 187, in get_template_rules
    (template, errors) = cfnlint.decode.decode(filename)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/__init__.py", line 28, in decode
    template = cfn_yaml.load(filename)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 237, in load
    return loads(content, filename)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 215, in loads
    template = loader.get_single_data()
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 51, in get_single_data
    return self.construct_document(node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 55, in construct_document
    data = self.construct_object(node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 100, in construct_object
    data = constructor(self, node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 81, in construct_yaml_map
    value = self.construct_object(value_node, False)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 100, in construct_object
    data = constructor(self, node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 81, in construct_yaml_map
    value = self.construct_object(value_node, False)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 100, in construct_object
    data = constructor(self, node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 81, in construct_yaml_map
    value = self.construct_object(value_node, False)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py", line 100, in construct_object
    data = constructor(self, node)
  File "/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py", line 98, in construct_yaml_map
    key, mapping[key].start_mark.line + 1),
AttributeError: 'int' object has no attribute 'start_mark'
```
* Feature request:
  * Please provide argumentation about the missing feature. Context is key!


Cfn-lint uses the [CloudFormation Resource Specifications](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) as the base to do validation. These files are included as part of the application version. Please update to the latest version of `cfn-lint` or update the spec files manually (`cfn-lint -u`)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cfnlint/decode/cfn_yaml.py`
Content:
```
1 """
2 Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 SPDX-License-Identifier: MIT-0
4 """
5 import fileinput
6 import logging
7 import sys
8 import six
9 from yaml.composer import Composer
10 from yaml.reader import Reader
11 from yaml.scanner import Scanner
12 from yaml.resolver import Resolver
13 from yaml import ScalarNode
14 from yaml import SequenceNode
15 from yaml import MappingNode
16 from yaml.constructor import SafeConstructor
17 from yaml.constructor import ConstructorError
18 import cfnlint
19 from cfnlint.decode.node import str_node, dict_node, list_node
20 
21 try:
22     from yaml.cyaml import CParser as Parser  # pylint: disable=ungrouped-imports
23     cyaml = True
24 except ImportError:
25     from yaml.parser import Parser  # pylint: disable=ungrouped-imports
26     cyaml = False
27 
28 UNCONVERTED_SUFFIXES = ['Ref', 'Condition']
29 FN_PREFIX = 'Fn::'
30 
31 LOGGER = logging.getLogger(__name__)
32 
33 
34 class CfnParseError(ConstructorError):
35     """
36     Error thrown when the template contains Cfn Error
37     """
38 
39     def __init__(self, filename, errors):
40 
41         if isinstance(errors, cfnlint.rules.Match):
42             errors = [errors]
43 
44         # Call the base class constructor with the parameters it needs
45         super(CfnParseError, self).__init__(errors[0].message)
46 
47         # Now for your custom code...
48         self.filename = filename
49         self.matches = errors
50 
51 def build_match(filename, message, line_number, column_number, key):
52     return cfnlint.rules.Match(
53         line_number + 1, column_number + 1, line_number + 1,
54         column_number + 1 + len(key), filename, cfnlint.rules.ParseError(), message=message)
55 
56 class NodeConstructor(SafeConstructor):
57     """
58     Node Constructors for loading different types in Yaml
59     """
60 
61     def __init__(self, filename):
62         # Call the base class constructor
63         super(NodeConstructor, self).__init__()
64 
65         self.filename = filename
66 
67     # To support lazy loading, the original constructors first yield
68     # an empty object, then fill them in when iterated. Due to
69     # laziness we omit this behaviour (and will only do "deep
70     # construction") by first exhausting iterators, then yielding
71     # copies.
72     def construct_yaml_map(self, node):
73 
74         # Check for duplicate keys on the current level, this is not desirable
75         # because a dict does not support this. It overwrites it with the last
76         # occurance, which can give unexpected results
77         mapping = {}
78         self.flatten_mapping(node)
79         for key_node, value_node in node.value:
80             key = self.construct_object(key_node, False)
81             value = self.construct_object(value_node, False)
82 
83             if key in mapping:
84                 raise CfnParseError(
85                     self.filename,
86                     [
87                         build_match(
88                             filename=self.filename,
89                             message='Duplicate resource found "{}" (line {})'.format(
90                                 key, key_node.start_mark.line + 1),
91                             line_number=key_node.start_mark.line,
92                             column_number=key_node.start_mark.column,
93                             key=key
94                         ),
95                         build_match(
96                             filename=self.filename,
97                             message='Duplicate resource found "{}" (line {})'.format(
98                                 key, mapping[key].start_mark.line + 1),
99                             line_number=mapping[key].start_mark.line,
100                             column_number=mapping[key].start_mark.column,
101                             key=key
102                         )
103                     ]
104                 )
105             mapping[key] = value
106 
107         obj, = SafeConstructor.construct_yaml_map(self, node)
108         return dict_node(obj, node.start_mark, node.end_mark)
109 
110     def construct_yaml_str(self, node):
111         obj = SafeConstructor.construct_yaml_str(self, node)
112         assert isinstance(obj, (six.string_types))
113         return str_node(obj, node.start_mark, node.end_mark)
114 
115     def construct_yaml_seq(self, node):
116         obj, = SafeConstructor.construct_yaml_seq(self, node)
117         assert isinstance(obj, list)
118         return list_node(obj, node.start_mark, node.end_mark)
119 
120     def construct_yaml_null_error(self, node):
121         """Throw a null error"""
122         raise CfnParseError(
123             self.filename,
124             [
125                 build_match(
126                     filename=self.filename,
127                     message='Null value at line {0} column {1}'.format(
128                         node.start_mark.line + 1, node.start_mark.column + 1),
129                     line_number=node.start_mark.line,
130                     column_number=node.start_mark.column,
131                     key=' ',
132                 )
133             ]
134         )
135 
136 
137 NodeConstructor.add_constructor(
138     u'tag:yaml.org,2002:map',
139     NodeConstructor.construct_yaml_map)
140 
141 NodeConstructor.add_constructor(
142     u'tag:yaml.org,2002:str',
143     NodeConstructor.construct_yaml_str)
144 
145 NodeConstructor.add_constructor(
146     u'tag:yaml.org,2002:seq',
147     NodeConstructor.construct_yaml_seq)
148 
149 NodeConstructor.add_constructor(
150     u'tag:yaml.org,2002:null',
151     NodeConstructor.construct_yaml_null_error)
152 
153 
154 class MarkedLoader(Reader, Scanner, Parser, Composer, NodeConstructor, Resolver):
155     """
156     Class for marked loading YAML
157     """
158     # pylint: disable=non-parent-init-called,super-init-not-called
159 
160     def __init__(self, stream, filename):
161         Reader.__init__(self, stream)
162         Scanner.__init__(self)
163         if cyaml:
164             Parser.__init__(self, stream)
165         else:
166             Parser.__init__(self)
167         Composer.__init__(self)
168         SafeConstructor.__init__(self)
169         Resolver.__init__(self)
170         NodeConstructor.__init__(self, filename)
171 
172 
173 def multi_constructor(loader, tag_suffix, node):
174     """
175     Deal with !Ref style function format
176     """
177 
178     if tag_suffix not in UNCONVERTED_SUFFIXES:
179         tag_suffix = '{}{}'.format(FN_PREFIX, tag_suffix)
180 
181     constructor = None
182     if tag_suffix == 'Fn::GetAtt':
183         constructor = construct_getatt
184     elif isinstance(node, ScalarNode):
185         constructor = loader.construct_scalar
186     elif isinstance(node, SequenceNode):
187         constructor = loader.construct_sequence
188     elif isinstance(node, MappingNode):
189         constructor = loader.construct_mapping
190     else:
191         raise 'Bad tag: !{}'.format(tag_suffix)
192 
193     return dict_node({tag_suffix: constructor(node)}, node.start_mark, node.end_mark)
194 
195 
196 def construct_getatt(node):
197     """
198     Reconstruct !GetAtt into a list
199     """
200 
201     if isinstance(node.value, (six.string_types)):
202         return list_node(node.value.split('.', 1), node.start_mark, node.end_mark)
203     if isinstance(node.value, list):
204         return list_node([s.value for s in node.value], node.start_mark, node.end_mark)
205 
206     raise ValueError('Unexpected node type: {}'.format(type(node.value)))
207 
208 
209 def loads(yaml_string, fname=None):
210     """
211     Load the given YAML string
212     """
213     loader = MarkedLoader(yaml_string, fname)
214     loader.add_multi_constructor('!', multi_constructor)
215     template = loader.get_single_data()
216     # Convert an empty file to an empty dict
217     if template is None:
218         template = {}
219 
220     return template
221 
222 
223 def load(filename):
224     """
225     Load the given YAML file
226     """
227 
228     content = ''
229 
230     if not sys.stdin.isatty():
231         for line in fileinput.input(files=filename):
232             content = content + line
233     else:
234         with open(filename) as fp:
235             content = fp.read()
236 
237     return loads(content, filename)
238
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/cfnlint/decode/cfn_yaml.py b/src/cfnlint/decode/cfn_yaml.py
--- a/src/cfnlint/decode/cfn_yaml.py
+++ b/src/cfnlint/decode/cfn_yaml.py
@@ -80,28 +80,29 @@
             key = self.construct_object(key_node, False)
             value = self.construct_object(value_node, False)
 
-            if key in mapping:
-                raise CfnParseError(
-                    self.filename,
-                    [
-                        build_match(
-                            filename=self.filename,
-                            message='Duplicate resource found "{}" (line {})'.format(
-                                key, key_node.start_mark.line + 1),
-                            line_number=key_node.start_mark.line,
-                            column_number=key_node.start_mark.column,
-                            key=key
-                        ),
-                        build_match(
-                            filename=self.filename,
-                            message='Duplicate resource found "{}" (line {})'.format(
-                                key, mapping[key].start_mark.line + 1),
-                            line_number=mapping[key].start_mark.line,
-                            column_number=mapping[key].start_mark.column,
-                            key=key
-                        )
-                    ]
-                )
+            for key_dup in mapping:
+                if key_dup == key:
+                    raise CfnParseError(
+                        self.filename,
+                        [
+                            build_match(
+                                filename=self.filename,
+                                message='Duplicate resource found "{}" (line {})'.format(
+                                    key, key_dup.start_mark.line + 1),
+                                line_number=key_dup.start_mark.line,
+                                column_number=key_dup.start_mark.column,
+                                key=key
+                            ),
+                            build_match(
+                                filename=self.filename,
+                                message='Duplicate resource found "{}" (line {})'.format(
+                                    key, key_node.start_mark.line + 1),
+                                line_number=key_node.start_mark.line,
+                                column_number=key_node.start_mark.column,
+                                key=key
+                            ),
+                        ]
+                    )
             mapping[key] = value
 
         obj, = SafeConstructor.construct_yaml_map(self, node)

{"golden_diff": "diff --git a/src/cfnlint/decode/cfn_yaml.py b/src/cfnlint/decode/cfn_yaml.py\n--- a/src/cfnlint/decode/cfn_yaml.py\n+++ b/src/cfnlint/decode/cfn_yaml.py\n@@ -80,28 +80,29 @@\n             key = self.construct_object(key_node, False)\n             value = self.construct_object(value_node, False)\n \n-            if key in mapping:\n-                raise CfnParseError(\n-                    self.filename,\n-                    [\n-                        build_match(\n-                            filename=self.filename,\n-                            message='Duplicate resource found \"{}\" (line {})'.format(\n-                                key, key_node.start_mark.line + 1),\n-                            line_number=key_node.start_mark.line,\n-                            column_number=key_node.start_mark.column,\n-                            key=key\n-                        ),\n-                        build_match(\n-                            filename=self.filename,\n-                            message='Duplicate resource found \"{}\" (line {})'.format(\n-                                key, mapping[key].start_mark.line + 1),\n-                            line_number=mapping[key].start_mark.line,\n-                            column_number=mapping[key].start_mark.column,\n-                            key=key\n-                        )\n-                    ]\n-                )\n+            for key_dup in mapping:\n+                if key_dup == key:\n+                    raise CfnParseError(\n+                        self.filename,\n+                        [\n+                            build_match(\n+                                filename=self.filename,\n+                                message='Duplicate resource found \"{}\" (line {})'.format(\n+                                    key, key_dup.start_mark.line + 1),\n+                                line_number=key_dup.start_mark.line,\n+                                column_number=key_dup.start_mark.column,\n+                                key=key\n+                            ),\n+                            build_match(\n+                                filename=self.filename,\n+                                message='Duplicate resource found \"{}\" (line {})'.format(\n+                                    key, key_node.start_mark.line + 1),\n+                                line_number=key_node.start_mark.line,\n+                                column_number=key_node.start_mark.column,\n+                                key=key\n+                            ),\n+                        ]\n+                    )\n             mapping[key] = value\n \n         obj, = SafeConstructor.construct_yaml_map(self, node)\n", "issue": "Duplicate properties on a resource can cause unhandled exceptions\n*cfn-lint version: (`cfn-lint --version`)*\r\n0.48.3\r\n\r\n*Description of issue.*\r\nDuplicate properties can cause unhandled exceptions\r\n\r\nPlease provide as much information as possible:\r\n* Template linting issues:\r\n  * Please provide a CloudFormation sample that generated the issue.\r\n  * If present, please add links to the (official) documentation for clarification.\r\n  * Validate if the issue still exists with the latest version of `cfn-lint` and/or the latest Spec files\r\n\r\ne.g.\r\n```yaml\r\n  PublicHttpsListener:\r\n    Type: 'AWS::ElasticLoadBalancingV2::Listener'\r\n    Properties:\r\n      LoadBalancerArn: !Ref PublicLoadBalancer\r\n      Port: 443\r\n      Protocol: HTTPS\r\n      Certificates: !Ref LoadBalancerCertificateArn\r\n      DefaultActions:\r\n      - Type: fixed-response\r\n        FixedResponseConfig:\r\n          StatusCode: 404\r\n      Port: 443\r\n      Protocol: HTTPS\r\n```\r\nresults in:\r\n```bash\r\nTraceback (most recent call last):\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/bin/cfn-lint\", line 10, in <module>\r\n    sys.exit(main())\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/__main__.py\", line 28, in main\r\n    (template, rules, errors) = cfnlint.core.get_template_rules(filename, args)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/core.py\", line 187, in get_template_rules\r\n    (template, errors) = cfnlint.decode.decode(filename)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/__init__.py\", line 28, in decode\r\n    template = cfn_yaml.load(filename)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 237, in load\r\n    return loads(content, filename)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 215, in loads\r\n    template = loader.get_single_data()\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 51, in get_single_data\r\n    return self.construct_document(node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 55, in construct_document\r\n    data = self.construct_object(node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 100, in construct_object\r\n    data = constructor(self, node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 81, in construct_yaml_map\r\n    value = self.construct_object(value_node, False)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 100, in construct_object\r\n    data = constructor(self, node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 81, in construct_yaml_map\r\n    value = self.construct_object(value_node, False)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 100, in construct_object\r\n    data = constructor(self, node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 81, in construct_yaml_map\r\n    value = self.construct_object(value_node, False)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/yaml/constructor.py\", line 100, in construct_object\r\n    data = constructor(self, node)\r\n  File \"/Users/nick.chadwick/Projects/msd/miniconda3/lib/python3.7/site-packages/cfnlint/decode/cfn_yaml.py\", line 98, in construct_yaml_map\r\n    key, mapping[key].start_mark.line + 1),\r\nAttributeError: 'int' object has no attribute 'start_mark'\r\n```\r\n* Feature request:\r\n  * Please provide argumentation about the missing feature. Context is key!\r\n\r\n\r\nCfn-lint uses the [CloudFormation Resource Specifications](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) as the base to do validation. These files are included as part of the application version. Please update to the latest version of `cfn-lint` or update the spec files manually (`cfn-lint -u`)\r\n\n", "before_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport fileinput\nimport logging\nimport sys\nimport six\nfrom yaml.composer import Composer\nfrom yaml.reader import Reader\nfrom yaml.scanner import Scanner\nfrom yaml.resolver import Resolver\nfrom yaml import ScalarNode\nfrom yaml import SequenceNode\nfrom yaml import MappingNode\nfrom yaml.constructor import SafeConstructor\nfrom yaml.constructor import ConstructorError\nimport cfnlint\nfrom cfnlint.decode.node import str_node, dict_node, list_node\n\ntry:\n    from yaml.cyaml import CParser as Parser  # pylint: disable=ungrouped-imports\n    cyaml = True\nexcept ImportError:\n    from yaml.parser import Parser  # pylint: disable=ungrouped-imports\n    cyaml = False\n\nUNCONVERTED_SUFFIXES = ['Ref', 'Condition']\nFN_PREFIX = 'Fn::'\n\nLOGGER = logging.getLogger(__name__)\n\n\nclass CfnParseError(ConstructorError):\n    \"\"\"\n    Error thrown when the template contains Cfn Error\n    \"\"\"\n\n    def __init__(self, filename, errors):\n\n        if isinstance(errors, cfnlint.rules.Match):\n            errors = [errors]\n\n        # Call the base class constructor with the parameters it needs\n        super(CfnParseError, self).__init__(errors[0].message)\n\n        # Now for your custom code...\n        self.filename = filename\n        self.matches = errors\n\ndef build_match(filename, message, line_number, column_number, key):\n    return cfnlint.rules.Match(\n        line_number + 1, column_number + 1, line_number + 1,\n        column_number + 1 + len(key), filename, cfnlint.rules.ParseError(), message=message)\n\nclass NodeConstructor(SafeConstructor):\n    \"\"\"\n    Node Constructors for loading different types in Yaml\n    \"\"\"\n\n    def __init__(self, filename):\n        # Call the base class constructor\n        super(NodeConstructor, self).__init__()\n\n        self.filename = filename\n\n    # To support lazy loading, the original constructors first yield\n    # an empty object, then fill them in when iterated. Due to\n    # laziness we omit this behaviour (and will only do \"deep\n    # construction\") by first exhausting iterators, then yielding\n    # copies.\n    def construct_yaml_map(self, node):\n\n        # Check for duplicate keys on the current level, this is not desirable\n        # because a dict does not support this. It overwrites it with the last\n        # occurance, which can give unexpected results\n        mapping = {}\n        self.flatten_mapping(node)\n        for key_node, value_node in node.value:\n            key = self.construct_object(key_node, False)\n            value = self.construct_object(value_node, False)\n\n            if key in mapping:\n                raise CfnParseError(\n                    self.filename,\n                    [\n                        build_match(\n                            filename=self.filename,\n                            message='Duplicate resource found \"{}\" (line {})'.format(\n                                key, key_node.start_mark.line + 1),\n                            line_number=key_node.start_mark.line,\n                            column_number=key_node.start_mark.column,\n                            key=key\n                        ),\n                        build_match(\n                            filename=self.filename,\n                            message='Duplicate resource found \"{}\" (line {})'.format(\n                                key, mapping[key].start_mark.line + 1),\n                            line_number=mapping[key].start_mark.line,\n                            column_number=mapping[key].start_mark.column,\n                            key=key\n                        )\n                    ]\n                )\n            mapping[key] = value\n\n        obj, = SafeConstructor.construct_yaml_map(self, node)\n        return dict_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_str(self, node):\n        obj = SafeConstructor.construct_yaml_str(self, node)\n        assert isinstance(obj, (six.string_types))\n        return str_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_seq(self, node):\n        obj, = SafeConstructor.construct_yaml_seq(self, node)\n        assert isinstance(obj, list)\n        return list_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_null_error(self, node):\n        \"\"\"Throw a null error\"\"\"\n        raise CfnParseError(\n            self.filename,\n            [\n                build_match(\n                    filename=self.filename,\n                    message='Null value at line {0} column {1}'.format(\n                        node.start_mark.line + 1, node.start_mark.column + 1),\n                    line_number=node.start_mark.line,\n                    column_number=node.start_mark.column,\n                    key=' ',\n                )\n            ]\n        )\n\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:map',\n    NodeConstructor.construct_yaml_map)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:str',\n    NodeConstructor.construct_yaml_str)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:seq',\n    NodeConstructor.construct_yaml_seq)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:null',\n    NodeConstructor.construct_yaml_null_error)\n\n\nclass MarkedLoader(Reader, Scanner, Parser, Composer, NodeConstructor, Resolver):\n    \"\"\"\n    Class for marked loading YAML\n    \"\"\"\n    # pylint: disable=non-parent-init-called,super-init-not-called\n\n    def __init__(self, stream, filename):\n        Reader.__init__(self, stream)\n        Scanner.__init__(self)\n        if cyaml:\n            Parser.__init__(self, stream)\n        else:\n            Parser.__init__(self)\n        Composer.__init__(self)\n        SafeConstructor.__init__(self)\n        Resolver.__init__(self)\n        NodeConstructor.__init__(self, filename)\n\n\ndef multi_constructor(loader, tag_suffix, node):\n    \"\"\"\n    Deal with !Ref style function format\n    \"\"\"\n\n    if tag_suffix not in UNCONVERTED_SUFFIXES:\n        tag_suffix = '{}{}'.format(FN_PREFIX, tag_suffix)\n\n    constructor = None\n    if tag_suffix == 'Fn::GetAtt':\n        constructor = construct_getatt\n    elif isinstance(node, ScalarNode):\n        constructor = loader.construct_scalar\n    elif isinstance(node, SequenceNode):\n        constructor = loader.construct_sequence\n    elif isinstance(node, MappingNode):\n        constructor = loader.construct_mapping\n    else:\n        raise 'Bad tag: !{}'.format(tag_suffix)\n\n    return dict_node({tag_suffix: constructor(node)}, node.start_mark, node.end_mark)\n\n\ndef construct_getatt(node):\n    \"\"\"\n    Reconstruct !GetAtt into a list\n    \"\"\"\n\n    if isinstance(node.value, (six.string_types)):\n        return list_node(node.value.split('.', 1), node.start_mark, node.end_mark)\n    if isinstance(node.value, list):\n        return list_node([s.value for s in node.value], node.start_mark, node.end_mark)\n\n    raise ValueError('Unexpected node type: {}'.format(type(node.value)))\n\n\ndef loads(yaml_string, fname=None):\n    \"\"\"\n    Load the given YAML string\n    \"\"\"\n    loader = MarkedLoader(yaml_string, fname)\n    loader.add_multi_constructor('!', multi_constructor)\n    template = loader.get_single_data()\n    # Convert an empty file to an empty dict\n    if template is None:\n        template = {}\n\n    return template\n\n\ndef load(filename):\n    \"\"\"\n    Load the given YAML file\n    \"\"\"\n\n    content = ''\n\n    if not sys.stdin.isatty():\n        for line in fileinput.input(files=filename):\n            content = content + line\n    else:\n        with open(filename) as fp:\n            content = fp.read()\n\n    return loads(content, filename)\n", "path": "src/cfnlint/decode/cfn_yaml.py"}], "after_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport fileinput\nimport logging\nimport sys\nimport six\nfrom yaml.composer import Composer\nfrom yaml.reader import Reader\nfrom yaml.scanner import Scanner\nfrom yaml.resolver import Resolver\nfrom yaml import ScalarNode\nfrom yaml import SequenceNode\nfrom yaml import MappingNode\nfrom yaml.constructor import SafeConstructor\nfrom yaml.constructor import ConstructorError\nimport cfnlint\nfrom cfnlint.decode.node import str_node, dict_node, list_node\n\ntry:\n    from yaml.cyaml import CParser as Parser  # pylint: disable=ungrouped-imports\n    cyaml = True\nexcept ImportError:\n    from yaml.parser import Parser  # pylint: disable=ungrouped-imports\n    cyaml = False\n\nUNCONVERTED_SUFFIXES = ['Ref', 'Condition']\nFN_PREFIX = 'Fn::'\n\nLOGGER = logging.getLogger(__name__)\n\n\nclass CfnParseError(ConstructorError):\n    \"\"\"\n    Error thrown when the template contains Cfn Error\n    \"\"\"\n\n    def __init__(self, filename, errors):\n\n        if isinstance(errors, cfnlint.rules.Match):\n            errors = [errors]\n\n        # Call the base class constructor with the parameters it needs\n        super(CfnParseError, self).__init__(errors[0].message)\n\n        # Now for your custom code...\n        self.filename = filename\n        self.matches = errors\n\ndef build_match(filename, message, line_number, column_number, key):\n    return cfnlint.rules.Match(\n        line_number + 1, column_number + 1, line_number + 1,\n        column_number + 1 + len(key), filename, cfnlint.rules.ParseError(), message=message)\n\nclass NodeConstructor(SafeConstructor):\n    \"\"\"\n    Node Constructors for loading different types in Yaml\n    \"\"\"\n\n    def __init__(self, filename):\n        # Call the base class constructor\n        super(NodeConstructor, self).__init__()\n\n        self.filename = filename\n\n    # To support lazy loading, the original constructors first yield\n    # an empty object, then fill them in when iterated. Due to\n    # laziness we omit this behaviour (and will only do \"deep\n    # construction\") by first exhausting iterators, then yielding\n    # copies.\n    def construct_yaml_map(self, node):\n\n        # Check for duplicate keys on the current level, this is not desirable\n        # because a dict does not support this. It overwrites it with the last\n        # occurance, which can give unexpected results\n        mapping = {}\n        self.flatten_mapping(node)\n        for key_node, value_node in node.value:\n            key = self.construct_object(key_node, False)\n            value = self.construct_object(value_node, False)\n\n            for key_dup in mapping:\n                if key_dup == key:\n                    raise CfnParseError(\n                        self.filename,\n                        [\n                            build_match(\n                                filename=self.filename,\n                                message='Duplicate resource found \"{}\" (line {})'.format(\n                                    key, key_dup.start_mark.line + 1),\n                                line_number=key_dup.start_mark.line,\n                                column_number=key_dup.start_mark.column,\n                                key=key\n                            ),\n                            build_match(\n                                filename=self.filename,\n                                message='Duplicate resource found \"{}\" (line {})'.format(\n                                    key, key_node.start_mark.line + 1),\n                                line_number=key_node.start_mark.line,\n                                column_number=key_node.start_mark.column,\n                                key=key\n                            ),\n                        ]\n                    )\n            mapping[key] = value\n\n        obj, = SafeConstructor.construct_yaml_map(self, node)\n        return dict_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_str(self, node):\n        obj = SafeConstructor.construct_yaml_str(self, node)\n        assert isinstance(obj, (six.string_types))\n        return str_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_seq(self, node):\n        obj, = SafeConstructor.construct_yaml_seq(self, node)\n        assert isinstance(obj, list)\n        return list_node(obj, node.start_mark, node.end_mark)\n\n    def construct_yaml_null_error(self, node):\n        \"\"\"Throw a null error\"\"\"\n        raise CfnParseError(\n            self.filename,\n            [\n                build_match(\n                    filename=self.filename,\n                    message='Null value at line {0} column {1}'.format(\n                        node.start_mark.line + 1, node.start_mark.column + 1),\n                    line_number=node.start_mark.line,\n                    column_number=node.start_mark.column,\n                    key=' ',\n                )\n            ]\n        )\n\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:map',\n    NodeConstructor.construct_yaml_map)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:str',\n    NodeConstructor.construct_yaml_str)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:seq',\n    NodeConstructor.construct_yaml_seq)\n\nNodeConstructor.add_constructor(\n    u'tag:yaml.org,2002:null',\n    NodeConstructor.construct_yaml_null_error)\n\n\nclass MarkedLoader(Reader, Scanner, Parser, Composer, NodeConstructor, Resolver):\n    \"\"\"\n    Class for marked loading YAML\n    \"\"\"\n    # pylint: disable=non-parent-init-called,super-init-not-called\n\n    def __init__(self, stream, filename):\n        Reader.__init__(self, stream)\n        Scanner.__init__(self)\n        if cyaml:\n            Parser.__init__(self, stream)\n        else:\n            Parser.__init__(self)\n        Composer.__init__(self)\n        SafeConstructor.__init__(self)\n        Resolver.__init__(self)\n        NodeConstructor.__init__(self, filename)\n\n\ndef multi_constructor(loader, tag_suffix, node):\n    \"\"\"\n    Deal with !Ref style function format\n    \"\"\"\n\n    if tag_suffix not in UNCONVERTED_SUFFIXES:\n        tag_suffix = '{}{}'.format(FN_PREFIX, tag_suffix)\n\n    constructor = None\n    if tag_suffix == 'Fn::GetAtt':\n        constructor = construct_getatt\n    elif isinstance(node, ScalarNode):\n        constructor = loader.construct_scalar\n    elif isinstance(node, SequenceNode):\n        constructor = loader.construct_sequence\n    elif isinstance(node, MappingNode):\n        constructor = loader.construct_mapping\n    else:\n        raise 'Bad tag: !{}'.format(tag_suffix)\n\n    return dict_node({tag_suffix: constructor(node)}, node.start_mark, node.end_mark)\n\n\ndef construct_getatt(node):\n    \"\"\"\n    Reconstruct !GetAtt into a list\n    \"\"\"\n\n    if isinstance(node.value, (six.string_types)):\n        return list_node(node.value.split('.', 1), node.start_mark, node.end_mark)\n    if isinstance(node.value, list):\n        return list_node([s.value for s in node.value], node.start_mark, node.end_mark)\n\n    raise ValueError('Unexpected node type: {}'.format(type(node.value)))\n\n\ndef loads(yaml_string, fname=None):\n    \"\"\"\n    Load the given YAML string\n    \"\"\"\n    loader = MarkedLoader(yaml_string, fname)\n    loader.add_multi_constructor('!', multi_constructor)\n    template = loader.get_single_data()\n    # Convert an empty file to an empty dict\n    if template is None:\n        template = {}\n\n    return template\n\n\ndef load(filename):\n    \"\"\"\n    Load the given YAML file\n    \"\"\"\n\n    content = ''\n\n    if not sys.stdin.isatty():\n        for line in fileinput.input(files=filename):\n            content = content + line\n    else:\n        with open(filename) as fp:\n            content = fp.read()\n\n    return loads(content, filename)\n", "path": "src/cfnlint/decode/cfn_yaml.py"}]}