simple-http-checker-new 1.1.1__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 umuttekin2000
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.4
2
+ Name: simple-http-checker-new
3
+ Version: 1.1.1
4
+ Summary: A simple CLI tool to check the status of URLs.
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: requests<3.0,>=2.28
9
+ Requires-Dist: click<9.0,>=8.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest; extra == "dev"
12
+ Requires-Dist: pytest-mock; extra == "dev"
13
+ Requires-Dist: ruff; extra == "dev"
14
+ Requires-Dist: black; extra == "dev"
15
+ Requires-Dist: mypy; extra == "dev"
16
+ Requires-Dist: bandit; extra == "dev"
17
+ Requires-Dist: types-requests; extra == "dev"
18
+ Dynamic: license-file
19
+
20
+ # python-ci-cd-project
21
+ This repo contains the code for the CI/CD section of my Python project.
22
+
23
+ ## What i implement in this repository
24
+
25
+ [x] The project (code files)
26
+ [x] Add a simple GHA workflow
27
+ [x] Add linting(ruff) and format checks(black)
28
+ [x] Add typing(mypy) and security checks(bandit)
29
+ [x] Add test automation
30
+ [x] Build Python project
31
+ [] Publish the project to both TestPyPi and PyPi when new tag pushed
@@ -0,0 +1,12 @@
1
+ # python-ci-cd-project
2
+ This repo contains the code for the CI/CD section of my Python project.
3
+
4
+ ## What i implement in this repository
5
+
6
+ [x] The project (code files)
7
+ [x] Add a simple GHA workflow
8
+ [x] Add linting(ruff) and format checks(black)
9
+ [x] Add typing(mypy) and security checks(bandit)
10
+ [x] Add test automation
11
+ [x] Build Python project
12
+ [] Publish the project to both TestPyPi and PyPi when new tag pushed
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "simple-http-checker-new"
7
+ version = "1.1.1"
8
+ description = "A simple CLI tool to check the status of URLs."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "requests>=2.28,<3.0",
13
+ "click>=8.0,<9.0",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ dev = [
18
+ "pytest",
19
+ "pytest-mock",
20
+ "ruff",
21
+ "black",
22
+ "mypy",
23
+ "bandit",
24
+ "types-requests"
25
+ ]
26
+
27
+ [project.scripts]
28
+ check-urls = "simple_http_checker.cli:main"
29
+
30
+ [tool.ruff]
31
+ line-length = 88
32
+
33
+ [tool.black]
34
+ line-length = 88
35
+
36
+ [tool.mypy]
37
+ warn_return_any = true
38
+ warn_unused_configs = true
39
+ ignore_missing_imports = true
40
+
41
+ [tool.bandit]
42
+ exclude_dirs = [".venv", "__pycache__", "build", "dist"]
43
+ skips = ["B101"]
44
+
45
+ [tool.pytest.ini-options]
46
+ addopts = "-rA -s -v"
47
+
48
+ [tool.semantic_release]
49
+ version_toml = ["pyproject.toml:project.version"]
50
+ build_command = "pip install build && python -m build"
51
+ dist_path = "dist/"
52
+ commit_message = "chore(release): {version} [skip ci]"
53
+
54
+ [tool.semantic_release.publish]
55
+ dist_glob_patterns = ["dist/*"]
56
+ upload_to_vcs_release = true
57
+
58
+ [tool.semantic_release.branches.main]
59
+ match = "main"
60
+ prerelease = false
61
+
62
+ [tool.semantic_release.changelog.default_templates]
63
+ changelog_file = "CHANGELOG.md"
64
+
65
+ [tool.semantic_release.commit_parser_options]
66
+ allowed_tags = [
67
+ "build",
68
+ "chore",
69
+ "ci",
70
+ "docs",
71
+ "feat",
72
+ "fix",
73
+ "perf",
74
+ "style",
75
+ "refactor",
76
+ "test"
77
+ ]
78
+ minor_tags = ["feat"]
79
+ patch_tags = ["fix", "perf"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,46 @@
1
+ import logging
2
+
3
+ import requests
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+
8
+ def check_urls(urls: list[str], timeout: int = 5) -> dict[str, str]:
9
+ """
10
+ Check the status of a list of URLs.
11
+
12
+ Args:
13
+ urls (List[str]): A list of URLs to check.
14
+ timeout (int): The timeout for the HTTP request in seconds.
15
+
16
+ Returns:
17
+ Dict[str, str]: A dictionary with URLs as keys and their status codes as values.
18
+ """
19
+ logger.info(f"Checking {len(urls)} URLs with a timeout of {timeout} seconds.")
20
+
21
+ results: dict[str, str] = {}
22
+
23
+ for url in urls:
24
+ status: str = "Unknown"
25
+ try:
26
+ logger.debug(f"Checking URL: {url}")
27
+ response = requests.get(url, timeout=timeout)
28
+
29
+ if response.ok:
30
+ status = f"{response.status_code} OK"
31
+ else:
32
+ status = f"{response.status_code} {response.reason}"
33
+ except requests.exceptions.Timeout:
34
+ status = "Timeout"
35
+ logger.warning(f"Request to {url} timed out.")
36
+ except requests.exceptions.ConnectionError:
37
+ status = "Connection Error"
38
+ logger.warning(f"Connection error occurred while checking {url}.")
39
+ except requests.exceptions.RequestException as e:
40
+ status = f"Request Error: {type(e).__name__}"
41
+ logger.exception(f"An expected request error occurred while checking {url}")
42
+ results[url] = status
43
+ logger.debug(f"Checked URL: {url:<40} -> {status}")
44
+
45
+ logger.info("URL checking completed.")
46
+ return results
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from collections.abc import (
3
+ Collection, # Collection is used to type hint the urls argument in the main function
4
+ )
5
+
6
+ import click
7
+
8
+ from simple_http_checker.checker import check_urls # Adjust import path if needed
9
+
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format="%(asctime)s - %(levelname)-8s - %(message)s",
13
+ datefmt="%Y-%m-%d %H:%M:%S",
14
+ )
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @click.command()
20
+ @click.argument("urls", nargs=-1)
21
+ @click.option("--timeout", default=5, help="Timeout for the HTTP request in seconds.")
22
+ @click.option(
23
+ "-v", "--verbose", is_flag=True, help="Enable debug logging."
24
+ ) # Note '-v' instead of "v"
25
+ def main(urls: Collection[str], timeout: int, verbose: bool):
26
+ if verbose:
27
+ logging.getLogger().setLevel(logging.DEBUG)
28
+ logger.debug("Verbose mode enabled. Debug logging is active.")
29
+
30
+ if not urls:
31
+ logger.error("No URLs provided. Please provide at least one URL to check.")
32
+ click.echo("Error: No URLs provided. Please provide at least one URL to check.")
33
+ return
34
+
35
+ logger.info(
36
+ f"Starting check for {len(urls)} URLs with a timeout of {timeout} seconds."
37
+ )
38
+ logger.info(f"Received urls: {urls}")
39
+ logger.info(f"Received timeout: {timeout}")
40
+ logger.info(f"Received verbose flag: {verbose}")
41
+
42
+ if urls:
43
+ results = check_urls(list(urls), timeout=timeout)
44
+ for url, status in results.items():
45
+ if "OK" in status:
46
+ fg_color = "green"
47
+ elif "Timeout" in status:
48
+ fg_color = "yellow"
49
+ else:
50
+ fg_color = "red"
51
+ click.echo(
52
+ click.style(f"{url:<40} -> {status}", fg=fg_color)
53
+ ) # Color the output based on status
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main() # Default entry point for the CLI
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.4
2
+ Name: simple-http-checker-new
3
+ Version: 1.1.1
4
+ Summary: A simple CLI tool to check the status of URLs.
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: requests<3.0,>=2.28
9
+ Requires-Dist: click<9.0,>=8.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest; extra == "dev"
12
+ Requires-Dist: pytest-mock; extra == "dev"
13
+ Requires-Dist: ruff; extra == "dev"
14
+ Requires-Dist: black; extra == "dev"
15
+ Requires-Dist: mypy; extra == "dev"
16
+ Requires-Dist: bandit; extra == "dev"
17
+ Requires-Dist: types-requests; extra == "dev"
18
+ Dynamic: license-file
19
+
20
+ # python-ci-cd-project
21
+ This repo contains the code for the CI/CD section of my Python project.
22
+
23
+ ## What i implement in this repository
24
+
25
+ [x] The project (code files)
26
+ [x] Add a simple GHA workflow
27
+ [x] Add linting(ruff) and format checks(black)
28
+ [x] Add typing(mypy) and security checks(bandit)
29
+ [x] Add test automation
30
+ [x] Build Python project
31
+ [] Publish the project to both TestPyPi and PyPi when new tag pushed
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/simple_http_checker/__init__.py
5
+ src/simple_http_checker/checker.py
6
+ src/simple_http_checker/cli.py
7
+ src/simple_http_checker_new.egg-info/PKG-INFO
8
+ src/simple_http_checker_new.egg-info/SOURCES.txt
9
+ src/simple_http_checker_new.egg-info/dependency_links.txt
10
+ src/simple_http_checker_new.egg-info/entry_points.txt
11
+ src/simple_http_checker_new.egg-info/requires.txt
12
+ src/simple_http_checker_new.egg-info/top_level.txt
13
+ tests/test_checker.py
14
+ tests/test_cli.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ check-urls = simple_http_checker.cli:main
@@ -0,0 +1,11 @@
1
+ requests<3.0,>=2.28
2
+ click<9.0,>=8.0
3
+
4
+ [dev]
5
+ pytest
6
+ pytest-mock
7
+ ruff
8
+ black
9
+ mypy
10
+ bandit
11
+ types-requests
@@ -0,0 +1,131 @@
1
+ import pytest
2
+ import requests
3
+ from pytest_mock import MockerFixture
4
+
5
+ from simple_http_checker.checker import check_urls
6
+
7
+
8
+ def test_check_urls_success(mocker: MockerFixture):
9
+ # Mock the requests.get method to simulate a successful response
10
+ mocker_requests_get = mocker.patch("simple_http_checker.checker.requests.get")
11
+
12
+ mock_response = mocker.MagicMock(spec=requests.Response)
13
+ mock_response.status_code = 200
14
+ mock_response.reason = "OK"
15
+ mock_response.ok = True
16
+ mocker_requests_get.return_value = mock_response
17
+
18
+ urls = ["http://example.com"]
19
+ results = check_urls(urls)
20
+
21
+ mocker_requests_get.assert_called_once_with("http://example.com", timeout=5)
22
+
23
+ assert results == {"http://example.com": "200 OK"}
24
+
25
+
26
+ def test_check_urls_client_error(mocker: MockerFixture):
27
+ # Mock the requests.get method to simulate a connection error
28
+ mocker_requests_get = mocker.patch("simple_http_checker.checker.requests.get")
29
+
30
+ mock_response = mocker.MagicMock(spec=requests.Response)
31
+ mock_response.status_code = 404
32
+ mock_response.reason = "Not Found"
33
+ mock_response.ok = False
34
+ mocker_requests_get.return_value = mock_response
35
+
36
+ urls = ["http://example.com/nonexistent"]
37
+ results = check_urls(urls)
38
+
39
+ mocker_requests_get.assert_called_once_with(
40
+ "http://example.com/nonexistent", timeout=5
41
+ )
42
+
43
+ assert results == {"http://example.com/nonexistent": "404 Not Found"}
44
+
45
+
46
+ @pytest.mark.parametrize(
47
+ "error_exception, expected_status",
48
+ [
49
+ (requests.exceptions.Timeout, "Timeout"),
50
+ (requests.exceptions.ConnectionError, "Connection Error"),
51
+ (requests.exceptions.RequestException, "Request Error: RequestException"),
52
+ ],
53
+ )
54
+ def test_check_urls_request_exception(
55
+ mocker: MockerFixture,
56
+ error_exception: type[requests.RequestException],
57
+ expected_status: str,
58
+ ):
59
+ mocker_requests_get = mocker.patch("simple_http_checker.checker.requests.get")
60
+ mocker_requests_get.side_effect = error_exception(
61
+ f"Simulated {expected_status} for testing"
62
+ )
63
+
64
+ urls = ["http://problem.com"]
65
+ results = check_urls(urls)
66
+
67
+ mocker_requests_get.assert_called_once_with("http://problem.com", timeout=5)
68
+
69
+ assert results == {"http://problem.com": f"{expected_status}"}
70
+ assert results[urls[0]] == expected_status
71
+
72
+
73
+ def test_check_urls_multiple_urls(mocker: MockerFixture):
74
+ # Mock the requests.get method to simulate different responses for multiple URLs
75
+ mocker_requests_get = mocker.patch("simple_http_checker.checker.requests.get")
76
+
77
+ def side_effect(url: str, timeout: int):
78
+ mock_response = mocker.MagicMock(spec=requests.Response)
79
+ if url == "http://example.com":
80
+ mock_response.status_code = 200
81
+ mock_response.reason = "OK"
82
+ mock_response.ok = True
83
+ elif url == "http://example.com/timeout":
84
+ raise requests.exceptions.Timeout("Simulated timeout for testing")
85
+ elif url == "http://example.com/error":
86
+ raise requests.exceptions.ConnectionError(
87
+ "Simulated connection error for testing"
88
+ )
89
+ return mock_response
90
+
91
+ mocker_requests_get.side_effect = side_effect
92
+
93
+ urls = [
94
+ "http://example.com",
95
+ "http://example.com/timeout",
96
+ "http://example.com/error",
97
+ ]
98
+ results = check_urls(urls)
99
+
100
+ assert results == {
101
+ "http://example.com": "200 OK",
102
+ "http://example.com/timeout": "Timeout",
103
+ "http://example.com/error": "Connection Error",
104
+ }
105
+
106
+
107
+ def test_check_urls_empty_list():
108
+ urls: list[str] = []
109
+ results = check_urls(urls)
110
+ assert results == {}
111
+
112
+
113
+ def test_check_urls_custom_timeout(mocker: MockerFixture):
114
+ # Mock the requests.get method to simulate a successful response
115
+ mocker_requests_get = mocker.patch("simple_http_checker.checker.requests.get")
116
+
117
+ mock_response = mocker.MagicMock(spec=requests.Response)
118
+ mock_response.status_code = 200
119
+ mock_response.reason = "OK"
120
+ mock_response.ok = True
121
+ mocker_requests_get.return_value = mock_response
122
+
123
+ urls = ["http://example.com"]
124
+ custom_timeout = 10
125
+ results = check_urls(urls, timeout=custom_timeout)
126
+
127
+ mocker_requests_get.assert_called_once_with(
128
+ "http://example.com", timeout=custom_timeout
129
+ )
130
+
131
+ assert results == {"http://example.com": "200 OK"}
@@ -0,0 +1,26 @@
1
+ from click.testing import CliRunner
2
+ from pytest_mock import MockerFixture
3
+
4
+ from simple_http_checker.cli import main
5
+
6
+
7
+ def test_cli_no_urls():
8
+ runner = CliRunner()
9
+ result = runner.invoke(main, [])
10
+ assert result.exit_code == 0
11
+ assert "Error: No URLs provided" in result.output
12
+
13
+
14
+ def test_cli_single_url(mocker: MockerFixture):
15
+ # Mock the check_urls function to return a predefined result
16
+ mocker.patch(
17
+ "simple_http_checker.cli.check_urls",
18
+ return_value={"http://example.com": "200 OK"},
19
+ )
20
+
21
+ runner = CliRunner()
22
+ result = runner.invoke(main, ["http://example.com"])
23
+
24
+ assert result.exit_code == 0
25
+ assert "http://example.com" in result.output
26
+ assert "200 OK" in result.output