From f9cddbbf081ddc72fe7e4882716dea42e9dc4e41 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Mon, 1 Dec 2025 11:57:11 -0500 Subject: [PATCH 1/9] update development dependencies --- .github/dependabot.yml | 3 ++- .pre-commit-config.yaml | 15 +++++------ pyproject.toml | 58 ++++++++++++++++++++--------------------- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c5a3f8b..e02bcb3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,8 +10,9 @@ updates: schedule: interval: monthly ignore: - - dependency-name: ruff - dependency-name: bandit + - dependency-name: ruff + - dependency-name: ssort - package-ecosystem: github-actions directory: / diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cfc3703..1e9d8e6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: 'v5.0.0' + rev: 'v6.0.0' hooks: - id: check-yaml - id: check-ast @@ -13,19 +13,18 @@ repos: - id: check-toml - id: debug-statements - id: mixed-line-ending - - repo: https://github.com/asottile/pyupgrade - rev: 'v3.19.1' + - repo: https://github.com/bwhmather/ssort + rev: 0.15.0 hooks: - - id: pyupgrade - args: ['--py39-plus'] + - id: ssort - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 'v0.11.11' + rev: 'v0.14.7' hooks: - id: ruff - id: ruff-format - repo: https://github.com/PyCQA/bandit - rev: '1.8.3' + rev: '1.9.2' hooks: - id: bandit args: ['--confidence-level', 'medium'] - files: '^requestium' \ No newline at end of file + files: '^src' diff --git a/pyproject.toml b/pyproject.toml index 3af7a64..c35a24e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "requestium" version = "0.5.0" readme = { file = "README.md", content-type = "text/markdown" } -requires-python = ">=3.9" +requires-python = ">=3.10" license = { file = "LICENSE" } authors = [ { name = "Joaquin Alori", email = "joaquin@tryolabs.com" } @@ -11,12 +11,6 @@ maintainers = [ { name = "Judson Neer", email = "jkudson.neer@gmail.com" }, { name = "Wil T", email = "wil.t.me@pm.me" }, ] -dependencies = [ - "parsel>=1.0", - "requests>=2.0", - "selenium>=4.0", - "tldextract>=5.3", -] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -36,6 +30,12 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", ] +dependencies = [ + "parsel>=1.0", + "requests>=2.0", + "selenium>=4.0", + "tldextract>=5.3", +] [project.urls] source = "https://github.com/tryolabs/requestium" @@ -44,20 +44,21 @@ issues = "https://github.com/tryolabs/requestium/issues" [project.optional-dependencies] dev = [ - "bandit[sarif]==1.8.3", - "coverage==7.10.7", - "mypy==1.18.2", - "pre-commit==4.3.0", - "pytest-cov==7.0.0", - "pytest-xdist==3.8.0", - "pytest==8.4.2", - "ruff==0.11.11", + "bandit[sarif]==1.9.2", + "mypy~=1.18.0", + "pre-commit~=4.5.0", + "pytest-cov~=7.0.0", + "pytest-xdist~=3.8.0", + "pytest~=9.0.0", + "ruff==0.14.7", + "ssort==0.15.0", "types-requests==2.32.4.20250913", ] +[tool] + [tool.ruff] line-length = 160 -target-version = "py39" include = [ "requestium/**/*.py", "tests/**/*.py", @@ -90,6 +91,7 @@ extend-select = [ "LOG", # flake8-logging (LOG) "N", # pep8-naming (N) "PIE", # flake8-pie (PIE) + "PL", # Pylint (PL) "PT", # flake8-pytest-style (PT) "PTH", # flake8-use-pathlib (PTH) "Q", # flake8-quotes (Q) @@ -121,28 +123,24 @@ ignore = [ ] [tool.ruff.lint.per-file-ignores] -"**/{tests,docs}/*" = ["SLF001"] +"**/{tests,docs}/*" = [ + "SLF001", # private-member-access (SLF001) + "PLR2004", # magic-value-comparison (PLR2004) +] -[tool.pytest.ini_options] -addopts = "--cov=requestium -n auto" +[tool.pytest] +addopts = ["-n", "auto", "--cov=requestium", "--no-cov-on-fail"] testpaths = [ - "tests/", + "tests", ] +[tool.coverage] + [tool.coverage.run] branch = true relative_files = true -command_line = "-m pytest" - -[tool.coverage.paths] -source = [ - "requestium/", -] -omit = [ - "tests/", -] [tool.coverage.report] exclude_also = [ - "logger.", + "logger\\.", ] From e927c57b9bb29fa761846b46a45b140af530003c Mon Sep 17 00:00:00 2001 From: Ramona T Date: Mon, 1 Dec 2025 11:59:07 -0500 Subject: [PATCH 2/9] update python checks workflow --- .github/workflows/python.yml | 59 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 2051947..a250dc9 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -13,7 +13,7 @@ on: permissions: read-all jobs: - test: + pytest: name: Pytest testing runs-on: ${{ matrix.os }} @@ -21,11 +21,11 @@ jobs: fail-fast: false matrix: python-version: - - '3.9' - '3.10' - '3.11' - '3.12' - '3.13' + - '3.14' os: - ubuntu-latest - windows-latest @@ -35,19 +35,19 @@ jobs: contents: write steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: false egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: ${{ matrix.python-version }} cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -57,8 +57,7 @@ jobs: path: .pytest_cache key: ${{ runner.os }}-pytest-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} - - name: Run pytest (with headless support) - uses: GabrielBB/xvfb-action@5bcda06da84ba084708898801da79736b88e00a9 + - uses: GabrielBB/xvfb-action@5bcda06da84ba084708898801da79736b88e00a9 env: COVERAGE_FILE: .coverage.${{ runner.os }}.${{ matrix.python-version }} with: @@ -76,7 +75,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -85,14 +84,14 @@ jobs: github.com:443 pypi.org:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: '3.13' cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -114,7 +113,7 @@ jobs: security-events: write steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -124,14 +123,14 @@ jobs: github.com:443 pypi.org:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: '3.13' cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -145,7 +144,7 @@ jobs: run: | ruff check --output-format=sarif -o results.sarif . - - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee + - uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b if: ( success() || failure() ) && contains('["success", "failure"]', steps.run-ruff-sarif.outcome) with: sarif_file: results.sarif @@ -161,7 +160,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -171,14 +170,14 @@ jobs: github.com:443 pypi.org:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: '3.13' cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -201,7 +200,7 @@ jobs: security-events: write steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -211,14 +210,14 @@ jobs: github.com:443 pypi.org:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: '3.13' cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -226,7 +225,7 @@ jobs: run: | bandit --confidence-level 'medium' --format 'sarif' --output 'results.sarif' --recursive 'requestium' - - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee + - uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b if: ( success() || failure() ) && contains('["success", "failure"]', steps.run-bandit-sarif.outcome) with: sarif_file: results.sarif @@ -238,12 +237,12 @@ jobs: coverage: runs-on: ubuntu-latest - needs: test + needs: pytest permissions: pull-requests: write contents: write steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -252,16 +251,16 @@ jobs: github.com:443 img.shields.io:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: pattern: coverage-* merge-multiple: true - name: Coverage comment id: coverage_comment - uses: py-cov-action/python-coverage-comment-action@91aaf3b39c7e2331c6bc77767ce017f5160c5f11 + uses: py-cov-action/python-coverage-comment-action@e623398c19eb3853a5572d4a516e10b15b5cefbc with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MERGE_COVERAGE_FILES: true @@ -283,7 +282,7 @@ jobs: contents: write steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -293,14 +292,14 @@ jobs: proxy.golang.org:443 pypi.org:443 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c with: python-version: '3.13' cache: pip - - uses: install-pinned/uv@3863536aec631cbd0a0d99cc91d32d06292bcb93 + - uses: install-pinned/uv@3b52ff50f07de12f5ebcdd31d078466611a008a6 - run: uv pip install --system -e .[dev] @@ -308,7 +307,7 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: path: .pre-commit-cache - key: ${{ runner.os }}-pre-commit-3.13 + key: ${{ runner.os }}-pre-commit-3.13-${{ hashFiles('.pre-commit-config.yaml') }} - name: Run pre-commit on all files run: | From 2165533482924f1842d0b022b79a4b7658f5b36a Mon Sep 17 00:00:00 2001 From: Ramona T Date: Mon, 1 Dec 2025 11:59:17 -0500 Subject: [PATCH 3/9] sort functions and methods --- requestium/requestium_mixin.py | 78 ++++++++++++++++---------------- requestium/requestium_session.py | 74 +++++++++++++++--------------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/requestium/requestium_mixin.py b/requestium/requestium_mixin.py index c627496..3c9818c 100644 --- a/requestium/requestium_mixin.py +++ b/requestium/requestium_mixin.py @@ -20,6 +20,45 @@ DEFAULT_TIMEOUT: float = 0.5 +def _ensure_click(self: WebElement) -> None: + """ + Ensure a click gets made, because Selenium can be a bit buggy about clicks. + + This method gets added to the selenium element returned in '__ensure_element_by_xpath'. + We should probably add it to more selenium methods, such as all the 'find**' methods though. + + I wrote this method out of frustration with chromedriver and its problems with clicking + items that need to be scrolled to in order to be clickable. In '__ensure_element_by_xpath' we + scroll to the item before returning it, but chrome has some problems if it doesn't get some + time to scroll to the item. This method ensures chromes gets enough time to scroll to the item + before clicking it. I tried SEVERAL more 'correct' methods to get around this, but none of them + worked 100% of the time (waiting for the element to be 'clickable' does not work). + """ + # We ensure the element is scrolled into the middle of the viewport to ensure that + # it is clickable. There are two main ways an element may not be clickable: + # - It is outside of the viewport + # - It is under a banner or toolbar + # This script solves both cases + script = ( + "var viewPortHeight = Math.max(" + "document.documentElement.clientHeight, window.innerHeight || 0);" + "var elementTop = arguments[0].getBoundingClientRect().top;" + "window.scrollBy(0, elementTop-(viewPortHeight/2));" + ) + self.parent.execute_script(script, self) # parent = the webdriver + + exception_message = "" + for _ in range(10): + try: + self.click() + return + except WebDriverException as e: + exception_message = str(e) + time.sleep(0.2) + msg = f"Couldn't click item after trying 10 times, got error message: \n{exception_message}" + raise WebDriverException(msg) + + class DriverMixin(RemoteWebDriver): """Provides helper methods to our driver classes.""" @@ -214,42 +253,3 @@ def re(self, *args, **kwargs) -> list[str]: def re_first(self, *args, **kwargs) -> str | None: return self.selector.re_first(*args, **kwargs) - - -def _ensure_click(self: WebElement) -> None: - """ - Ensure a click gets made, because Selenium can be a bit buggy about clicks. - - This method gets added to the selenium element returned in '__ensure_element_by_xpath'. - We should probably add it to more selenium methods, such as all the 'find**' methods though. - - I wrote this method out of frustration with chromedriver and its problems with clicking - items that need to be scrolled to in order to be clickable. In '__ensure_element_by_xpath' we - scroll to the item before returning it, but chrome has some problems if it doesn't get some - time to scroll to the item. This method ensures chromes gets enough time to scroll to the item - before clicking it. I tried SEVERAL more 'correct' methods to get around this, but none of them - worked 100% of the time (waiting for the element to be 'clickable' does not work). - """ - # We ensure the element is scrolled into the middle of the viewport to ensure that - # it is clickable. There are two main ways an element may not be clickable: - # - It is outside of the viewport - # - It is under a banner or toolbar - # This script solves both cases - script = ( - "var viewPortHeight = Math.max(" - "document.documentElement.clientHeight, window.innerHeight || 0);" - "var elementTop = arguments[0].getBoundingClientRect().top;" - "window.scrollBy(0, elementTop-(viewPortHeight/2));" - ) - self.parent.execute_script(script, self) # parent = the webdriver - - exception_message = "" - for _ in range(10): - try: - self.click() - return - except WebDriverException as e: - exception_message = str(e) - time.sleep(0.2) - msg = f"Couldn't click item after trying 10 times, got error message: \n{exception_message}" - raise WebDriverException(msg) diff --git a/requestium/requestium_session.py b/requestium/requestium_session.py index 28f710c..c8db805 100644 --- a/requestium/requestium_session.py +++ b/requestium/requestium_session.py @@ -30,43 +30,6 @@ class Session(requests.Session): Some useful helper methods and object wrappings have been added. """ - def __init__( - self, - webdriver_path: str | None = None, - headless: bool | None = None, - default_timeout: float = 5, - webdriver_options: dict[str, Any] | None = None, - driver: DriverMixin | None = None, - ) -> None: - super().__init__() - - if webdriver_options is None: - webdriver_options = {} - - self.webdriver_path = webdriver_path - self.default_timeout = default_timeout - self.webdriver_options = webdriver_options - self._driver = driver - self._last_requests_url: str | None = None - - if not self._driver: - self._driver_initializer = functools.partial(self._start_chrome_browser, headless=headless) - else: - for name in DriverMixin.__dict__: - name_private = name.startswith("__") and name.endswith("__") - name_function = isinstance(DriverMixin.__dict__[name], types.FunctionType) - name_in_driver = name in dir(self._driver) - if name_private or not name_function or name_in_driver: - continue - self._driver.__dict__[name] = DriverMixin.__dict__[name].__get__(self._driver) - self._driver.default_timeout = self.default_timeout - - @property - def driver(self) -> DriverMixin: - if self._driver is None: - self._driver = self._driver_initializer() - return self._driver - def _start_chrome_browser(self, headless: bool | None = False): # noqa C901 # TODO @joaqo: Transfer of proxies and headers. # https://github.com/tryolabs/requestium/issues/96 @@ -109,6 +72,43 @@ def _start_chrome_browser(self, headless: bool | None = False): # noqa C901 service = ChromeService(executable_path=self.webdriver_path) return RequestiumChrome(service=service, options=chrome_options, default_timeout=self.default_timeout) + def __init__( + self, + webdriver_path: str | None = None, + headless: bool | None = None, + default_timeout: float = 5, + webdriver_options: dict[str, Any] | None = None, + driver: DriverMixin | None = None, + ) -> None: + super().__init__() + + if webdriver_options is None: + webdriver_options = {} + + self.webdriver_path = webdriver_path + self.default_timeout = default_timeout + self.webdriver_options = webdriver_options + self._driver = driver + self._last_requests_url: str | None = None + + if not self._driver: + self._driver_initializer = functools.partial(self._start_chrome_browser, headless=headless) + else: + for name in DriverMixin.__dict__: + name_private = name.startswith("__") and name.endswith("__") + name_function = isinstance(DriverMixin.__dict__[name], types.FunctionType) + name_in_driver = name in dir(self._driver) + if name_private or not name_function or name_in_driver: + continue + self._driver.__dict__[name] = DriverMixin.__dict__[name].__get__(self._driver) + self._driver.default_timeout = self.default_timeout + + @property + def driver(self) -> DriverMixin: + if self._driver is None: + self._driver = self._driver_initializer() + return self._driver + def transfer_session_cookies_to_driver(self, domain: str | None = None) -> None: """ Copy the Session's cookies into the webdriver. From e22b579836333139bc30f092a3c42cde004666a1 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Mon, 1 Dec 2025 12:02:26 -0500 Subject: [PATCH 4/9] add more specific warning confirmation in test_deprecation_warning_for_ensure_element_locators_with_underscores --- tests/test_ensure_elements_deprecation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ensure_elements_deprecation.py b/tests/test_ensure_elements_deprecation.py index 431277f..e5c6aa5 100644 --- a/tests/test_ensure_elements_deprecation.py +++ b/tests/test_ensure_elements_deprecation.py @@ -5,5 +5,5 @@ def test_deprecation_warning_for_ensure_element_locators_with_underscores(session: requestium.Session) -> None: session.driver.get("http://the-internet.herokuapp.com") - with pytest.warns(DeprecationWarning): + with pytest.warns(DeprecationWarning, match="Support for locator strategy names with underscores is deprecated"): session.driver.ensure_element("class_name", "no-js") From 5f849dc09732ab165fa6f0191019e62569bf0f46 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Mon, 1 Dec 2025 12:02:50 -0500 Subject: [PATCH 5/9] no more positional args in Session (breaking change) --- requestium/requestium_session.py | 1 + 1 file changed, 1 insertion(+) diff --git a/requestium/requestium_session.py b/requestium/requestium_session.py index c8db805..59acc7d 100644 --- a/requestium/requestium_session.py +++ b/requestium/requestium_session.py @@ -74,6 +74,7 @@ def _start_chrome_browser(self, headless: bool | None = False): # noqa C901 def __init__( self, + *, webdriver_path: str | None = None, headless: bool | None = None, default_timeout: float = 5, From 8d43cb613210259c0f0ebe952930d9c44f8f45d1 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Tue, 2 Dec 2025 00:32:36 -0500 Subject: [PATCH 6/9] update classifiers/maintainer --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c35a24e..a56590d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,17 +9,16 @@ authors = [ ] maintainers = [ { name = "Judson Neer", email = "jkudson.neer@gmail.com" }, - { name = "Wil T", email = "wil.t.me@pm.me" }, ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Natural Language :: English", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", From 03fc352d623a065f853091804b364f9c6eca84be Mon Sep 17 00:00:00 2001 From: Ramona T Date: Tue, 2 Dec 2025 00:37:09 -0500 Subject: [PATCH 7/9] update codeql workflow to fix failing check --- .github/workflows/codeql.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3980b5f..948f83a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,7 +27,7 @@ jobs: - python steps: - - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 with: disable-sudo: true egress-policy: block @@ -36,15 +36,16 @@ jobs: github.com:443 objects.githubusercontent.com:443 uploads.github.com:443 + release-assets.githubusercontent.com - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 - - uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee + - uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b with: languages: ${{ matrix.language }} - - uses: github/codeql-action/autobuild@0499de31b99561a6d14a36a5f662c2a54f91beee + - uses: github/codeql-action/autobuild@e12f0178983d466f2f6028f5cc7a6d786fd97f4b - - uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee + - uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b with: category: /language:${{matrix.language}} From dda075900622cb757ef020bc2e18c260060aab83 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Tue, 2 Dec 2025 00:41:52 -0500 Subject: [PATCH 8/9] Bump major version for breaking change --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a56590d..6e226ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "requestium" -version = "0.5.0" +version = "1.0.0" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.10" license = { file = "LICENSE" } From 43f3597ce098cabfa601dc7775b8e03c4a902984 Mon Sep 17 00:00:00 2001 From: Ramona T Date: Tue, 2 Dec 2025 10:46:13 -0500 Subject: [PATCH 9/9] don't rely on google cookies for cookie testing --- tests/test_cookies.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/test_cookies.py b/tests/test_cookies.py index 3e6271a..d202af9 100644 --- a/tests/test_cookies.py +++ b/tests/test_cookies.py @@ -4,12 +4,29 @@ import requestium.requestium -def test_transfer_session_cookies_to_driver(session: requestium.Session) -> None: - assert session.cookies.keys() == [] - response = session.get("http://google.com/") - assert response.cookies.keys().sort() == ["AEC", "NID"].sort() +@pytest.fixture( + params=[ + {"name": "session_id", "value": "abc123", "domain": "example.com", "path": "/"}, + {"name": "user_token", "value": "xyz789", "domain": "example.com", "path": "/"}, + ], + ids=["session_id", "user_token"], +) +def cookie_data(request) -> dict[str, str]: # noqa: ANN001 + return request.param + + +def test_transfer_session_cookies_to_driver(session: requestium.Session, cookie_data: dict[str, str]) -> None: + session.get(f"http://{cookie_data['domain']}") + session.cookies.set(name=cookie_data["name"], value=cookie_data["value"], domain=cookie_data["domain"], path=cookie_data["path"]) + + assert session.driver.get_cookies() == [] session.transfer_session_cookies_to_driver() - assert session.cookies.keys() == ["AEC", "NID"] + driver_cookies = session.driver.get_cookies() + assert len(driver_cookies) == 1 + assert driver_cookies[0]["name"] == cookie_data["name"] + assert driver_cookies[0]["value"] == cookie_data["value"] + assert driver_cookies[0]["domain"] in [cookie_data["domain"], f".{cookie_data['domain']}"] + assert driver_cookies[0]["path"] == cookie_data["path"] def test_transfer_session_cookies_to_driver_no_domain_error(session: requestium.Session) -> None: