We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Nova Scotia new URL (CA_NS)
Quick note, I haven't had a chance to dig into it in detail yet:

Looks like the website has been redesigned and things shuffled around a bit.

New page URL is https://www.nspower.ca/clean-energy/todays-energy-stats

JSON URL is now https://www.nspower.ca/library/CurrentLoad/CurrentMix.json

JSON format looks similar to before so it might just be a matter of swapping the URL.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `parsers/CA_NS.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 # The arrow library is used to handle datetimes
4 import arrow
5 # The request library is used to fetch content through HTTP
6 import requests
7 
8 
9 def _get_ns_info(requests_obj, logger):
10     zone_key = 'CA-NS'
11 
12     # This is based on validation logic in https://www.nspower.ca/site/renewables/assets/js/site.js
13     # In practical terms, I've seen hydro production go way too high (>70%) which is way more
14     # than reported capacity.
15     valid_percent = {
16         # The validation JS reports error when Solid Fuel (coal) is over 85%,
17         # but as far as I can tell, that can actually be a valid result, I've seen it a few times.
18         # Use 98% instead.
19         'coal': (0.25, 0.98),
20         'gas': (0, 0.5),
21         'biomass': (0, 0.15),
22         'hydro': (0, 0.60),
23         'wind': (0, 0.55),
24         'imports': (0, 0.20)
25     }
26 
27     # Sanity checks: verify that reported production doesn't exceed listed capacity by a lot.
28     # In particular, we've seen error cases where hydro production ends up calculated as 900 MW
29     # which greatly exceeds known capacity of 418 MW.
30     valid_absolute = {
31         'coal': 1300,
32         'gas': 700,
33         'biomass': 100,
34         'hydro': 500,
35         'wind': 700
36     }
37 
38     # As of November 2018, NSPower redirects their web traffic to HTTPS. However we've been
39     # getting SSL errors in Python, even though loading these URLs in Firefox 63 gives no errors.
40     # This isn't confidential or security-sensitive data, so ignore the SSL errors.
41     mix_url = 'https://www.nspower.ca/system_report/today/currentmix.json'
42     mix_data = requests_obj.get(mix_url, verify=False).json()
43 
44     load_url = 'https://www.nspower.ca/system_report/today/currentload.json'
45     load_data = requests_obj.get(load_url, verify=False).json()
46 
47     production = []
48     imports = []
49     for mix in mix_data:
50         percent_mix = {
51             'coal': mix['Solid Fuel'] / 100.0,
52             'gas': (mix['HFO/Natural Gas'] + mix['CT\'s'] + mix['LM 6000\'s']) / 100.0,
53             'biomass': mix['Biomass'] / 100.0,
54             'hydro': mix['Hydro'] / 100.0,
55             'wind': mix['Wind'] / 100.0,
56             'imports': mix['Imports'] / 100.0
57         }
58 
59         # datetime is in format '/Date(1493924400000)/'
60         # get the timestamp 1493924400 (cutting out last three zeros as well)
61         data_timestamp = int(mix['datetime'][6:-5])
62         data_date = arrow.get(data_timestamp).datetime
63 
64         # validate
65         valid = True
66         for gen_type, value in percent_mix.items():
67             percent_bounds = valid_percent[gen_type]
68             if not (percent_bounds[0] <= value <= percent_bounds[1]):
69                 # skip this datapoint in the loop
70                 valid = False
71                 logger.warning(
72                     'discarding datapoint at {dt} due to {fuel} percentage '
73                     'out of bounds: {value}'.format(dt=data_date, fuel=gen_type, value=value),
74                     extra={'key': zone_key})
75         if not valid:
76             # continue the outer loop, not the inner
77             continue
78 
79         # in mix_data, the values are expressed as percentages,
80         # and have to be multiplied by load to find the actual MW value.
81         corresponding_load = [load_period for load_period in load_data
82                               if load_period['datetime'] == mix['datetime']]
83         if corresponding_load:
84             load = corresponding_load[0]['Base Load']
85         else:
86             # if not found, assume 1244 MW, based on average yearly electricity available for use
87             # in 2014 and 2015 (Statistics Canada table Table 127-0008 for Nova Scotia)
88             load = 1244
89             logger.warning('unable to find load for {}, assuming 1244 MW'.format(data_date),
90                            extra={'key': zone_key})
91 
92         electricity_mix = {
93             gen_type: percent_value * load
94             for gen_type, percent_value in percent_mix.items()
95         }
96 
97         # validate again
98         valid = True
99         for gen_type, value in electricity_mix.items():
100             absolute_bound = valid_absolute.get(gen_type)  # imports are not in valid_absolute
101             if absolute_bound and value > absolute_bound:
102                 valid = False
103                 logger.warning(
104                     'discarding datapoint at {dt} due to {fuel} '
105                     'too high: {value} MW'.format(dt=data_date, fuel=gen_type, value=value),
106                     extra={'key': zone_key})
107         if not valid:
108             # continue the outer loop, not the inner
109             continue
110 
111         production.append({
112             'zoneKey': zone_key,
113             'datetime': data_date,
114             'production': {key: value
115                            for key, value in electricity_mix.items()
116                            if key != 'imports'},
117             'source': 'nspower.ca'
118         })
119 
120         # In this source, imports are positive. In the expected result for CA-NB->CA-NS,
121         # "net" represents a flow from NB to NS, that is, an import to NS.
122         # So the value can be used directly.
123         # Note that this API only specifies imports. When NS is exporting energy, the API returns 0.
124         imports.append({
125             'datetime': data_date,
126             'netFlow': electricity_mix['imports'],
127             'sortedZoneKeys': 'CA-NB->CA-NS',
128             'source': 'nspower.ca'
129         })
130 
131     return production, imports
132 
133 
134 def fetch_production(zone_key='CA-NS', session=None, target_datetime=None, logger=None):
135     """Requests the last known production mix (in MW) of a given country
136 
137     Arguments:
138     zone_key (optional) -- used in case a parser is able to fetch multiple countries
139     session (optional)      -- request session passed in order to re-use an existing session
140 
141     Return:
142     A dictionary in the form:
143     {
144       'zoneKey': 'FR',
145       'datetime': '2017-01-01T00:00:00Z',
146       'production': {
147           'biomass': 0.0,
148           'coal': 0.0,
149           'gas': 0.0,
150           'hydro': 0.0,
151           'nuclear': null,
152           'oil': 0.0,
153           'solar': 0.0,
154           'wind': 0.0,
155           'geothermal': 0.0,
156           'unknown': 0.0
157       },
158       'storage': {
159           'hydro': -10.0,
160       },
161       'source': 'mysource.com'
162     }
163     """
164     if target_datetime:
165         raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')
166 
167     r = session or requests.session()
168 
169     production, imports = _get_ns_info(r, logger)
170 
171     return production
172 
173 
174 def fetch_exchange(zone_key1, zone_key2, session=None, target_datetime=None, logger=None):
175     """Requests the last known power exchange (in MW) between two regions.
176 
177     Note: As of early 2017, Nova Scotia only has an exchange with New Brunswick (CA-NB).
178     (An exchange with Newfoundland, "Maritime Link", is scheduled to open in "late 2017").
179 
180     The API for Nova Scotia only specifies imports. When NS is exporting energy,
181     the API returns 0.
182     """
183     if target_datetime:
184         raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')
185 
186     sorted_zone_keys = '->'.join(sorted([zone_key1, zone_key2]))
187 
188     if sorted_zone_keys != 'CA-NB->CA-NS':
189         raise NotImplementedError('This exchange pair is not implemented')
190 
191     requests_obj = session or requests.session()
192     _, imports = _get_ns_info(requests_obj, logger)
193 
194     return imports
195 
196 
197 if __name__ == '__main__':
198     """Main method, never used by the Electricity Map backend, but handy for testing."""
199 
200     from pprint import pprint
201     import logging
202     test_logger = logging.getLogger()
203 
204     print('fetch_production() ->')
205     pprint(fetch_production(logger=test_logger))
206 
207     print('fetch_exchange("CA-NS", "CA-NB") ->')
208     pprint(fetch_exchange("CA-NS", "CA-NB", logger=test_logger))
209
```
--- 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/parsers/CA_NS.py b/parsers/CA_NS.py
--- a/parsers/CA_NS.py
+++ b/parsers/CA_NS.py
@@ -35,14 +35,11 @@
         'wind': 700
     }
 
-    # As of November 2018, NSPower redirects their web traffic to HTTPS. However we've been
-    # getting SSL errors in Python, even though loading these URLs in Firefox 63 gives no errors.
-    # This isn't confidential or security-sensitive data, so ignore the SSL errors.
-    mix_url = 'https://www.nspower.ca/system_report/today/currentmix.json'
-    mix_data = requests_obj.get(mix_url, verify=False).json()
-
-    load_url = 'https://www.nspower.ca/system_report/today/currentload.json'
-    load_data = requests_obj.get(load_url, verify=False).json()
+    mix_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentMix.json'
+    mix_data = requests_obj.get(mix_url).json()
+
+    load_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentLoad.json'
+    load_data = requests_obj.get(load_url).json()
 
     production = []
     imports = []

{"golden_diff": "diff --git a/parsers/CA_NS.py b/parsers/CA_NS.py\n--- a/parsers/CA_NS.py\n+++ b/parsers/CA_NS.py\n@@ -35,14 +35,11 @@\n         'wind': 700\n     }\n \n-    # As of November 2018, NSPower redirects their web traffic to HTTPS. However we've been\n-    # getting SSL errors in Python, even though loading these URLs in Firefox 63 gives no errors.\n-    # This isn't confidential or security-sensitive data, so ignore the SSL errors.\n-    mix_url = 'https://www.nspower.ca/system_report/today/currentmix.json'\n-    mix_data = requests_obj.get(mix_url, verify=False).json()\n-\n-    load_url = 'https://www.nspower.ca/system_report/today/currentload.json'\n-    load_data = requests_obj.get(load_url, verify=False).json()\n+    mix_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentMix.json'\n+    mix_data = requests_obj.get(mix_url).json()\n+\n+    load_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentLoad.json'\n+    load_data = requests_obj.get(load_url).json()\n \n     production = []\n     imports = []\n", "issue": "Nova Scotia new URL (CA_NS)\nQuick note, I haven't had a chance to dig into it in detail yet:\r\n\r\nLooks like the website has been redesigned and things shuffled around a bit.\r\n\r\nNew page URL is https://www.nspower.ca/clean-energy/todays-energy-stats\r\n\r\nJSON URL is now https://www.nspower.ca/library/CurrentLoad/CurrentMix.json\r\n\r\nJSON format looks similar to before so it might just be a matter of swapping the URL.\n", "before_files": [{"content": "#!/usr/bin/env python3\n\n# The arrow library is used to handle datetimes\nimport arrow\n# The request library is used to fetch content through HTTP\nimport requests\n\n\ndef _get_ns_info(requests_obj, logger):\n    zone_key = 'CA-NS'\n\n    # This is based on validation logic in https://www.nspower.ca/site/renewables/assets/js/site.js\n    # In practical terms, I've seen hydro production go way too high (>70%) which is way more\n    # than reported capacity.\n    valid_percent = {\n        # The validation JS reports error when Solid Fuel (coal) is over 85%,\n        # but as far as I can tell, that can actually be a valid result, I've seen it a few times.\n        # Use 98% instead.\n        'coal': (0.25, 0.98),\n        'gas': (0, 0.5),\n        'biomass': (0, 0.15),\n        'hydro': (0, 0.60),\n        'wind': (0, 0.55),\n        'imports': (0, 0.20)\n    }\n\n    # Sanity checks: verify that reported production doesn't exceed listed capacity by a lot.\n    # In particular, we've seen error cases where hydro production ends up calculated as 900 MW\n    # which greatly exceeds known capacity of 418 MW.\n    valid_absolute = {\n        'coal': 1300,\n        'gas': 700,\n        'biomass': 100,\n        'hydro': 500,\n        'wind': 700\n    }\n\n    # As of November 2018, NSPower redirects their web traffic to HTTPS. However we've been\n    # getting SSL errors in Python, even though loading these URLs in Firefox 63 gives no errors.\n    # This isn't confidential or security-sensitive data, so ignore the SSL errors.\n    mix_url = 'https://www.nspower.ca/system_report/today/currentmix.json'\n    mix_data = requests_obj.get(mix_url, verify=False).json()\n\n    load_url = 'https://www.nspower.ca/system_report/today/currentload.json'\n    load_data = requests_obj.get(load_url, verify=False).json()\n\n    production = []\n    imports = []\n    for mix in mix_data:\n        percent_mix = {\n            'coal': mix['Solid Fuel'] / 100.0,\n            'gas': (mix['HFO/Natural Gas'] + mix['CT\\'s'] + mix['LM 6000\\'s']) / 100.0,\n            'biomass': mix['Biomass'] / 100.0,\n            'hydro': mix['Hydro'] / 100.0,\n            'wind': mix['Wind'] / 100.0,\n            'imports': mix['Imports'] / 100.0\n        }\n\n        # datetime is in format '/Date(1493924400000)/'\n        # get the timestamp 1493924400 (cutting out last three zeros as well)\n        data_timestamp = int(mix['datetime'][6:-5])\n        data_date = arrow.get(data_timestamp).datetime\n\n        # validate\n        valid = True\n        for gen_type, value in percent_mix.items():\n            percent_bounds = valid_percent[gen_type]\n            if not (percent_bounds[0] <= value <= percent_bounds[1]):\n                # skip this datapoint in the loop\n                valid = False\n                logger.warning(\n                    'discarding datapoint at {dt} due to {fuel} percentage '\n                    'out of bounds: {value}'.format(dt=data_date, fuel=gen_type, value=value),\n                    extra={'key': zone_key})\n        if not valid:\n            # continue the outer loop, not the inner\n            continue\n\n        # in mix_data, the values are expressed as percentages,\n        # and have to be multiplied by load to find the actual MW value.\n        corresponding_load = [load_period for load_period in load_data\n                              if load_period['datetime'] == mix['datetime']]\n        if corresponding_load:\n            load = corresponding_load[0]['Base Load']\n        else:\n            # if not found, assume 1244 MW, based on average yearly electricity available for use\n            # in 2014 and 2015 (Statistics Canada table Table 127-0008 for Nova Scotia)\n            load = 1244\n            logger.warning('unable to find load for {}, assuming 1244 MW'.format(data_date),\n                           extra={'key': zone_key})\n\n        electricity_mix = {\n            gen_type: percent_value * load\n            for gen_type, percent_value in percent_mix.items()\n        }\n\n        # validate again\n        valid = True\n        for gen_type, value in electricity_mix.items():\n            absolute_bound = valid_absolute.get(gen_type)  # imports are not in valid_absolute\n            if absolute_bound and value > absolute_bound:\n                valid = False\n                logger.warning(\n                    'discarding datapoint at {dt} due to {fuel} '\n                    'too high: {value} MW'.format(dt=data_date, fuel=gen_type, value=value),\n                    extra={'key': zone_key})\n        if not valid:\n            # continue the outer loop, not the inner\n            continue\n\n        production.append({\n            'zoneKey': zone_key,\n            'datetime': data_date,\n            'production': {key: value\n                           for key, value in electricity_mix.items()\n                           if key != 'imports'},\n            'source': 'nspower.ca'\n        })\n\n        # In this source, imports are positive. In the expected result for CA-NB->CA-NS,\n        # \"net\" represents a flow from NB to NS, that is, an import to NS.\n        # So the value can be used directly.\n        # Note that this API only specifies imports. When NS is exporting energy, the API returns 0.\n        imports.append({\n            'datetime': data_date,\n            'netFlow': electricity_mix['imports'],\n            'sortedZoneKeys': 'CA-NB->CA-NS',\n            'source': 'nspower.ca'\n        })\n\n    return production, imports\n\n\ndef fetch_production(zone_key='CA-NS', session=None, target_datetime=None, logger=None):\n    \"\"\"Requests the last known production mix (in MW) of a given country\n\n    Arguments:\n    zone_key (optional) -- used in case a parser is able to fetch multiple countries\n    session (optional)      -- request session passed in order to re-use an existing session\n\n    Return:\n    A dictionary in the form:\n    {\n      'zoneKey': 'FR',\n      'datetime': '2017-01-01T00:00:00Z',\n      'production': {\n          'biomass': 0.0,\n          'coal': 0.0,\n          'gas': 0.0,\n          'hydro': 0.0,\n          'nuclear': null,\n          'oil': 0.0,\n          'solar': 0.0,\n          'wind': 0.0,\n          'geothermal': 0.0,\n          'unknown': 0.0\n      },\n      'storage': {\n          'hydro': -10.0,\n      },\n      'source': 'mysource.com'\n    }\n    \"\"\"\n    if target_datetime:\n        raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')\n\n    r = session or requests.session()\n\n    production, imports = _get_ns_info(r, logger)\n\n    return production\n\n\ndef fetch_exchange(zone_key1, zone_key2, session=None, target_datetime=None, logger=None):\n    \"\"\"Requests the last known power exchange (in MW) between two regions.\n\n    Note: As of early 2017, Nova Scotia only has an exchange with New Brunswick (CA-NB).\n    (An exchange with Newfoundland, \"Maritime Link\", is scheduled to open in \"late 2017\").\n\n    The API for Nova Scotia only specifies imports. When NS is exporting energy,\n    the API returns 0.\n    \"\"\"\n    if target_datetime:\n        raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')\n\n    sorted_zone_keys = '->'.join(sorted([zone_key1, zone_key2]))\n\n    if sorted_zone_keys != 'CA-NB->CA-NS':\n        raise NotImplementedError('This exchange pair is not implemented')\n\n    requests_obj = session or requests.session()\n    _, imports = _get_ns_info(requests_obj, logger)\n\n    return imports\n\n\nif __name__ == '__main__':\n    \"\"\"Main method, never used by the Electricity Map backend, but handy for testing.\"\"\"\n\n    from pprint import pprint\n    import logging\n    test_logger = logging.getLogger()\n\n    print('fetch_production() ->')\n    pprint(fetch_production(logger=test_logger))\n\n    print('fetch_exchange(\"CA-NS\", \"CA-NB\") ->')\n    pprint(fetch_exchange(\"CA-NS\", \"CA-NB\", logger=test_logger))\n", "path": "parsers/CA_NS.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n\n# The arrow library is used to handle datetimes\nimport arrow\n# The request library is used to fetch content through HTTP\nimport requests\n\n\ndef _get_ns_info(requests_obj, logger):\n    zone_key = 'CA-NS'\n\n    # This is based on validation logic in https://www.nspower.ca/site/renewables/assets/js/site.js\n    # In practical terms, I've seen hydro production go way too high (>70%) which is way more\n    # than reported capacity.\n    valid_percent = {\n        # The validation JS reports error when Solid Fuel (coal) is over 85%,\n        # but as far as I can tell, that can actually be a valid result, I've seen it a few times.\n        # Use 98% instead.\n        'coal': (0.25, 0.98),\n        'gas': (0, 0.5),\n        'biomass': (0, 0.15),\n        'hydro': (0, 0.60),\n        'wind': (0, 0.55),\n        'imports': (0, 0.20)\n    }\n\n    # Sanity checks: verify that reported production doesn't exceed listed capacity by a lot.\n    # In particular, we've seen error cases where hydro production ends up calculated as 900 MW\n    # which greatly exceeds known capacity of 418 MW.\n    valid_absolute = {\n        'coal': 1300,\n        'gas': 700,\n        'biomass': 100,\n        'hydro': 500,\n        'wind': 700\n    }\n\n    mix_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentMix.json'\n    mix_data = requests_obj.get(mix_url).json()\n\n    load_url = 'https://www.nspower.ca/library/CurrentLoad/CurrentLoad.json'\n    load_data = requests_obj.get(load_url).json()\n\n    production = []\n    imports = []\n    for mix in mix_data:\n        percent_mix = {\n            'coal': mix['Solid Fuel'] / 100.0,\n            'gas': (mix['HFO/Natural Gas'] + mix['CT\\'s'] + mix['LM 6000\\'s']) / 100.0,\n            'biomass': mix['Biomass'] / 100.0,\n            'hydro': mix['Hydro'] / 100.0,\n            'wind': mix['Wind'] / 100.0,\n            'imports': mix['Imports'] / 100.0\n        }\n\n        # datetime is in format '/Date(1493924400000)/'\n        # get the timestamp 1493924400 (cutting out last three zeros as well)\n        data_timestamp = int(mix['datetime'][6:-5])\n        data_date = arrow.get(data_timestamp).datetime\n\n        # validate\n        valid = True\n        for gen_type, value in percent_mix.items():\n            percent_bounds = valid_percent[gen_type]\n            if not (percent_bounds[0] <= value <= percent_bounds[1]):\n                # skip this datapoint in the loop\n                valid = False\n                logger.warning(\n                    'discarding datapoint at {dt} due to {fuel} percentage '\n                    'out of bounds: {value}'.format(dt=data_date, fuel=gen_type, value=value),\n                    extra={'key': zone_key})\n        if not valid:\n            # continue the outer loop, not the inner\n            continue\n\n        # in mix_data, the values are expressed as percentages,\n        # and have to be multiplied by load to find the actual MW value.\n        corresponding_load = [load_period for load_period in load_data\n                              if load_period['datetime'] == mix['datetime']]\n        if corresponding_load:\n            load = corresponding_load[0]['Base Load']\n        else:\n            # if not found, assume 1244 MW, based on average yearly electricity available for use\n            # in 2014 and 2015 (Statistics Canada table Table 127-0008 for Nova Scotia)\n            load = 1244\n            logger.warning('unable to find load for {}, assuming 1244 MW'.format(data_date),\n                           extra={'key': zone_key})\n\n        electricity_mix = {\n            gen_type: percent_value * load\n            for gen_type, percent_value in percent_mix.items()\n        }\n\n        # validate again\n        valid = True\n        for gen_type, value in electricity_mix.items():\n            absolute_bound = valid_absolute.get(gen_type)  # imports are not in valid_absolute\n            if absolute_bound and value > absolute_bound:\n                valid = False\n                logger.warning(\n                    'discarding datapoint at {dt} due to {fuel} '\n                    'too high: {value} MW'.format(dt=data_date, fuel=gen_type, value=value),\n                    extra={'key': zone_key})\n        if not valid:\n            # continue the outer loop, not the inner\n            continue\n\n        production.append({\n            'zoneKey': zone_key,\n            'datetime': data_date,\n            'production': {key: value\n                           for key, value in electricity_mix.items()\n                           if key != 'imports'},\n            'source': 'nspower.ca'\n        })\n\n        # In this source, imports are positive. In the expected result for CA-NB->CA-NS,\n        # \"net\" represents a flow from NB to NS, that is, an import to NS.\n        # So the value can be used directly.\n        # Note that this API only specifies imports. When NS is exporting energy, the API returns 0.\n        imports.append({\n            'datetime': data_date,\n            'netFlow': electricity_mix['imports'],\n            'sortedZoneKeys': 'CA-NB->CA-NS',\n            'source': 'nspower.ca'\n        })\n\n    return production, imports\n\n\ndef fetch_production(zone_key='CA-NS', session=None, target_datetime=None, logger=None):\n    \"\"\"Requests the last known production mix (in MW) of a given country\n\n    Arguments:\n    zone_key (optional) -- used in case a parser is able to fetch multiple countries\n    session (optional)      -- request session passed in order to re-use an existing session\n\n    Return:\n    A dictionary in the form:\n    {\n      'zoneKey': 'FR',\n      'datetime': '2017-01-01T00:00:00Z',\n      'production': {\n          'biomass': 0.0,\n          'coal': 0.0,\n          'gas': 0.0,\n          'hydro': 0.0,\n          'nuclear': null,\n          'oil': 0.0,\n          'solar': 0.0,\n          'wind': 0.0,\n          'geothermal': 0.0,\n          'unknown': 0.0\n      },\n      'storage': {\n          'hydro': -10.0,\n      },\n      'source': 'mysource.com'\n    }\n    \"\"\"\n    if target_datetime:\n        raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')\n\n    r = session or requests.session()\n\n    production, imports = _get_ns_info(r, logger)\n\n    return production\n\n\ndef fetch_exchange(zone_key1, zone_key2, session=None, target_datetime=None, logger=None):\n    \"\"\"Requests the last known power exchange (in MW) between two regions.\n\n    Note: As of early 2017, Nova Scotia only has an exchange with New Brunswick (CA-NB).\n    (An exchange with Newfoundland, \"Maritime Link\", is scheduled to open in \"late 2017\").\n\n    The API for Nova Scotia only specifies imports. When NS is exporting energy,\n    the API returns 0.\n    \"\"\"\n    if target_datetime:\n        raise NotImplementedError('This parser is unable to give information more than 24 hours in the past')\n\n    sorted_zone_keys = '->'.join(sorted([zone_key1, zone_key2]))\n\n    if sorted_zone_keys != 'CA-NB->CA-NS':\n        raise NotImplementedError('This exchange pair is not implemented')\n\n    requests_obj = session or requests.session()\n    _, imports = _get_ns_info(requests_obj, logger)\n\n    return imports\n\n\nif __name__ == '__main__':\n    \"\"\"Main method, never used by the Electricity Map backend, but handy for testing.\"\"\"\n\n    from pprint import pprint\n    import logging\n    test_logger = logging.getLogger()\n\n    print('fetch_production() ->')\n    pprint(fetch_production(logger=test_logger))\n\n    print('fetch_exchange(\"CA-NS\", \"CA-NB\") ->')\n    pprint(fetch_exchange(\"CA-NS\", \"CA-NB\", logger=test_logger))\n", "path": "parsers/CA_NS.py"}]}