uk_bin_collection 0.85.5__py3-none-any.whl → 0.85.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -245,7 +245,7 @@
245
245
  "url": "https://myaccount.chorley.gov.uk/wastecollections.aspx",
246
246
  "web_driver": "http://selenium:4444",
247
247
  "wiki_name": "Chorley Council",
248
- "wiki_note": "Chorley needs to be passed both a Postcode & UPRN to work. Find this on [FindMyAddress](https://www.findmyaddress.co.uk/search)"
248
+ "wiki_note": "Chorley needs to be passed both a Postcode & UPRN in the format of UPRNXXXXXX to work. Find this on [FindMyAddress](https://www.findmyaddress.co.uk/search)"
249
249
  },
250
250
  "ConwyCountyBorough": {
251
251
  "postcode": "LL30 2DF",
@@ -1,136 +1,73 @@
1
- import json
2
- from unittest import mock
3
-
1
+ from unittest.mock import MagicMock, patch
2
+ import argparse
4
3
  import pytest
5
- from requests import exceptions as req_exp
6
- from requests.models import Response
7
- from uk_bin_collection.get_bin_data import AbstractGetBinDataClass as agbdc
8
- from uk_bin_collection.get_bin_data import setup_logging
9
- import logging
10
-
11
-
12
- def mocked_requests_get(*args, **kwargs):
13
- class MockResponse:
14
- def __init__(self, json_data, status_code, raise_error_type):
15
- self.text = json_data
16
- self.status_code = status_code
17
- if raise_error_type is not None:
18
- self.raise_for_status = self.raise_error(raise_error_type)
19
- else:
20
- self.raise_for_status = lambda: None
21
-
22
- def raise_error(self, errorType):
23
- if errorType == "HTTPError":
24
- raise req_exp.HTTPError()
25
- elif errorType == "ConnectionError":
26
- raise req_exp.ConnectionError()
27
- elif errorType == "Timeout":
28
- raise req_exp.Timeout()
29
- elif errorType == "RequestException":
30
- raise req_exp.RequestException()
31
- return errorType
32
-
33
- if args[0] == "aurl":
34
- return MockResponse({"test_data": "test"}, 200, None)
35
- elif args[0] == "HTTPError":
36
- return MockResponse({}, 999, "HTTPError")
37
- elif args[0] == "ConnectionError":
38
- return MockResponse({}, 999, "ConnectionError")
39
- elif args[0] == "Timeout":
40
- return MockResponse({}, 999, "Timeout")
41
- elif args[0] == "RequestException":
42
- return MockResponse({}, 999, "RequestException")
43
- elif args[0] == "notPage":
44
- return MockResponse("not json", 200, None)
45
- return MockResponse(None, 404, "HTTPError")
46
-
47
-
48
- # Unit tests
49
-
50
-
51
- def test_logging_exception():
52
- logging_dict = "SW1A 1AA"
53
- with pytest.raises(ValueError) as exc_info:
54
- result = setup_logging(logging_dict, "ROOT")
55
- assert exc_info.typename == "ValueError"
56
-
57
-
58
- def test_setup_logging_valid_config():
59
- # Example of a minimal valid logging configuration dictionary
60
- logging_config = {
61
- "version": 1,
62
- "handlers": {
63
- "console": {
64
- "class": "logging.StreamHandler",
65
- "level": "DEBUG",
66
- },
67
- },
68
- "loggers": {
69
- "ROOT": {
70
- "handlers": ["console"],
71
- "level": "DEBUG",
72
- },
73
- },
74
- }
75
- logger_name = "ROOT"
76
- # Run the function with valid logging configuration
77
- logger = setup_logging(logging_config, logger_name)
78
-
79
- # Assert that logger is correctly configured
80
- assert logger.name == logger_name
81
- assert logger.level == logging.DEBUG
82
-
83
-
84
- @mock.patch("requests.get", side_effect=mocked_requests_get)
85
- def test_get_data(mock_get):
86
- page_data = agbdc.get_data("aurl")
87
- assert page_data.text == {"test_data": "test"}
88
-
89
-
90
- @pytest.mark.parametrize(
91
- "url", ["HTTPError", "ConnectionError", "Timeout", "RequestException"]
92
- )
93
- @mock.patch("requests.get", side_effect=mocked_requests_get)
94
- def test_get_data_error(mock_get, url):
95
- with pytest.raises(Exception) as exc_info:
96
- result = agbdc.get_data(url)
97
- assert exc_info.typename == url
98
-
99
-
100
- def test_output_json():
101
- bin_data = {"bin": ""}
102
- output = agbdc.output_json(bin_data)
103
- assert type(output) == str
104
- assert output == '{\n "bin": ""\n}'
105
-
106
- class ConcreteGetBinDataClass(agbdc):
107
- """Concrete implementation of the abstract class to test abstract methods."""
108
- def parse_data(self, page: str, **kwargs) -> dict:
109
- return {"mock_key": "mock_value"}
110
-
111
- @pytest.fixture
112
- def concrete_class_instance():
113
- return ConcreteGetBinDataClass()
114
-
115
- def test_get_and_parse_data_no_skip_get_url(concrete_class_instance):
116
- mock_page = "mocked page content"
117
- mock_parsed_data = {"mock_key": "mock_value"}
118
-
119
- with mock.patch.object(concrete_class_instance, 'get_data', return_value=mock_page) as mock_get_data, \
120
- mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data:
121
-
122
- result = concrete_class_instance.get_and_parse_data("http://example.com")
123
-
124
- mock_get_data.assert_called_once_with("http://example.com")
125
- mock_parse_data.assert_called_once_with(mock_page, url="http://example.com")
126
- assert result == mock_parsed_data
127
-
128
- def test_get_and_parse_data_skip_get_url(concrete_class_instance):
129
- mock_parsed_data = {"mock_key": "mock_value"}
130
-
131
- with mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data:
132
-
133
- result = concrete_class_instance.get_and_parse_data("http://example.com", skip_get_url=True)
134
-
135
- mock_parse_data.assert_called_once_with("", url="http://example.com", skip_get_url=True)
136
- assert result == mock_parsed_data
4
+ from uk_bin_collection.collect_data import UKBinCollectionApp, import_council_module
5
+
6
+
7
+
8
+ # Test UKBinCollectionApp setup_arg_parser
9
+ def test_setup_arg_parser():
10
+ app = UKBinCollectionApp()
11
+ app.setup_arg_parser()
12
+
13
+ # Assert that the argument parser has the correct arguments
14
+ assert isinstance(app.parser, argparse.ArgumentParser)
15
+ args = app.parser._actions
16
+ arg_names = [action.dest for action in args]
17
+
18
+ expected_args = [
19
+ "module",
20
+ "URL",
21
+ "postcode",
22
+ "number",
23
+ "skip_get_url",
24
+ "uprn",
25
+ "web_driver",
26
+ "headless",
27
+ "local_browser",
28
+ "dev_mode",
29
+ ]
30
+ assert all(arg in arg_names for arg in expected_args)
31
+
32
+
33
+ # Test UKBinCollectionApp set_args
34
+ def test_set_args():
35
+ app = UKBinCollectionApp()
36
+ app.setup_arg_parser()
37
+
38
+ # Test valid args
39
+ args = ["council_module", "http://example.com", "--postcode", "AB1 2CD"]
40
+ app.set_args(args)
41
+
42
+ assert app.parsed_args.module == "council_module"
43
+ assert app.parsed_args.URL == "http://example.com"
44
+ assert app.parsed_args.postcode == "AB1 2CD"
45
+
46
+
47
+ # Test UKBinCollectionApp client_code method
48
+ def test_client_code():
49
+ app = UKBinCollectionApp()
50
+ mock_get_bin_data_class = MagicMock()
51
+
52
+ # Run the client_code and ensure that template_method is called
53
+ app.client_code(mock_get_bin_data_class, "http://example.com", postcode="AB1 2CD")
54
+ mock_get_bin_data_class.template_method.assert_called_once_with(
55
+ "http://example.com", postcode="AB1 2CD"
56
+ )
57
+
58
+
59
+ # Test the run() function with logging setup
60
+ @patch("uk_bin_collection.collect_data.setup_logging") # Correct patch path
61
+ @patch("uk_bin_collection.collect_data.UKBinCollectionApp.run") # Correct patch path
62
+ @patch("sys.argv", ["uk_bin_collection.py", "council_module", "http://example.com"])
63
+ def test_run_function(mock_app_run, mock_setup_logging):
64
+ from uk_bin_collection.collect_data import run
65
+
66
+ mock_setup_logging.return_value = MagicMock()
67
+ mock_app_run.return_value = None
68
+
69
+ run()
70
+
71
+ # Ensure logging was set up and the app run method was called
72
+ mock_setup_logging.assert_called_once()
73
+ mock_app_run.assert_called_once()
@@ -0,0 +1,197 @@
1
+ import os
2
+ from unittest import mock
3
+ import tempfile
4
+
5
+ import pytest
6
+ from requests import exceptions as req_exp
7
+ from requests.models import Response
8
+ from unittest.mock import patch
9
+ from uk_bin_collection.get_bin_data import AbstractGetBinDataClass as agbdc
10
+ from uk_bin_collection.get_bin_data import setup_logging
11
+ import logging
12
+
13
+
14
+ def mocked_requests_get(*args, **kwargs):
15
+ class MockResponse:
16
+ def __init__(self, json_data, status_code, raise_error_type):
17
+ self.text = json_data
18
+ self.status_code = status_code
19
+ if raise_error_type is not None:
20
+ self.raise_for_status = self.raise_error(raise_error_type)
21
+ else:
22
+ self.raise_for_status = lambda: None
23
+
24
+ def raise_error(self, errorType):
25
+ if errorType == "HTTPError":
26
+ raise req_exp.HTTPError()
27
+ elif errorType == "ConnectionError":
28
+ raise req_exp.ConnectionError()
29
+ elif errorType == "Timeout":
30
+ raise req_exp.Timeout()
31
+ elif errorType == "RequestException":
32
+ raise req_exp.RequestException()
33
+ return errorType
34
+
35
+ if args[0] == "aurl":
36
+ return MockResponse({"test_data": "test"}, 200, None)
37
+ elif args[0] == "HTTPError":
38
+ return MockResponse({}, 999, "HTTPError")
39
+ elif args[0] == "ConnectionError":
40
+ return MockResponse({}, 999, "ConnectionError")
41
+ elif args[0] == "Timeout":
42
+ return MockResponse({}, 999, "Timeout")
43
+ elif args[0] == "RequestException":
44
+ return MockResponse({}, 999, "RequestException")
45
+ elif args[0] == "notPage":
46
+ return MockResponse("not json", 200, None)
47
+ return MockResponse(None, 404, "HTTPError")
48
+
49
+
50
+ # Unit tests
51
+
52
+
53
+ def test_logging_exception():
54
+ logging_dict = "SW1A 1AA"
55
+ with pytest.raises(ValueError) as exc_info:
56
+ result = setup_logging(logging_dict, "ROOT")
57
+ assert exc_info.typename == "ValueError"
58
+
59
+
60
+ def test_setup_logging_valid_config():
61
+ # Example of a minimal valid logging configuration dictionary
62
+ logging_config = {
63
+ "version": 1,
64
+ "handlers": {
65
+ "console": {
66
+ "class": "logging.StreamHandler",
67
+ "level": "DEBUG",
68
+ },
69
+ },
70
+ "loggers": {
71
+ "ROOT": {
72
+ "handlers": ["console"],
73
+ "level": "DEBUG",
74
+ },
75
+ },
76
+ }
77
+ logger_name = "ROOT"
78
+ # Run the function with valid logging configuration
79
+ logger = setup_logging(logging_config, logger_name)
80
+
81
+ # Assert that logger is correctly configured
82
+ assert logger.name == logger_name
83
+ assert logger.level == logging.DEBUG
84
+
85
+
86
+ @mock.patch("requests.get", side_effect=mocked_requests_get)
87
+ def test_get_data(mock_get):
88
+ page_data = agbdc.get_data("aurl")
89
+ assert page_data.text == {"test_data": "test"}
90
+
91
+
92
+ @pytest.mark.parametrize(
93
+ "url", ["HTTPError", "ConnectionError", "Timeout", "RequestException"]
94
+ )
95
+ @mock.patch("requests.get", side_effect=mocked_requests_get)
96
+ def test_get_data_error(mock_get, url):
97
+ with pytest.raises(Exception) as exc_info:
98
+ result = agbdc.get_data(url)
99
+ assert exc_info.typename == url
100
+
101
+
102
+ def test_output_json():
103
+ bin_data = {"bin": ""}
104
+ output = agbdc.output_json(bin_data)
105
+ assert type(output) == str
106
+ assert output == '{\n "bin": ""\n}'
107
+
108
+ class ConcreteGetBinDataClass(agbdc):
109
+ """Concrete implementation of the abstract class to test abstract methods."""
110
+ def parse_data(self, page: str, **kwargs) -> dict:
111
+ return {"mock_key": "mock_value"}
112
+
113
+ def update_dev_mode_data(self, council_module_str, this_url, **kwargs):
114
+ # You can implement the method or delegate it to the abstract class's method
115
+ super().update_dev_mode_data(council_module_str, this_url, **kwargs)
116
+
117
+ @pytest.fixture
118
+ def concrete_class_instance():
119
+ return ConcreteGetBinDataClass()
120
+
121
+ def test_get_and_parse_data_no_skip_get_url(concrete_class_instance):
122
+ mock_page = "mocked page content"
123
+ mock_parsed_data = {"mock_key": "mock_value"}
124
+
125
+ with mock.patch.object(concrete_class_instance, 'get_data', return_value=mock_page) as mock_get_data, \
126
+ mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data:
127
+
128
+ result = concrete_class_instance.get_and_parse_data("http://example.com")
129
+
130
+ mock_get_data.assert_called_once_with("http://example.com")
131
+ mock_parse_data.assert_called_once_with(mock_page, url="http://example.com")
132
+ assert result == mock_parsed_data
133
+
134
+ def test_get_and_parse_data_skip_get_url(concrete_class_instance):
135
+ mock_parsed_data = {"mock_key": "mock_value"}
136
+
137
+ with mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data:
138
+
139
+ result = concrete_class_instance.get_and_parse_data("http://example.com", skip_get_url=True)
140
+
141
+ mock_parse_data.assert_called_once_with("", url="http://example.com", skip_get_url=True)
142
+ assert result == mock_parsed_data
143
+
144
+ @pytest.fixture
145
+ def setup_test_update_dev_mode_data():
146
+ """Fixture to set up and tear down the environment for test_update_dev_mode_data"""
147
+ # Create a temporary directory to simulate the working directory
148
+ test_dir = tempfile.TemporaryDirectory()
149
+
150
+ # Patch os.getcwd() to return the temporary directory
151
+ cwd_patch = patch('os.getcwd', return_value=test_dir.name)
152
+ mock_getcwd = cwd_patch.start()
153
+
154
+ # Ensure the nested directory structure exists
155
+ os.makedirs(os.path.join(test_dir.name, "uk_bin_collection", "tests"))
156
+
157
+ # Yield control back to the test, then clean up after the test
158
+ yield test_dir.name # Provide the test with the temporary directory
159
+
160
+ # Teardown
161
+ test_dir.cleanup()
162
+ cwd_patch.stop()
163
+
164
+
165
+ def test_update_dev_mode_data(setup_test_update_dev_mode_data):
166
+ """Test update_dev_mode_data method to ensure input.json is updated correctly"""
167
+ # The setup fixture returns the mocked current working directory
168
+ mock_cwd = setup_test_update_dev_mode_data
169
+
170
+ # Create an instance of the concrete class that inherits from AbstractGetBinDataClass
171
+ obj = ConcreteGetBinDataClass()
172
+
173
+ # Define input arguments for the method
174
+ council_module_str = 'test_council_module'
175
+ this_url = 'https://example.com'
176
+ kwargs = {
177
+ 'postcode': '12345',
178
+ 'paon': '1A',
179
+ 'uprn': '100012345',
180
+ 'usrn': '200012345',
181
+ 'web_driver': 'mocked_web_driver',
182
+ 'skip_get_url': True,
183
+ }
184
+
185
+ # Call the method being tested on the instance
186
+ obj.update_dev_mode_data(council_module_str, this_url, **kwargs)
187
+
188
+ # Verify that input.json was created in the correct location
189
+ input_file_path = os.path.join(mock_cwd, "uk_bin_collection", "tests", "input.json")
190
+ assert os.path.exists(input_file_path)
191
+
192
+ # Read the contents of the file and make necessary assertions
193
+ with open(input_file_path, 'r') as f:
194
+ file_content = f.read()
195
+
196
+ # Example assertion - check if certain values exist in the file content (based on your actual file format)
197
+ assert '100012345' in file_content # Checking UPRN as an example
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uk_bin_collection
3
- Version: 0.85.5
3
+ Version: 0.85.7
4
4
  Summary: Python Lib to collect UK Bin Data
5
5
  Author: Robert Bradley
6
6
  Author-email: robbrad182@gmail.com
@@ -2,13 +2,14 @@ uk_bin_collection/README.rst,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
2
2
  uk_bin_collection/tests/council_feature_input_parity.py,sha256=DO6Mk4ImYgM5ZCZ-cutwz5RoYYWZRLYx2tr6zIs_9Rc,3843
3
3
  uk_bin_collection/tests/features/environment.py,sha256=VQZjJdJI_kZn08M0j5cUgvKT4k3iTw8icJge1DGOkoA,127
4
4
  uk_bin_collection/tests/features/validate_council_outputs.feature,sha256=SJK-Vc737hrf03tssxxbeg_JIvAH-ddB8f6gU1LTbuQ,251
5
- uk_bin_collection/tests/input.json,sha256=VahhxxLYSXAux-pD0P_orlSLSEPyQ-kpcenaeXls0Js,59700
5
+ uk_bin_collection/tests/input.json,sha256=mhfscmGyBmckPef5PwBNFLus437GxD8E6WBlKxhzY5I,59728
6
6
  uk_bin_collection/tests/output.schema,sha256=ZwKQBwYyTDEM4G2hJwfLUVM-5v1vKRvRK9W9SS1sd18,1086
7
7
  uk_bin_collection/tests/step_defs/step_helpers/file_handler.py,sha256=Ygzi4V0S1MIHqbdstUlIqtRIwnynvhu4UtpweJ6-5N8,1474
8
8
  uk_bin_collection/tests/step_defs/test_validate_council.py,sha256=LrOSt_loA1Mw3vTqaO2LpaDMu7rYJy6k5Kr-EOBln7s,3424
9
- uk_bin_collection/tests/test_collect_data.py,sha256=cZjz4XUe5zaWCDJK96p2p7EC9GWrmT15ooFFx6mlP1Q,4776
9
+ uk_bin_collection/tests/test_collect_data.py,sha256=xit4lopMGXb5g2faCK9VrOjHl81QDV9sZAu7vBdr2Uw,2253
10
10
  uk_bin_collection/tests/test_common_functions.py,sha256=WRm7AYI9qaDqW0dNROTFh-KZRdNFhhYHvjrFZUN4IPs,14084
11
11
  uk_bin_collection/tests/test_conftest.py,sha256=GWqP6-fCv5A2VUYiyXqUO-Dm0hlUOwbFgfi6CkdGqvQ,1061
12
+ uk_bin_collection/tests/test_get_data.py,sha256=tQGyuTR8pZvnwzVsDqFhUrFtBeMP11eRnWD4Xq-mF-U,7181
12
13
  uk_bin_collection/uk_bin_collection/collect_data.py,sha256=dB7wWXsJX4fm5bIf84lexkvHIcO54CZ3JPxqmS-60YY,4654
13
14
  uk_bin_collection/uk_bin_collection/common.py,sha256=oZQW8CYRGfbhNSyq7t7jEhrFl1tjb4H157xSx8QHWSY,10106
14
15
  uk_bin_collection/uk_bin_collection/councils/AdurAndWorthingCouncils.py,sha256=ppbrmm-MzB1wOulK--CU_0j4P-djNf3ozMhHnmQFqLo,1511
@@ -185,8 +186,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
185
186
  uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=4s9ODGPAwPqwXc8SrTX5Wlfmizs3_58iXUtHc4Ir86o,1162
186
187
  uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
187
188
  uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
188
- uk_bin_collection-0.85.5.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
189
- uk_bin_collection-0.85.5.dist-info/METADATA,sha256=G7stCdHgn58f50RCOAtx0YIs9vFto9YHNZR1nLQXUQY,16231
190
- uk_bin_collection-0.85.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
191
- uk_bin_collection-0.85.5.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
192
- uk_bin_collection-0.85.5.dist-info/RECORD,,
189
+ uk_bin_collection-0.85.7.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
190
+ uk_bin_collection-0.85.7.dist-info/METADATA,sha256=QaL1Kok_IeZ67sAPpPQQBarqR_SHff1CY-3HPMTuoIM,16231
191
+ uk_bin_collection-0.85.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
192
+ uk_bin_collection-0.85.7.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
193
+ uk_bin_collection-0.85.7.dist-info/RECORD,,