We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
E2507 error when using using policy statements for serverless functions
*cfn-lint version: 0.8.2* (and doesn't happen with earlier versions)

The template below produces the following error when processing it with `cfn-lint`:
```
E0002 Unknown exception while processing rule E2507: 'str' object has no attribute 'start_mark'
function_with_policy_templates.yaml:1:1
````

```yaml
AWSTemplateFormatVersion: '2010-09-09'

Transform: 'AWS::Serverless-2016-10-31'

Resources:
  Test:
    Type: 'AWS::Serverless::Function'
    Properties:
      CodeUri: ./
      Handler: hello.handler
      Runtime: python3.6
      Policies:
        - Statement:
          - Action: [ 'dynamodb:*' ]
            Effect: Allow
            Resource: '*'
```

That issue goes away when removing the `Transform: 'AWS::Serverless-2016-10-31'`, but that's of course no fix, as that would prevent transformation of the `AWS::Serverless::Function`.

--- 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/helpers.py`
Content:
```
1 """
2   Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy of this
5   software and associated documentation files (the "Software"), to deal in the Software
6   without restriction, including without limitation the rights to use, copy, modify,
7   merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8   permit persons to whom the Software is furnished to do so.
9 
10   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 """
17 import sys
18 import fnmatch
19 import json
20 import os
21 import imp
22 import logging
23 import re
24 import inspect
25 import pkg_resources
26 from cfnlint.decode.node import dict_node, list_node
27 
28 LOGGER = logging.getLogger(__name__)
29 
30 TAG_MAP = 'tag:yaml.org,2002:map'
31 UNCONVERTED_SUFFIXES = ['Ref', 'Condition']
32 FN_PREFIX = 'Fn::'
33 CONDITION_FUNCTIONS = ['Fn::If']
34 REGIONS = ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'ca-central-1',
35            'eu-central-1', 'eu-west-1', 'eu-west-2', 'ap-northeast-1',
36            'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1',
37            'sa-east-1']
38 
39 REGEX_ALPHANUMERIC = re.compile('^[a-zA-Z0-9]*$')
40 REGEX_CIDR = re.compile(r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$')
41 REGEX_IPV4 = re.compile(r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')
42 REGEX_IPV6 = re.compile(r'^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\Z', re.I | re.S)
43 REGEX_DYN_REF = re.compile(r'^.*{{resolve:.+}}.*$')
44 REGEX_DYN_REF_SSM = re.compile(r'^.*{{resolve:ssm:[a-zA-Z0-9_\.\-/]+:\d+}}.*$')
45 REGEX_DYN_REF_SSM_SECURE = re.compile(r'^.*{{resolve:ssm-secure:[a-zA-Z0-9_\.\-/]+:\d+}}.*$')
46 
47 
48 AVAILABILITY_ZONES = [
49     'us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d', 'us-east-1e', 'us-east-1f',
50     'us-east-2a' 'us-east-2b' 'us-east-2c',
51     'us-west-1a', 'us-west-1b', 'us-west-1c',
52     'us-west-2a', 'us-west-2b', 'us-west-2c',
53     'ca-central-1a', 'ca-central-1b',
54     'sa-east-1a', 'sa-east-1b', 'sa-east-1c',
55     'eu-west-1a', 'eu-west-1b', 'eu-west-1c',
56     'eu-west-2a', 'eu-west-2b', 'eu-west-2c',
57     'eu-west-3a', 'eu-west-3b', 'eu-west-3c',
58     'eu-central-1a', 'eu-central-1b', 'eu-central-1c',
59     'eu-central-2a', 'eu-central-2b', 'eu-central-2c',
60     'ap-northeast-1a', 'ap-northeast-1b', 'ap-northeast-1c', 'ap-northeast-1d',
61     'ap-northeast-2a', 'ap-northeast-2b',
62     'ap-northeast-3a',
63     'ap-southeast-1a', 'ap-southeast-1b', 'ap-southeast-1c',
64     'ap-southeast-2a', 'ap-southeast-2b', 'ap-southeast-2c',
65     'ap-south-1a', 'ap-south-1b',
66     'cn-north-1a', 'cn-north-1b',
67 ]
68 
69 FUNCTIONS = [
70     'Fn::Base64', 'Fn::GetAtt', 'Fn::GetAZs', 'Fn::ImportValue',
71     'Fn::Join', 'Fn::Split', 'Fn::FindInMap', 'Fn::Select', 'Ref',
72     'Fn::If', 'Fn::Contains', 'Fn::Sub', 'Fn::Cidr']
73 
74 LIMITS = {
75     'mappings': {
76         'number': 100,
77         'attributes': 64,
78         'name': 255  # in characters
79     },
80     'outputs': {
81         'number': 60,
82         'name': 255,  # in characters
83         'description': 1024  # in bytes
84     },
85     'parameters': {
86         'number': 60,
87         'name': 255,  # in characters
88         'value': 4096  # in bytes
89     },
90     'resources': {
91         'number': 200,
92         'name': 255  # in characters
93     },
94     'template': {
95         'body': 460800,  # in bytes
96         'description': 1024  # in bytes
97     }
98 }
99 
100 
101 def load_resources(filename='/data/CloudSpecs/us-east-1.json'):
102     """Load resources"""
103 
104     filename = pkg_resources.resource_filename(
105         __name__,
106         filename
107     )
108 
109     with open(filename) as fp:
110         return json.load(fp)
111 
112 
113 RESOURCE_SPECS = {}
114 
115 
116 def merge_spec(source, destination):
117     """ Recursive merge spec dict """
118 
119     for key, value in source.items():
120         if isinstance(value, dict):
121             node = destination.setdefault(key, {})
122             merge_spec(value, node)
123         else:
124             destination[key] = value
125 
126     return destination
127 
128 
129 def set_specs(override_spec_data):
130     """ Override Resource Specs """
131 
132     excludes = []
133     includes = []
134 
135     # Extract the exclude list from the override file
136     if 'ExcludeResourceTypes' in override_spec_data:
137         excludes = override_spec_data.pop('ExcludeResourceTypes')
138     if 'IncludeResourceTypes' in override_spec_data:
139         includes = override_spec_data.pop('IncludeResourceTypes')
140 
141     for region, spec in RESOURCE_SPECS.items():
142 
143         # Merge override spec file into the AWS Resource specification
144         if override_spec_data:
145             RESOURCE_SPECS[region] = merge_spec(override_spec_data, spec)
146 
147         # Grab a list of all resources
148         all_resources = list(RESOURCE_SPECS[region]['ResourceTypes'].keys())[:]
149 
150         resources = []
151 
152         # Remove unsupported resource using includes
153         if includes:
154             for include in includes:
155                 regex = re.compile(include.replace('*', '(.*)') + '$')
156                 matches = [string for string in all_resources if re.match(regex, string)]
157 
158                 resources.extend(matches)
159         else:
160             resources = all_resources[:]
161 
162         # Remove unsupported resources using the excludes
163         if excludes:
164             for exclude in excludes:
165                 regex = re.compile(exclude.replace('*', '(.*)') + '$')
166                 matches = [string for string in resources if re.match(regex, string)]
167 
168                 for match in matches:
169                     resources.remove(match)
170 
171         # Remove unsupported resources
172         for resource in all_resources:
173             if resource not in resources:
174                 del RESOURCE_SPECS[region]['ResourceTypes'][resource]
175 
176 
177 def initialize_specs():
178     """ Reload Resource Specs """
179     for reg in REGIONS:
180         RESOURCE_SPECS[reg] = load_resources(filename=('/data/CloudSpecs/%s.json' % reg))
181 
182 
183 initialize_specs()
184 
185 
186 def load_plugins(directory):
187     """Load plugins"""
188     result = []
189     fh = None
190 
191     def onerror(os_error):
192         """Raise an error"""
193         raise os_error
194 
195     for root, _, filenames in os.walk(directory, onerror=onerror):
196         for filename in fnmatch.filter(filenames, '[A-Za-z]*.py'):
197             pluginname = filename.replace('.py', '')
198             try:
199                 fh, filename, desc = imp.find_module(pluginname, [root])
200                 mod = imp.load_module(pluginname, fh, filename, desc)
201                 for _, clazz in inspect.getmembers(mod, inspect.isclass):
202                     method_resolution = inspect.getmro(clazz)
203                     if [clz for clz in method_resolution[1:] if clz.__module__ == 'cfnlint' and clz.__name__ == 'CloudFormationLintRule']:
204                         # create and instance of subclasses of CloudFormationLintRule
205                         obj = clazz()
206                         result.append(obj)
207             finally:
208                 if fh:
209                     fh.close()
210 
211     return result
212 
213 
214 def convert_dict(template, start_mark=(0, 0), end_mark=(0, 0)):
215     """Convert dict to template"""
216     if isinstance(template, dict):
217         if not isinstance(template, dict_node):
218             template = dict_node(template, start_mark, end_mark)
219         for k, v in template.items():
220             template[k] = convert_dict(v)
221     elif isinstance(template, list):
222         if not isinstance(template, list_node):
223             template = list_node(template, start_mark, end_mark)
224         for i, v in enumerate(template):
225             template[i] = convert_dict(v)
226 
227     return template
228 
229 
230 def override_specs(override_spec_file):
231     """Override specs file"""
232     try:
233         filename = override_spec_file
234         with open(filename) as fp:
235             custom_spec_data = json.load(fp)
236 
237         set_specs(custom_spec_data)
238     except IOError as e:
239         if e.errno == 2:
240             LOGGER.error('Override spec file not found: %s', filename)
241             sys.exit(1)
242         elif e.errno == 21:
243             LOGGER.error('Override spec file references a directory, not a file: %s', filename)
244             sys.exit(1)
245         elif e.errno == 13:
246             LOGGER.error('Permission denied when accessing override spec file: %s', filename)
247             sys.exit(1)
248     except (ValueError) as err:
249         LOGGER.error('Override spec file %s is malformed: %s', filename, err)
250         sys.exit(1)
251
```
--- 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/helpers.py b/src/cfnlint/helpers.py
--- a/src/cfnlint/helpers.py
+++ b/src/cfnlint/helpers.py
@@ -23,7 +23,7 @@
 import re
 import inspect
 import pkg_resources
-from cfnlint.decode.node import dict_node, list_node
+from cfnlint.decode.node import dict_node, list_node, str_node
 
 LOGGER = logging.getLogger(__name__)
 
@@ -216,13 +216,20 @@
     if isinstance(template, dict):
         if not isinstance(template, dict_node):
             template = dict_node(template, start_mark, end_mark)
-        for k, v in template.items():
-            template[k] = convert_dict(v)
+        for k, v in template.copy().items():
+            k_start_mark = start_mark
+            k_end_mark = end_mark
+            if isinstance(k, str_node):
+                k_start_mark = k.start_mark
+                k_end_mark = k.end_mark
+            new_k = str_node(k, k_start_mark, k_end_mark)
+            del template[k]
+            template[new_k] = convert_dict(v, k_start_mark, k_end_mark)
     elif isinstance(template, list):
         if not isinstance(template, list_node):
             template = list_node(template, start_mark, end_mark)
         for i, v in enumerate(template):
-            template[i] = convert_dict(v)
+            template[i] = convert_dict(v, start_mark, end_mark)
 
     return template

{"golden_diff": "diff --git a/src/cfnlint/helpers.py b/src/cfnlint/helpers.py\n--- a/src/cfnlint/helpers.py\n+++ b/src/cfnlint/helpers.py\n@@ -23,7 +23,7 @@\n import re\n import inspect\n import pkg_resources\n-from cfnlint.decode.node import dict_node, list_node\n+from cfnlint.decode.node import dict_node, list_node, str_node\n \n LOGGER = logging.getLogger(__name__)\n \n@@ -216,13 +216,20 @@\n     if isinstance(template, dict):\n         if not isinstance(template, dict_node):\n             template = dict_node(template, start_mark, end_mark)\n-        for k, v in template.items():\n-            template[k] = convert_dict(v)\n+        for k, v in template.copy().items():\n+            k_start_mark = start_mark\n+            k_end_mark = end_mark\n+            if isinstance(k, str_node):\n+                k_start_mark = k.start_mark\n+                k_end_mark = k.end_mark\n+            new_k = str_node(k, k_start_mark, k_end_mark)\n+            del template[k]\n+            template[new_k] = convert_dict(v, k_start_mark, k_end_mark)\n     elif isinstance(template, list):\n         if not isinstance(template, list_node):\n             template = list_node(template, start_mark, end_mark)\n         for i, v in enumerate(template):\n-            template[i] = convert_dict(v)\n+            template[i] = convert_dict(v, start_mark, end_mark)\n \n     return template\n", "issue": "E2507 error when using using policy statements for serverless functions\n*cfn-lint version: 0.8.2* (and doesn't happen with earlier versions)\r\n\r\nThe template below produces the following error when processing it with `cfn-lint`:\r\n```\r\nE0002 Unknown exception while processing rule E2507: 'str' object has no attribute 'start_mark'\r\nfunction_with_policy_templates.yaml:1:1\r\n````\r\n\r\n```yaml\r\nAWSTemplateFormatVersion: '2010-09-09'\r\n\r\nTransform: 'AWS::Serverless-2016-10-31'\r\n\r\nResources:\r\n  Test:\r\n    Type: 'AWS::Serverless::Function'\r\n    Properties:\r\n      CodeUri: ./\r\n      Handler: hello.handler\r\n      Runtime: python3.6\r\n      Policies:\r\n        - Statement:\r\n          - Action: [ 'dynamodb:*' ]\r\n            Effect: Allow\r\n            Resource: '*'\r\n```\r\n\r\nThat issue goes away when removing the `Transform: 'AWS::Serverless-2016-10-31'`, but that's of course no fix, as that would prevent transformation of the `AWS::Serverless::Function`.\n", "before_files": [{"content": "\"\"\"\n  Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nimport sys\nimport fnmatch\nimport json\nimport os\nimport imp\nimport logging\nimport re\nimport inspect\nimport pkg_resources\nfrom cfnlint.decode.node import dict_node, list_node\n\nLOGGER = logging.getLogger(__name__)\n\nTAG_MAP = 'tag:yaml.org,2002:map'\nUNCONVERTED_SUFFIXES = ['Ref', 'Condition']\nFN_PREFIX = 'Fn::'\nCONDITION_FUNCTIONS = ['Fn::If']\nREGIONS = ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'ca-central-1',\n           'eu-central-1', 'eu-west-1', 'eu-west-2', 'ap-northeast-1',\n           'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1',\n           'sa-east-1']\n\nREGEX_ALPHANUMERIC = re.compile('^[a-zA-Z0-9]*$')\nREGEX_CIDR = re.compile(r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$')\nREGEX_IPV4 = re.compile(r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')\nREGEX_IPV6 = re.compile(r'^(((?=.*(::))(?!.*\\3.+\\3))\\3?|[\\dA-F]{1,4}:)([\\dA-F]{1,4}(\\3|:\\b)|\\2){5}(([\\dA-F]{1,4}(\\3|:\\b|$)|\\2){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})\\Z', re.I | re.S)\nREGEX_DYN_REF = re.compile(r'^.*{{resolve:.+}}.*$')\nREGEX_DYN_REF_SSM = re.compile(r'^.*{{resolve:ssm:[a-zA-Z0-9_\\.\\-/]+:\\d+}}.*$')\nREGEX_DYN_REF_SSM_SECURE = re.compile(r'^.*{{resolve:ssm-secure:[a-zA-Z0-9_\\.\\-/]+:\\d+}}.*$')\n\n\nAVAILABILITY_ZONES = [\n    'us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d', 'us-east-1e', 'us-east-1f',\n    'us-east-2a' 'us-east-2b' 'us-east-2c',\n    'us-west-1a', 'us-west-1b', 'us-west-1c',\n    'us-west-2a', 'us-west-2b', 'us-west-2c',\n    'ca-central-1a', 'ca-central-1b',\n    'sa-east-1a', 'sa-east-1b', 'sa-east-1c',\n    'eu-west-1a', 'eu-west-1b', 'eu-west-1c',\n    'eu-west-2a', 'eu-west-2b', 'eu-west-2c',\n    'eu-west-3a', 'eu-west-3b', 'eu-west-3c',\n    'eu-central-1a', 'eu-central-1b', 'eu-central-1c',\n    'eu-central-2a', 'eu-central-2b', 'eu-central-2c',\n    'ap-northeast-1a', 'ap-northeast-1b', 'ap-northeast-1c', 'ap-northeast-1d',\n    'ap-northeast-2a', 'ap-northeast-2b',\n    'ap-northeast-3a',\n    'ap-southeast-1a', 'ap-southeast-1b', 'ap-southeast-1c',\n    'ap-southeast-2a', 'ap-southeast-2b', 'ap-southeast-2c',\n    'ap-south-1a', 'ap-south-1b',\n    'cn-north-1a', 'cn-north-1b',\n]\n\nFUNCTIONS = [\n    'Fn::Base64', 'Fn::GetAtt', 'Fn::GetAZs', 'Fn::ImportValue',\n    'Fn::Join', 'Fn::Split', 'Fn::FindInMap', 'Fn::Select', 'Ref',\n    'Fn::If', 'Fn::Contains', 'Fn::Sub', 'Fn::Cidr']\n\nLIMITS = {\n    'mappings': {\n        'number': 100,\n        'attributes': 64,\n        'name': 255  # in characters\n    },\n    'outputs': {\n        'number': 60,\n        'name': 255,  # in characters\n        'description': 1024  # in bytes\n    },\n    'parameters': {\n        'number': 60,\n        'name': 255,  # in characters\n        'value': 4096  # in bytes\n    },\n    'resources': {\n        'number': 200,\n        'name': 255  # in characters\n    },\n    'template': {\n        'body': 460800,  # in bytes\n        'description': 1024  # in bytes\n    }\n}\n\n\ndef load_resources(filename='/data/CloudSpecs/us-east-1.json'):\n    \"\"\"Load resources\"\"\"\n\n    filename = pkg_resources.resource_filename(\n        __name__,\n        filename\n    )\n\n    with open(filename) as fp:\n        return json.load(fp)\n\n\nRESOURCE_SPECS = {}\n\n\ndef merge_spec(source, destination):\n    \"\"\" Recursive merge spec dict \"\"\"\n\n    for key, value in source.items():\n        if isinstance(value, dict):\n            node = destination.setdefault(key, {})\n            merge_spec(value, node)\n        else:\n            destination[key] = value\n\n    return destination\n\n\ndef set_specs(override_spec_data):\n    \"\"\" Override Resource Specs \"\"\"\n\n    excludes = []\n    includes = []\n\n    # Extract the exclude list from the override file\n    if 'ExcludeResourceTypes' in override_spec_data:\n        excludes = override_spec_data.pop('ExcludeResourceTypes')\n    if 'IncludeResourceTypes' in override_spec_data:\n        includes = override_spec_data.pop('IncludeResourceTypes')\n\n    for region, spec in RESOURCE_SPECS.items():\n\n        # Merge override spec file into the AWS Resource specification\n        if override_spec_data:\n            RESOURCE_SPECS[region] = merge_spec(override_spec_data, spec)\n\n        # Grab a list of all resources\n        all_resources = list(RESOURCE_SPECS[region]['ResourceTypes'].keys())[:]\n\n        resources = []\n\n        # Remove unsupported resource using includes\n        if includes:\n            for include in includes:\n                regex = re.compile(include.replace('*', '(.*)') + '$')\n                matches = [string for string in all_resources if re.match(regex, string)]\n\n                resources.extend(matches)\n        else:\n            resources = all_resources[:]\n\n        # Remove unsupported resources using the excludes\n        if excludes:\n            for exclude in excludes:\n                regex = re.compile(exclude.replace('*', '(.*)') + '$')\n                matches = [string for string in resources if re.match(regex, string)]\n\n                for match in matches:\n                    resources.remove(match)\n\n        # Remove unsupported resources\n        for resource in all_resources:\n            if resource not in resources:\n                del RESOURCE_SPECS[region]['ResourceTypes'][resource]\n\n\ndef initialize_specs():\n    \"\"\" Reload Resource Specs \"\"\"\n    for reg in REGIONS:\n        RESOURCE_SPECS[reg] = load_resources(filename=('/data/CloudSpecs/%s.json' % reg))\n\n\ninitialize_specs()\n\n\ndef load_plugins(directory):\n    \"\"\"Load plugins\"\"\"\n    result = []\n    fh = None\n\n    def onerror(os_error):\n        \"\"\"Raise an error\"\"\"\n        raise os_error\n\n    for root, _, filenames in os.walk(directory, onerror=onerror):\n        for filename in fnmatch.filter(filenames, '[A-Za-z]*.py'):\n            pluginname = filename.replace('.py', '')\n            try:\n                fh, filename, desc = imp.find_module(pluginname, [root])\n                mod = imp.load_module(pluginname, fh, filename, desc)\n                for _, clazz in inspect.getmembers(mod, inspect.isclass):\n                    method_resolution = inspect.getmro(clazz)\n                    if [clz for clz in method_resolution[1:] if clz.__module__ == 'cfnlint' and clz.__name__ == 'CloudFormationLintRule']:\n                        # create and instance of subclasses of CloudFormationLintRule\n                        obj = clazz()\n                        result.append(obj)\n            finally:\n                if fh:\n                    fh.close()\n\n    return result\n\n\ndef convert_dict(template, start_mark=(0, 0), end_mark=(0, 0)):\n    \"\"\"Convert dict to template\"\"\"\n    if isinstance(template, dict):\n        if not isinstance(template, dict_node):\n            template = dict_node(template, start_mark, end_mark)\n        for k, v in template.items():\n            template[k] = convert_dict(v)\n    elif isinstance(template, list):\n        if not isinstance(template, list_node):\n            template = list_node(template, start_mark, end_mark)\n        for i, v in enumerate(template):\n            template[i] = convert_dict(v)\n\n    return template\n\n\ndef override_specs(override_spec_file):\n    \"\"\"Override specs file\"\"\"\n    try:\n        filename = override_spec_file\n        with open(filename) as fp:\n            custom_spec_data = json.load(fp)\n\n        set_specs(custom_spec_data)\n    except IOError as e:\n        if e.errno == 2:\n            LOGGER.error('Override spec file not found: %s', filename)\n            sys.exit(1)\n        elif e.errno == 21:\n            LOGGER.error('Override spec file references a directory, not a file: %s', filename)\n            sys.exit(1)\n        elif e.errno == 13:\n            LOGGER.error('Permission denied when accessing override spec file: %s', filename)\n            sys.exit(1)\n    except (ValueError) as err:\n        LOGGER.error('Override spec file %s is malformed: %s', filename, err)\n        sys.exit(1)\n", "path": "src/cfnlint/helpers.py"}], "after_files": [{"content": "\"\"\"\n  Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nimport sys\nimport fnmatch\nimport json\nimport os\nimport imp\nimport logging\nimport re\nimport inspect\nimport pkg_resources\nfrom cfnlint.decode.node import dict_node, list_node, str_node\n\nLOGGER = logging.getLogger(__name__)\n\nTAG_MAP = 'tag:yaml.org,2002:map'\nUNCONVERTED_SUFFIXES = ['Ref', 'Condition']\nFN_PREFIX = 'Fn::'\nCONDITION_FUNCTIONS = ['Fn::If']\nREGIONS = ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'ca-central-1',\n           'eu-central-1', 'eu-west-1', 'eu-west-2', 'ap-northeast-1',\n           'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1',\n           'sa-east-1']\n\nREGEX_ALPHANUMERIC = re.compile('^[a-zA-Z0-9]*$')\nREGEX_CIDR = re.compile(r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$')\nREGEX_IPV4 = re.compile(r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')\nREGEX_IPV6 = re.compile(r'^(((?=.*(::))(?!.*\\3.+\\3))\\3?|[\\dA-F]{1,4}:)([\\dA-F]{1,4}(\\3|:\\b)|\\2){5}(([\\dA-F]{1,4}(\\3|:\\b|$)|\\2){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})\\Z', re.I | re.S)\nREGEX_DYN_REF = re.compile(r'^.*{{resolve:.+}}.*$')\nREGEX_DYN_REF_SSM = re.compile(r'^.*{{resolve:ssm:[a-zA-Z0-9_\\.\\-/]+:\\d+}}.*$')\nREGEX_DYN_REF_SSM_SECURE = re.compile(r'^.*{{resolve:ssm-secure:[a-zA-Z0-9_\\.\\-/]+:\\d+}}.*$')\n\n\nAVAILABILITY_ZONES = [\n    'us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d', 'us-east-1e', 'us-east-1f',\n    'us-east-2a' 'us-east-2b' 'us-east-2c',\n    'us-west-1a', 'us-west-1b', 'us-west-1c',\n    'us-west-2a', 'us-west-2b', 'us-west-2c',\n    'ca-central-1a', 'ca-central-1b',\n    'sa-east-1a', 'sa-east-1b', 'sa-east-1c',\n    'eu-west-1a', 'eu-west-1b', 'eu-west-1c',\n    'eu-west-2a', 'eu-west-2b', 'eu-west-2c',\n    'eu-west-3a', 'eu-west-3b', 'eu-west-3c',\n    'eu-central-1a', 'eu-central-1b', 'eu-central-1c',\n    'eu-central-2a', 'eu-central-2b', 'eu-central-2c',\n    'ap-northeast-1a', 'ap-northeast-1b', 'ap-northeast-1c', 'ap-northeast-1d',\n    'ap-northeast-2a', 'ap-northeast-2b',\n    'ap-northeast-3a',\n    'ap-southeast-1a', 'ap-southeast-1b', 'ap-southeast-1c',\n    'ap-southeast-2a', 'ap-southeast-2b', 'ap-southeast-2c',\n    'ap-south-1a', 'ap-south-1b',\n    'cn-north-1a', 'cn-north-1b',\n]\n\nFUNCTIONS = [\n    'Fn::Base64', 'Fn::GetAtt', 'Fn::GetAZs', 'Fn::ImportValue',\n    'Fn::Join', 'Fn::Split', 'Fn::FindInMap', 'Fn::Select', 'Ref',\n    'Fn::If', 'Fn::Contains', 'Fn::Sub', 'Fn::Cidr']\n\nLIMITS = {\n    'mappings': {\n        'number': 100,\n        'attributes': 64,\n        'name': 255  # in characters\n    },\n    'outputs': {\n        'number': 60,\n        'name': 255,  # in characters\n        'description': 1024  # in bytes\n    },\n    'parameters': {\n        'number': 60,\n        'name': 255,  # in characters\n        'value': 4096  # in bytes\n    },\n    'resources': {\n        'number': 200,\n        'name': 255  # in characters\n    },\n    'template': {\n        'body': 460800,  # in bytes\n        'description': 1024  # in bytes\n    }\n}\n\n\ndef load_resources(filename='/data/CloudSpecs/us-east-1.json'):\n    \"\"\"Load resources\"\"\"\n\n    filename = pkg_resources.resource_filename(\n        __name__,\n        filename\n    )\n\n    with open(filename) as fp:\n        return json.load(fp)\n\n\nRESOURCE_SPECS = {}\n\n\ndef merge_spec(source, destination):\n    \"\"\" Recursive merge spec dict \"\"\"\n\n    for key, value in source.items():\n        if isinstance(value, dict):\n            node = destination.setdefault(key, {})\n            merge_spec(value, node)\n        else:\n            destination[key] = value\n\n    return destination\n\n\ndef set_specs(override_spec_data):\n    \"\"\" Override Resource Specs \"\"\"\n\n    excludes = []\n    includes = []\n\n    # Extract the exclude list from the override file\n    if 'ExcludeResourceTypes' in override_spec_data:\n        excludes = override_spec_data.pop('ExcludeResourceTypes')\n    if 'IncludeResourceTypes' in override_spec_data:\n        includes = override_spec_data.pop('IncludeResourceTypes')\n\n    for region, spec in RESOURCE_SPECS.items():\n\n        # Merge override spec file into the AWS Resource specification\n        if override_spec_data:\n            RESOURCE_SPECS[region] = merge_spec(override_spec_data, spec)\n\n        # Grab a list of all resources\n        all_resources = list(RESOURCE_SPECS[region]['ResourceTypes'].keys())[:]\n\n        resources = []\n\n        # Remove unsupported resource using includes\n        if includes:\n            for include in includes:\n                regex = re.compile(include.replace('*', '(.*)') + '$')\n                matches = [string for string in all_resources if re.match(regex, string)]\n\n                resources.extend(matches)\n        else:\n            resources = all_resources[:]\n\n        # Remove unsupported resources using the excludes\n        if excludes:\n            for exclude in excludes:\n                regex = re.compile(exclude.replace('*', '(.*)') + '$')\n                matches = [string for string in resources if re.match(regex, string)]\n\n                for match in matches:\n                    resources.remove(match)\n\n        # Remove unsupported resources\n        for resource in all_resources:\n            if resource not in resources:\n                del RESOURCE_SPECS[region]['ResourceTypes'][resource]\n\n\ndef initialize_specs():\n    \"\"\" Reload Resource Specs \"\"\"\n    for reg in REGIONS:\n        RESOURCE_SPECS[reg] = load_resources(filename=('/data/CloudSpecs/%s.json' % reg))\n\n\ninitialize_specs()\n\n\ndef load_plugins(directory):\n    \"\"\"Load plugins\"\"\"\n    result = []\n    fh = None\n\n    def onerror(os_error):\n        \"\"\"Raise an error\"\"\"\n        raise os_error\n\n    for root, _, filenames in os.walk(directory, onerror=onerror):\n        for filename in fnmatch.filter(filenames, '[A-Za-z]*.py'):\n            pluginname = filename.replace('.py', '')\n            try:\n                fh, filename, desc = imp.find_module(pluginname, [root])\n                mod = imp.load_module(pluginname, fh, filename, desc)\n                for _, clazz in inspect.getmembers(mod, inspect.isclass):\n                    method_resolution = inspect.getmro(clazz)\n                    if [clz for clz in method_resolution[1:] if clz.__module__ == 'cfnlint' and clz.__name__ == 'CloudFormationLintRule']:\n                        # create and instance of subclasses of CloudFormationLintRule\n                        obj = clazz()\n                        result.append(obj)\n            finally:\n                if fh:\n                    fh.close()\n\n    return result\n\n\ndef convert_dict(template, start_mark=(0, 0), end_mark=(0, 0)):\n    \"\"\"Convert dict to template\"\"\"\n    if isinstance(template, dict):\n        if not isinstance(template, dict_node):\n            template = dict_node(template, start_mark, end_mark)\n        for k, v in template.copy().items():\n            k_start_mark = start_mark\n            k_end_mark = end_mark\n            if isinstance(k, str_node):\n                k_start_mark = k.start_mark\n                k_end_mark = k.end_mark\n            new_k = str_node(k, k_start_mark, k_end_mark)\n            del template[k]\n            template[new_k] = convert_dict(v, k_start_mark, k_end_mark)\n    elif isinstance(template, list):\n        if not isinstance(template, list_node):\n            template = list_node(template, start_mark, end_mark)\n        for i, v in enumerate(template):\n            template[i] = convert_dict(v, start_mark, end_mark)\n\n    return template\n\n\ndef override_specs(override_spec_file):\n    \"\"\"Override specs file\"\"\"\n    try:\n        filename = override_spec_file\n        with open(filename) as fp:\n            custom_spec_data = json.load(fp)\n\n        set_specs(custom_spec_data)\n    except IOError as e:\n        if e.errno == 2:\n            LOGGER.error('Override spec file not found: %s', filename)\n            sys.exit(1)\n        elif e.errno == 21:\n            LOGGER.error('Override spec file references a directory, not a file: %s', filename)\n            sys.exit(1)\n        elif e.errno == 13:\n            LOGGER.error('Permission denied when accessing override spec file: %s', filename)\n            sys.exit(1)\n    except (ValueError) as err:\n        LOGGER.error('Override spec file %s is malformed: %s', filename, err)\n        sys.exit(1)\n", "path": "src/cfnlint/helpers.py"}]}