From 8d031d425c7e615628ad7b6c7808af3a3d0c5d44 Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:42:58 -0400 Subject: [PATCH 01/10] add mypy type checking --- .github/workflows/python.yml | 58 ++++++++++++++++++++++++++++++++---- pyproject.toml | 1 + 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index afb5194f..9f99e17b 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -75,9 +75,6 @@ jobs: runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf with: @@ -114,7 +111,6 @@ jobs: runs-on: ubuntu-latest permissions: - pull-requests: write security-events: write steps: @@ -159,6 +155,56 @@ jobs: run: | ruff check --output-format=github . + mypy: + name: Mypy type checking + + runs-on: ubuntu-latest + + permissions: + security-events: write + + steps: + - uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 + with: + python-version: '3.13' + cache: pip + + - uses: install-pinned/uv@5e770af195bb60f7bafe5430e7c5045bc2894b2a + + - run: uv pip install --system -e .[dev] + + - id: cache-mypy + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 + with: + path: .mypy_cache + key: ${{ runner.os }}-mypy-3.13-${{ hashFiles('pyproject.toml') }} + + - id: run-mypy-sarif + run: | + mypy . --output json + + - uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 + if: ( success() || failure() ) && contains('["success", "failure"]', steps.run-mypy-sarif.outcome) + with: + sarif_file: results.sarif + + - id: run-mypy + if: failure() && contains('["failure"]', steps.run-mypy-sarif.outcome) + run: | + mypy . + bandit: name: Bandit security @@ -190,7 +236,7 @@ jobs: - run: uv pip install --system -e .[dev] - id: run-bandit-sarif - run: > + run: | bandit --confidence-level 'medium' --format 'sarif' --output 'results.sarif' --recursive 'requestium' - uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 @@ -200,7 +246,7 @@ jobs: - id: run-bandit if: failure() && contains('["failure"]', steps.run-bandit-sarif.outcome) - run: > + run: | bandit --confidence-level 'medium' --recursive 'requestium' coverage: diff --git a/pyproject.toml b/pyproject.toml index 3169463d..41054bea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ issues = "https://github.com/tryolabs/requestium/issues" dev = [ "bandit[sarif]==1.8.3", "coverage==7.8.0", + "mypy==1.15.0", "pre-commit==4.2.0", "pytest-cov==6.1.1", "pytest-xdist==3.6.1", From f21d3443bd400a6c492de980c5bbb3fdfbbe1a87 Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:43:17 -0400 Subject: [PATCH 02/10] sort imports --- requestium/requestium.py | 8 +++++--- requestium/requestium_mixin.py | 1 + requestium/requestium_session.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/requestium/requestium.py b/requestium/requestium.py index ba067568..3d8b2e73 100644 --- a/requestium/requestium.py +++ b/requestium/requestium.py @@ -1,4 +1,6 @@ -from .requestium_session import Session # noqa: F401 +from .requestium_mixin import ( # noqa: F401 + DriverMixin, # noqa: F401 + _ensure_click, # noqa: F401 +) # noqa: F401 from .requestium_response import RequestiumResponse # noqa: F401 -from .requestium_mixin import DriverMixin # noqa: F401 -from .requestium_mixin import _ensure_click # noqa: F401 +from .requestium_session import Session # noqa: F401 diff --git a/requestium/requestium_mixin.py b/requestium/requestium_mixin.py index d5a39422..65a356ce 100644 --- a/requestium/requestium_mixin.py +++ b/requestium/requestium_mixin.py @@ -7,6 +7,7 @@ from parsel.selector import Selector, SelectorList from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By +from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.ui import WebDriverWait diff --git a/requestium/requestium_session.py b/requestium/requestium_session.py index 2b754977..03c6f658 100644 --- a/requestium/requestium_session.py +++ b/requestium/requestium_session.py @@ -3,9 +3,9 @@ from typing import Any, Optional import requests +import tldextract from selenium import webdriver from selenium.common import InvalidCookieDomainException -import tldextract from selenium.webdriver import ChromeService from .requestium_mixin import DriverMixin From 9748634da317ec61687a4da5252722ea29bf989e Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:43:38 -0400 Subject: [PATCH 03/10] inherit RemoteWebDriver to DriverMixin --- requestium/requestium_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requestium/requestium_mixin.py b/requestium/requestium_mixin.py index 65a356ce..78b1c6e9 100644 --- a/requestium/requestium_mixin.py +++ b/requestium/requestium_mixin.py @@ -13,7 +13,7 @@ from selenium.webdriver.support.ui import WebDriverWait -class DriverMixin: +class DriverMixin(RemoteWebDriver): """Provides helper methods to our driver classes""" def __init__(self, *args, **kwargs) -> None: From 09e49d44a7884775e7cdfbce11dfd7709d4977bd Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:43:59 -0400 Subject: [PATCH 04/10] only catch WebDriverException if message matches in try_add_cookie --- requestium/requestium_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requestium/requestium_mixin.py b/requestium/requestium_mixin.py index 78b1c6e9..d4e01e87 100644 --- a/requestium/requestium_mixin.py +++ b/requestium/requestium_mixin.py @@ -27,7 +27,7 @@ def try_add_cookie(self, cookie) -> bool: try: self.add_cookie(cookie) except WebDriverException as e: - if not e.msg.__contains__("Couldn't add the following cookie to the webdriver"): + if e.msg and not e.msg.__contains__("Couldn't add the following cookie to the webdriver"): raise WebDriverException from e pass return self.is_cookie_in_driver(cookie) From 615c9fc12f49b7903026ff45fa3ed683f793dd06 Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:44:19 -0400 Subject: [PATCH 05/10] missing session type hints --- requestium/requestium_session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requestium/requestium_session.py b/requestium/requestium_session.py index 03c6f658..7bbb8f19 100644 --- a/requestium/requestium_session.py +++ b/requestium/requestium_session.py @@ -31,7 +31,7 @@ def __init__( headless: Optional[bool] = None, default_timeout: float = 5, webdriver_options: Optional[dict[str, Any]] = None, - driver=None, + driver: Optional[DriverMixin] = None, ) -> None: super().__init__() @@ -42,7 +42,7 @@ def __init__( self.default_timeout = default_timeout self.webdriver_options = webdriver_options self._driver = driver - self._last_requests_url = None + self._last_requests_url: Optional[str] = None if not self._driver: self._driver_initializer = functools.partial(self._start_chrome_browser, headless=headless) From 2e115bcab0332ba91b5863561decc1ce11243e0c Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:44:35 -0400 Subject: [PATCH 06/10] ensure domain always exists in transfer_session_cookies_to_driver --- requestium/requestium_session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requestium/requestium_session.py b/requestium/requestium_session.py index 7bbb8f19..4dab4ca7 100644 --- a/requestium/requestium_session.py +++ b/requestium/requestium_session.py @@ -113,7 +113,8 @@ def transfer_session_cookies_to_driver(self, domain: Optional[str] = None) -> No """ if not domain and self._last_requests_url: domain = tldextract.extract(self._last_requests_url).registered_domain - elif not domain and not self._last_requests_url: + + if not domain: raise InvalidCookieDomainException( "Trying to transfer cookies to selenium without specifying a domain and without having visited any page in the current session" ) From ab1b0f951ac95bb122ce81858730f34c80884c9c Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:45:10 -0400 Subject: [PATCH 07/10] ignore dynamic addition of ensure_click to WebElements returned by ensure_element --- requestium/requestium_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requestium/requestium_mixin.py b/requestium/requestium_mixin.py index d4e01e87..198a365f 100644 --- a/requestium/requestium_mixin.py +++ b/requestium/requestium_mixin.py @@ -176,7 +176,7 @@ def ensure_element(self, locator: str, selector: str, state: str = "present", ti # sometimes needs some time before it can click an item, specially if it needs to # scroll into it first. This method ensures clicks don't fail because of this. if element: - element.ensure_click = functools.partial(_ensure_click, element) + element.ensure_click = functools.partial(_ensure_click, element) # type: ignore[attr-defined] return element @property From 517624f4965d079511032b3b57081a2cb93cef41 Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:46:51 -0400 Subject: [PATCH 08/10] add types-requests to dev extras --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 41054bea..b0ebd62b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ dev = [ "pytest-xdist==3.6.1", "pytest==8.3.5", "ruff==0.11.5", + "types-requests==2.32.0.20250328", ] [tool.ruff] From 7191c10b4e4d423a92407e673e5e0212dcebdd07 Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:50:55 -0400 Subject: [PATCH 09/10] save mypy json output to sarif file in workflow --- .github/workflows/python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 9f99e17b..0cf057b6 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -193,7 +193,7 @@ jobs: - id: run-mypy-sarif run: | - mypy . --output json + mypy . --output=json > results.sarif - uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 if: ( success() || failure() ) && contains('["success", "failure"]', steps.run-mypy-sarif.outcome) From e2f1d09141e54260e66f6ab70d88ba21d85a7d3f Mon Sep 17 00:00:00 2001 From: Wil T Date: Sun, 20 Apr 2025 11:53:08 -0400 Subject: [PATCH 10/10] don't use mypy json output --- .github/workflows/python.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 0cf057b6..c6b0aa96 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -160,9 +160,6 @@ jobs: runs-on: ubuntu-latest - permissions: - security-events: write - steps: - uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf with: @@ -191,17 +188,7 @@ jobs: path: .mypy_cache key: ${{ runner.os }}-mypy-3.13-${{ hashFiles('pyproject.toml') }} - - id: run-mypy-sarif - run: | - mypy . --output=json > results.sarif - - - uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 - if: ( success() || failure() ) && contains('["success", "failure"]', steps.run-mypy-sarif.outcome) - with: - sarif_file: results.sarif - - id: run-mypy - if: failure() && contains('["failure"]', steps.run-mypy-sarif.outcome) run: | mypy .