Skip to content

Combined prs jan 2026#1807

Merged
robbrad merged 28 commits into
masterfrom
combined-prs-jan-2026
Jan 14, 2026
Merged

Combined prs jan 2026#1807
robbrad merged 28 commits into
masterfrom
combined-prs-jan-2026

Conversation

@robbrad
Copy link
Copy Markdown
Owner

@robbrad robbrad commented Jan 14, 2026

Jan 2026 Release

Summary by CodeRabbit

  • Bug Fixes

    • Fixed bin collection date handling for December/January transitions to prevent incorrect date assignments.
  • New Features

    • Added support for Folkestone and Hythe District Council.
    • Improved data retrieval for multiple councils using more efficient methods.
  • Documentation

    • Updated council usage guides and command examples in wiki for various councils including Isle of Anglesey, Cumberland, Renfrewshire, and others.

✏️ Tip: You can customize this high-level summary in your review settings.

dependabot Bot and others added 28 commits December 8, 2025 06:04
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
fix: #1500 - Renfrewshire Council
fix: #1771 -  South Lanarkshire Council
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](actions/cache@v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
fix: #1777 - fix: Newark and Sherwood District Council
fix: #1760 - Folkstone and Hythe District Council
Some councils return January collection dates using the current year during December. For example, Bromley just lists the day and month, which is then interpreted as the current year rather than next year.
This causes valid upcoming collections to be dropped. This change corrects the year in Dec → Jan rollover cases.
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.6.0 to 2.6.3.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.6.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
fix: #1803 #1793 Castlepoint District Council
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.20.1 to 3.20.3.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/filelock/blob/main/docs/changelog.rst)
- [Commits](tox-dev/filelock@3.20.1...3.20.3)

---
updated-dependencies:
- dependency-name: filelock
  dependency-version: 3.20.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
# Conflicts:
#	uk_bin_collection/uk_bin_collection/councils/SouthLanarkshireCouncil.py
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 14, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request modernizes GitHub Actions workflows by bumping action versions, refactors multiple council bin collection parsers to use UPRN-based and HTTP-driven approaches (replacing Selenium workflows), adds December-to-January date rollover correction logic, restructures the Folkestone and Hythe council implementation, and updates test inputs and documentation to reflect the architectural changes.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow Updates
.github/workflows/bump.yml, .github/workflows/release.yml, .github/workflows/validate-release-ready.yml
Bumped action versions: actions/cache v4→v5, actions/checkout v5→v6. No control flow changes.
Core Date Handling
custom_components/uk_bin_collection/__init__.py
Added rollover correction for bin collection dates: when current date is in December and a January date parses as earlier than today, roll the January date forward by one year and log a debug message.
Council Parsers — Refactored to UPRN/HTTP Flow
uk_bin_collection/uk_bin_collection/councils/RenfrewshireCouncil.py
Replaced Selenium-driven Cloudflare-bypass flow with UPRN validation and lightweight HTTP/ICS parsing. Removed 230+ lines of browser automation; now fetches ICS data directly and parses calendar events.
Council Parsers — Query Parameter Updates
uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py, uk_bin_collection/uk_bin_collection/councils/FarehamBoroughCouncil.py
BuckinghamshireCouncil: converted POST to GET request with query parameter encoding; FarehamBoroughCouncil: consolidated "Road" and "Postcode" parameters into single "Road or Postcode" key.
Council Parsers — Parsing Logic Updates
uk_bin_collection/uk_bin_collection/councils/CastlepointDistrictCouncil.py, uk_bin_collection/uk_bin_collection/councils/SouthLanarkshireCouncil.py, uk_bin_collection/uk_bin_collection/councils/NewarkAndSherwoodDC.py
CastlepointDistrictCouncil: reworked HTML parsing to scan multiple calendar containers and iterate bins by month; SouthLanarkshireCouncil: added guard to filter "Area" schedule types; NewarkAndSherwoodDC: added UPRN validation and remote page fetch instead of local parsing.
Folkestone & Hythe Council Restructuring
uk_bin_collection/uk_bin_collection/councils/FolkestoneandHytheDistrictCouncil.py (new), uk_bin_collection/uk_bin_collection/councils/FolkstoneandHytheDistrictCouncil.py (removed)
Reimplemented council parser: file renamed (spelling corrected) and logic refactored to use UPRN-based HTTP requests with BeautifulSoup parsing instead of previous implementation. Old file deleted; new file added with updated data extraction flow.
Test Data & Documentation
uk_bin_collection/tests/input.json, wiki/Councils.md
Updated test input JSON: RenfrewshireCouncil changed from address fields to UPRN; FolkstoneandHytheDistrictCouncil renamed and restructured. Wiki documentation expanded with Isle of Anglesey council and updated command examples across multiple councils to reflect UPRN-centric workflows and new URLs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • dp247

🐰 A hop through workflows and councils true,
From Selenium's chains to UPRN's due,
Dates rollover gently when months renew,
Council parsers now sleek and lightweight brew,
Modern and swift—the rabbit's debut! 🚀

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94c49e5 and ba4e538.

⛔ Files ignored due to path filters (1)
  • poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .github/workflows/bump.yml
  • .github/workflows/release.yml
  • .github/workflows/validate-release-ready.yml
  • custom_components/uk_bin_collection/__init__.py
  • uk_bin_collection/tests/input.json
  • uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/CastlepointDistrictCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/FarehamBoroughCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/FolkestoneandHytheDistrictCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/FolkstoneandHytheDistrictCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/NewarkAndSherwoodDC.py
  • uk_bin_collection/uk_bin_collection/councils/RenfrewshireCouncil.py
  • uk_bin_collection/uk_bin_collection/councils/SouthLanarkshireCouncil.py
  • wiki/Councils.md

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 14, 2026

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
8 3 5 0
View the top 1 failed test(s) by shortest run time
uk_bin_collection.tests.step_defs.test_validate_council::test_scenario_outline[FarehamBoroughCouncil]
Stack Traces | 0.738s run time
fixturefunc = <function scrape_step at 0x7fe7ce59b600>
request = <FixtureRequest for <Function test_scenario_outline[FarehamBoroughCouncil]>>
kwargs = {'context': <test_validate_council.Context object at 0x7fe7cf2c0d70>, 'headless_mode': 'True', 'local_browser': 'False', 'selenium_url': 'http://localhost:4444'}

    def call_fixture_func(
        fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs
    ) -> FixtureValue:
        if is_generator(fixturefunc):
            fixturefunc = cast(
                Callable[..., Generator[FixtureValue, None, None]], fixturefunc
            )
            generator = fixturefunc(**kwargs)
            try:
                fixture_result = next(generator)
            except StopIteration:
                raise ValueError(f"{request.fixturename} did not yield a value") from None
            finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)
            request.addfinalizer(finalizer)
        else:
            fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)
>           fixture_result = fixturefunc(**kwargs)

../../../..../pypoetry/virtualenvs/uk-bin-collection-EwS6Gn8s-py3.12/lib/python3.12.../site-packages/_pytest/fixtures.py:898: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../tests/step_defs/test_validate_council.py:101: in scrape_step
    context.parse_result = CollectData.run()
uk_bin_collection/uk_bin_collection/collect_data.py:101: in run
    return self.client_code(
uk_bin_collection/uk_bin_collection/collect_data.py:121: in client_code
    return get_bin_data_class.template_method(address_url, **kwargs)
uk_bin_collection/uk_bin_collection/get_bin_data.py:61: in template_method
    bin_data_dict = self.get_and_parse_data(this_url, **kwargs)
uk_bin_collection/uk_bin_collection/get_bin_data.py:84: in get_and_parse_data
    bin_data_dict = self.parse_data("", url=address_url, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <FarehamBoroughCouncil.CouncilClass object at 0x7fe7ce2f94c0>, page = ''
kwargs = {'council_module_str': 'FarehamBoroughCouncil', 'dev_mode': False, 'headless': True, 'local_browser': False, ...}
user_postcode = 'PO14 4NR'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'}
params = {'Road or Postcode': 'PO14 4NR', 'list': 'DomesticBinCollections2025on', 'type': 'JSON'}
response = <Response [200]>
bin_data = 'there is no data matching the parameters supplied'
data = {'bins': []}

    def parse_data(self, page: str, **kwargs) -> dict:
        """
        Retrieve and parse Fareham bin collection dates for a given postcode into a structured dictionary.
    
        Parameters:
            page (str): Source page content (not used; present for interface compatibility).
            postcode (str, via kwargs['postcode']): Postcode to query; must be a valid postcode.
    
        Returns:
            dict: A dictionary with a "bins" key containing a list of entries. Each entry is a dict with:
                - "type" (str): The bin type (e.g., "Recycling", "Garden").
                - "collectionDate" (str): Collection date formatted as "DD/MM/YYYY".
    
        Raises:
            ValueError: If the postcode is not found on the website.
            RuntimeError: If expected collection dates cannot be parsed from the response.
        """
        user_postcode = kwargs.get("postcode")
        check_postcode(user_postcode)
    
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
        }
        params = {
            "type": "JSON",
            "list": "DomesticBinCollections2025on",
            "Road or Postcode": user_postcode,
        }
    
        response = requests.get(
            "https://www.fareham.gov.uk/internetlookups/search_data.aspx",
            params=params,
            headers=headers,
        )
    
        bin_data = response.json()["data"]
        data = {"bins": []}
    
        if "rows" in bin_data:
            collection_str = bin_data["rows"][0]["BinCollectionInformation"]
    
            results = re.findall(r'(\d{1,2}/\d{1,2}/\d{4}|today)\s*\(([^)]+)\)', collection_str)
    
            if results:
                for result in results:
                    if (result[0] == "today"):
                        collection_date = datetime.today()
                    else:
                        collection_date = datetime.strptime(result[0], "%d/%m/%Y")
                    dict_data = {
                        "type": result[1],
                        "collectionDate": collection_date.strftime(date_format),
                    }
                    data["bins"].append(dict_data)
            else:
                raise RuntimeError("Dates not parsed correctly.")
    
            # Look for garden waste key
            for key, value in bin_data["rows"][0].items():
                if key.startswith("GardenWasteBinDay"):
                    results = re.findall(r'(\d{1,2}/\d{1,2}/\d{4})', value)
                    if not results:
                        continue
                    collection_date = datetime.strptime(results[0], "%d/%m/%Y")
                    garden_data = {
                        "type": "Garden",
                        "collectionDate": collection_date.strftime(date_format),
                    }
                    data["bins"].append(garden_data)
    
        else:
>           raise ValueError("Postcode not found on website.")
E           ValueError: Postcode not found on website.

.../uk_bin_collection/councils/FarehamBoroughCouncil.py:86: ValueError
View the full list of 2 ❄️ flaky test(s)
uk_bin_collection.tests.step_defs.test_validate_council::test_scenario_outline[CastlepointDistrictCouncil]

Flake rate in main: 98.94% (Passed 3 times, Failed 280 times)

Stack Traces | 0.949s run time
fixturefunc = <function validate_output_step at 0x7f93689971a0>
request = <FixtureRequest for <Function test_scenario_outline[CastlepointDistrictCouncil]>>
kwargs = {'context': <test_validate_council.Context object at 0x7f936966c6b0>}

    def call_fixture_func(
        fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs
    ) -> FixtureValue:
        if is_generator(fixturefunc):
            fixturefunc = cast(
                Callable[..., Generator[FixtureValue, None, None]], fixturefunc
            )
            generator = fixturefunc(**kwargs)
            try:
                fixture_result = next(generator)
            except StopIteration:
                raise ValueError(f"{request.fixturename} did not yield a value") from None
            finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)
            request.addfinalizer(finalizer)
        else:
            fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)
>           fixture_result = fixturefunc(**kwargs)

../../../..../pypoetry/virtualenvs/uk-bin-collection-EwS6Gn8s-py3.12/lib/python3.12.../site-packages/_pytest/fixtures.py:898: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../tests/step_defs/test_validate_council.py:114: in validate_output_step
    assert file_handler.validate_json_schema(
.../step_defs/step_helpers/file_handler.py:40: in validate_json_schema
    validate(instance=json_data, schema=schema)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

instance = {'bins': []}
schema = {'$ref': '#/definitions/BinData', '$schema': 'http://json-schema.org/draft-06/schema#', 'definitions': {'Bin': {'addit...ems': {'$ref': '#/definitions/Bin'}, 'minItems': 1, 'type': 'array'}}, 'required': ['bins'], 'title': 'BinData', ...}}}
cls = <class 'jsonschema.validators.Draft6Validator'>, args = (), kwargs = {}
validator = Draft6Validator(schema={'$ref': '#/definitions/BinData', '$schema': 'http://json-...ft-06/schema#', 'definitions': {'B...nitions/Bin'}, 'minItems': 1, 'type': 'array'}}, 'required': ['bins'], 'title': 'BinData', ...}}}, format_checker=None)
error = <ValidationError: '[] should be non-empty'>

    def validate(instance, schema, cls=None, *args, **kwargs):  # noqa: D417
        """
        Validate an instance under the given schema.
    
            >>> validate([2, 3, 4], {"maxItems": 2})
            Traceback (most recent call last):
                ...
            ValidationError: [2, 3, 4] is too long
    
        :func:`~jsonschema.validators.validate` will first verify that the
        provided schema is itself valid, since not doing so can lead to less
        obvious error messages and fail in less obvious or consistent ways.
    
        If you know you have a valid schema already, especially
        if you intend to validate multiple instances with
        the same schema, you likely would prefer using the
        `jsonschema.protocols.Validator.validate` method directly on a
        specific validator (e.g. ``Draft202012Validator.validate``).
    
    
        Arguments:
    
            instance:
    
                The instance to validate
    
            schema:
    
                The schema to validate with
    
            cls (jsonschema.protocols.Validator):
    
                The class that will be used to validate the instance.
    
        If the ``cls`` argument is not provided, two things will happen
        in accordance with the specification. First, if the schema has a
        :kw:`$schema` keyword containing a known meta-schema [#]_ then the
        proper validator will be used. The specification recommends that
        all schemas contain :kw:`$schema` properties for this reason. If no
        :kw:`$schema` property is found, the default validator class is the
        latest released draft.
    
        Any other provided positional and keyword arguments will be passed
        on when instantiating the ``cls``.
    
        Raises:
    
            `jsonschema.exceptions.ValidationError`:
    
                if the instance is invalid
    
            `jsonschema.exceptions.SchemaError`:
    
                if the schema itself is invalid
    
        .. rubric:: Footnotes
        .. [#] known by a validator registered with
            `jsonschema.validators.validates`
    
        """
        if cls is None:
            cls = validator_for(schema)
    
        cls.check_schema(schema)
        validator = cls(schema, *args, **kwargs)
        error = exceptions.best_match(validator.iter_errors(instance))
        if error is not None:
>           raise error
E           jsonschema.exceptions.ValidationError: [] should be non-empty
E           
E           Failed validating 'minItems' in schema['properties']['bins']:
E               {'type': 'array', 'items': {'$ref': '#/definitions/Bin'}, 'minItems': 1}
E           
E           On instance['bins']:
E               []

../../../..../pypoetry/virtualenvs/uk-bin-collection-EwS6Gn8s-py3.12/lib/python3.12.../site-packages/jsonschema/validators.py:1332: ValidationError
uk_bin_collection.tests.step_defs.test_validate_council::test_scenario_outline[EastRenfrewshireCouncil]

Flake rate in main: 86.17% (Passed 39 times, Failed 243 times)

Stack Traces | 31.9s run time
fixturefunc = <function scrape_step at 0x7fe7ce59b600>
request = <FixtureRequest for <Function test_scenario_outline[EastRenfrewshireCouncil]>>
kwargs = {'context': <test_validate_council.Context object at 0x7fe7cf2c0d70>, 'headless_mode': 'True', 'local_browser': 'False', 'selenium_url': 'http://localhost:4444'}

    def call_fixture_func(
        fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs
    ) -> FixtureValue:
        if is_generator(fixturefunc):
            fixturefunc = cast(
                Callable[..., Generator[FixtureValue, None, None]], fixturefunc
            )
            generator = fixturefunc(**kwargs)
            try:
                fixture_result = next(generator)
            except StopIteration:
                raise ValueError(f"{request.fixturename} did not yield a value") from None
            finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)
            request.addfinalizer(finalizer)
        else:
            fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)
>           fixture_result = fixturefunc(**kwargs)

../../../..../pypoetry/virtualenvs/uk-bin-collection-EwS6Gn8s-py3.12/lib/python3.12.../site-packages/_pytest/fixtures.py:898: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../tests/step_defs/test_validate_council.py:101: in scrape_step
    context.parse_result = CollectData.run()
uk_bin_collection/uk_bin_collection/collect_data.py:101: in run
    return self.client_code(
uk_bin_collection/uk_bin_collection/collect_data.py:121: in client_code
    return get_bin_data_class.template_method(address_url, **kwargs)
uk_bin_collection/uk_bin_collection/get_bin_data.py:61: in template_method
    bin_data_dict = self.get_and_parse_data(this_url, **kwargs)
uk_bin_collection/uk_bin_collection/get_bin_data.py:84: in get_and_parse_data
    bin_data_dict = self.parse_data("", url=address_url, **kwargs)
.../uk_bin_collection/councils/EastRenfrewshireCouncil.py:34: in parse_data
    inputElement_postcode = WebDriverWait(driver, 30).until(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="43202fe00128de34d19fa20e83b7c723")>
method = <function presence_of_element_located.<locals>._predicate at 0x7fe7de66c4a0>
message = ''

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: 
E       Stacktrace:
E       #0 0x5558fdcaf61a <unknown>
E       #1 0x5558fd72c20b <unknown>
E       #2 0x5558fd77d90f <unknown>
E       #3 0x5558fd77db51 <unknown>
E       #4 0x5558fd7cbd84 <unknown>
E       #5 0x5558fd7c920e <unknown>
E       #6 0x5558fd770232 <unknown>
E       #7 0x5558fd770ee1 <unknown>
E       #8 0x5558fdc783f9 <unknown>
E       #9 0x5558fdc7b34d <unknown>
E       #10 0x5558fdc61122 <unknown>
E       #11 0x5558fdc7bf2b <unknown>
E       #12 0x5558fdc47c30 <unknown>
E       #13 0x5558fdc9cd78 <unknown>
E       #14 0x5558fdc9cf4c <unknown>
E       #15 0x5558fdcae973 <unknown>
E       #16 0x7f63b8561aa4 <unknown>
E       #17 0x7f63b85eea64 __clone

../../../..../pypoetry/virtualenvs/uk-bin-collection-EwS6Gn8s-py3.12/lib/python3.12.../webdriver/support/wait.py:146: TimeoutException

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@robbrad robbrad merged commit d95cb87 into master Jan 14, 2026
22 of 27 checks passed
@robbrad robbrad deleted the combined-prs-jan-2026 branch March 14, 2026 08:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants