Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misidentification of relevant coverage report causes tests to be thrown away #251

Open
j-ro opened this issue Dec 18, 2024 · 26 comments · Fixed by #254
Open

Misidentification of relevant coverage report causes tests to be thrown away #251

j-ro opened this issue Dec 18, 2024 · 26 comments · Fixed by #254
Labels
bug fix Something isn't working

Comments

@j-ro
Copy link

j-ro commented Dec 18, 2024

There is a bug when matching a test run with the targeted file's coverage report where, if there is more than one file with the same name endings (different paths), the matched coverage report will not be the file we are targeting, causing an erroneous report that coverage did not increase, and thus causing the tests to be thrown out.

For example, my coverage.xml file might look like this (this is a Ruby/Rails project):

[snip]
        <class name="has_report_invite" filename="app/models/concerns/has_report_invite.rb" line-rate="0.32" branch-rate="0" complexity="0">
          <methods/>
          <lines>
            <line number="1" branch="false" hits="1"/>
            <line number="2" branch="false" hits="1"/>
            <line number="4" branch="false" hits="1"/>
            <line number="5" branch="false" hits="0"/>
            <line number="8" branch="false" hits="1"/>
            <line number="9" branch="false" hits="0"/>
            <line number="12" branch="false" hits="1"/>
            <line number="13" branch="false" hits="0"/>
            <line number="16" branch="false" hits="1"/>
            <line number="17" branch="false" hits="0"/>
            <line number="20" branch="false" hits="1"/>
            <line number="21" branch="false" hits="0"/>
            <line number="22" branch="false" hits="0"/>
            <line number="24" branch="false" hits="0"/>
            <line number="25" branch="false" hits="0"/>
            <line number="29" branch="false" hits="0"/>
            <line number="32" branch="false" hits="0"/>
            <line number="33" branch="false" hits="0"/>
            <line number="34" branch="false" hits="0"/>
            <line number="35" branch="false" hits="0"/>
            <line number="39" branch="false" hits="0"/>
            <line number="44" branch="false" hits="0"/>
          </lines>
        </class>
        <class name="report_invite" filename="app/models/report_invite.rb" line-rate="0.36" branch-rate="0" complexity="0">
          <methods/>
          <lines>
            <line number="1" branch="false" hits="1"/>
            <line number="2" branch="false" hits="1"/>
            <line number="4" branch="false" hits="1"/>
            <line number="5" branch="false" hits="0"/>
            <line number="8" branch="false" hits="1"/>
            <line number="9" branch="false" hits="0"/>
            <line number="10" branch="false" hits="0"/>
            <line number="11" branch="false" hits="0"/>
            <line number="13" branch="false" hits="0"/>
            <line number="14" branch="false" hits="0"/>
            <line number="15" branch="false" hits="0"/>
            <line number="17" branch="false" hits="0"/>
            <line number="20" branch="false" hits="0"/>
            <line number="23" branch="false" hits="1"/>
            <line number="24" branch="false" hits="0"/>
            <line number="25" branch="false" hits="0"/>
            <line number="26" branch="false" hits="0"/>
            <line number="27" branch="false" hits="0"/>
            <line number="28" branch="false" hits="0"/>
            <line number="29" branch="false" hits="0"/>
            <line number="34" branch="false" hits="1"/>
            <line number="35" branch="false" hits="0"/>
            <line number="38" branch="false" hits="1"/>
            <line number="39" branch="false" hits="1"/>
            <line number="42" branch="false" hits="1"/>
            <line number="43" branch="false" hits="0"/>
            <line number="46" branch="false" hits="1"/>
            <line number="47" branch="false" hits="0"/>
          </lines>
        </class>
[snip]

As you can see, there are two files that end in "report_invite" in this report. As they are related to each other, both are exercised when the one target test file (in this case, "spec/models/report_invite_spec.rb") is run. So they both show up in this report.

Here is the command I'm using:

cover-agent \
  --source-file-path "app/models/report_invite.rb" \
  --test-file-path "spec/models/report_invite_spec.rb" \
  --code-coverage-report-path "coverage/coverage.xml" \
  --test-command "docker-compose exec -e RAILS_ENV=test web rspec spec/models/report_invite_spec.rb" \
  --additional-instructions "" \
  --included-files spec/factories/report_invites.rb app/mailers/report_invite_mailer.rb lib/tasks/report_invites.rake app/models/concerns/has_report_invite.rb  \
 --desired-coverage 100 \
  --model "gpt-4o"

As you can see from the above, the target file is "app/models/report_invite.rb". And if you manually look at the coverage report, you can see that it is 36% covered right now.

However, cover-agent reports that it is only 32% covered:

Streaming results from LLM model...
yaml
language: ruby
testing_framework: rspec
number_of_tests: 1
test_headers_indentation: 4


Streaming results from LLM model...
yaml
language: ruby
testing_framework: rspec
number_of_tests: 1
relevant_line_number_to_insert_tests_after: 8
relevant_line_number_to_insert_imports_after: 1


2024-12-18 11:06:22,710 - cover_agent.UnitTestValidator - INFO - Running build/test command to generate coverage report: "docker-compose exec -e RAILS_ENV=test web rspec spec/models/report_invite_spec.rb"
2024-12-18 11:06:35,309 - cover_agent.UnitTestValidator - INFO - Initial coverage: 31.82%
2024-12-18 11:06:35,315 - cover_agent.CoverAgent - INFO - Current Coverage: 31.82%
2024-12-18 11:06:35,315 - cover_agent.CoverAgent - INFO - Desired Coverage: 100%

Digging in, you can see it is matching to the "app/models/concerns/has_report_invite.rb" file, not the actual target, which has that percentage covered.

Because cover-agent is reading the wrong file for its coverage report, it throws out tests it generates as not increasing coverage, causing a lot of wasted time and expensive tokens.

I'm guessing the issue is with this line: https://github.com/qodo-ai/qodo-cover/blob/main/cover_agent/CoverageProcessor.py#L131

The fix is probably to try and match on the path, rather than just the partial file name, as it assumes all file names in a coverage report are unique (or don't share endings), when that is only true in a given path.

If I get some time I'll try and make a PR here, but wanted to post this bug first to see if folks had feedback on how to approach it.

@coderustic
Copy link
Contributor

@j-ro I am working on a fix. Right now as you analyzed cover_agent looks at the end of the file name and could have ambiguity as found in this case. I am working on using the name field instead of the filename filed. I could also use the full path as you suggested, but it is possible that sometimes multiple class files can be in a single source file. If I have a branch would you be able to test it and provide feedback if its working for your case?

@j-ro
Copy link
Author

j-ro commented Jan 3, 2025 via email

coderustic added a commit to coderustic/cover-agent that referenced this issue Jan 5, 2025
* While earlier PR[qodo-ai#230] managed to breakdown processing
  code into a class hierarechy, there wasnt any changes
  made to the code. This PR brings in enhancements to
  coverage processing where coverage data is stored by
  entity (Class or File).

* Coverage data is stored using a FQDN so that conflicts
  are taken care. This closes[qodo-ai#251]

* Earlier PR broke the behaviour of the agent that only
  target file coverage is considered if the global coverage
  flag is not set by the user, this PR fixes it to bring
  back the original behaviour.
@coderustic
Copy link
Contributor

@j-ro I made some efforts to fix this issue. Here in this PR [#254 ]. Appreciate your help in validating these changes.

@j-ro
Copy link
Author

j-ro commented Jan 5, 2025

@coderustic awesome, thanks! I'll try to give it a try this week!

@j-ro
Copy link
Author

j-ro commented Jan 6, 2025

@coderustic any tips for getting it to run from source?

I'm working on poetry install. It failed on my machine (M2 OSX Sequoia) on the litellm package. I could get it to complete by subbing out the codium pin for the standard one (https://github.com/BerriAI/litellm).

But trying to run it errors:

poetry run cover-agent -help
The currently activated Python version 3.13.1 is not supported by the project (>=3.9,<3.13).
Trying to find and use a compatible version. 
Using python3.9 (3.9.21)

'format'

I'm not a python dev, so I may be not doing something obvious. However the readme doesn't show any examples of how to actually run the CLI if you install it from source as far as I can tell.

@coderustic
Copy link
Contributor

@j-ro Looks like main is broken and we use a fork of the litellm. Will let you know as soon as the build is fixed.

coderustic added a commit to coderustic/cover-agent that referenced this issue Jan 7, 2025
* While earlier PR[qodo-ai#230] managed to breakdown processing
  code into a class hierarechy, there wasnt any changes
  made to the code. This PR brings in enhancements to
  coverage processing where coverage data is stored by
  entity (Class or File).

* Coverage data is stored using a FQDN so that conflicts
  are taken care. This closes[qodo-ai#251]

* Earlier PR broke the behaviour of the agent that only
  target file coverage is considered if the global coverage
  flag is not set by the user, this PR fixes it to bring
  back the original behaviour.
coderustic added a commit to coderustic/cover-agent that referenced this issue Jan 7, 2025
* While earlier PR[qodo-ai#230] managed to breakdown processing
  code into a class hierarechy, there wasnt any changes
  made to the code. This PR brings in enhancements to
  coverage processing where coverage data is stored by
  entity (Class or File).

* Coverage data is stored using a FQDN so that conflicts
  are taken care. This closes[qodo-ai#251]

* Earlier PR broke the behaviour of the agent that only
  target file coverage is considered if the global coverage
  flag is not set by the user, this PR fixes it to bring
  back the original behaviour.
@EmbeddedDevops1 EmbeddedDevops1 linked a pull request Jan 7, 2025 that will close this issue
EmbeddedDevops1 pushed a commit that referenced this issue Jan 7, 2025
* Enhanced coverage processing (#2)

* While earlier PR[#230] managed to breakdown processing
  code into a class hierarechy, there wasnt any changes
  made to the code. This PR brings in enhancements to
  coverage processing where coverage data is stored by
  entity (Class or File).

* Coverage data is stored using a FQDN so that conflicts
  are taken care. This closes[#251]

* Earlier PR broke the behaviour of the agent that only
  target file coverage is considered if the global coverage
  flag is not set by the user, this PR fixes it to bring
  back the original behaviour.

* removed sample-reports

* bump version
@EmbeddedDevops1
Copy link
Collaborator

@j-ro Looks like main is broken and we use a fork of the litellm. Will let you know as soon as the build is fixed.

CI Build was fixed but we had some failures in the regression tests when I merged this so I had to revert it. Apologies.

@j-ro
Copy link
Author

j-ro commented Jan 9, 2025

no worries, let me know when I should give it a try (and what branch to use!)

@j-ro
Copy link
Author

j-ro commented Jan 11, 2025

@coderustic wonder if you have an update here? Right now because I'm not able to run with poetry run, I'm unable to use the repo at all, since I removed the pipx install I had. Even if this PR isn't ready, do you have a path to getting the direct repo running? Is main still broken?

@coderustic
Copy link
Contributor

@j-ro main has been fixed with the earlier issue with lite-llm. You can give a try either installing new version which is 0.2.15 or using the main latest.

@j-ro
Copy link
Author

j-ro commented Jan 11, 2025

Thanks! Forgive me for my python ignorance, but how do I run with main latest? My git repo is up to date, but poetry run still errors:

poetry -vvv run cover-agent -help
Trying to detect current active python executable as specified in the config.
Unable to detect the current active python executable. Falling back to default.
Trying to detect current active python executable as specified in the config.
Unable to detect the current active python executable. Falling back to default.
The currently activated Python version 3.13.1 is not supported by the project (>=3.9,<3.13).
Trying to find and use a compatible version. 
Trying python3
Trying python3.9
Using python3.9 (3.9.21)
Virtualenv cover-agent-QB1wIuOP-py3.9 already exists.
Using virtualenv: /Users/jasonrosenbaum/Library/Caches/pypoetry/virtualenvs/cover-agent-QB1wIuOP-py3.9

  Stack trace:

  10  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/application.py:327 in run
       325│ 
       326│             try:
     → 327│                 exit_code = self._run(io)
       328│             except BrokenPipeError:
       329│                 # If we are piped to another process, it may close early and send a

   9  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/poetry/console/application.py:236 in _run
       234│ 
       235│         with directory(self._working_directory):
     → 236│             exit_code: int = super()._run(io)
       237│ 
       238│         return exit_code

   8  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/application.py:431 in _run
       429│             io.input.interactive(interactive)
       430│ 
     → 431│         exit_code = self._run_command(command, io)
       432│         self._running_command = None
       433│ 

   7  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/application.py:473 in _run_command
       471│ 
       472│         if error is not None:
     → 473│             raise error
       474│ 
       475│         return terminate_event.exit_code

   6  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/application.py:457 in _run_command
       455│ 
       456│             if command_event.command_should_run():
     → 457│                 exit_code = command.run(io)
       458│             else:
       459│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

   5  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/commands/base_command.py:117 in run
       115│         io.input.validate()
       116│ 
     → 117│         return self.execute(io) or 0
       118│ 
       119│     def merge_application_definition(self, merge_args: bool = True) -> None:

   4  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/cleo/commands/command.py:61 in execute
        59│ 
        60│         try:
     →  61│             return self.handle()
        62│         except KeyboardInterrupt:
        63│             return 1

   3  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/poetry/console/commands/run.py:31 in handle
        29│ 
        30│         if scripts and script in scripts:
     →  31│             return self.run_script(scripts[script], args)
        32│ 
        33│         try:

   2  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/poetry/console/commands/run.py:77 in run_script
        75│         module, callable_ = script.split(":")
        76│ 
     →  77│         src_in_sys_path = "sys.path.append('src'); " if self._module.is_in_src() else ""
        78│ 
        79│         cmd = ["python", "-c"]

   1  /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/poetry/console/commands/run.py:46 in _module
        44│         package = poetry.package
        45│         path = poetry.file.path.parent
     →  46│         module = Module(package.name, path.as_posix(), package.packages)
        47│ 
        48│         return module

  KeyError

  'format'

  at /usr/local/Cellar/poetry/2.0.0/libexec/lib/python3.13/site-packages/poetry/core/masonry/utils/module.py:79 in __init__
       75│             self._package_includes.append(
       76│                 PackageInclude(
       77│                     self._path,
       78│                     package["include"],
    →  79│                     formats=package["format"],
       80│                     source=package.get("from"),
       81│                     target=package.get("to"),
       82│                 )
       83│      

@coderustic
Copy link
Contributor

I am sorry but looks like every one over github is merging fixes thats breaking everywhere, see this python-poetry/poetry#9961
What version of poetry you have? I am using Poetry (version 1.8.4)

$ poetry -vvv run cover-agent -help
Using virtualenv: /home/sai/.cache/pypoetry/virtualenvs/cover-agent-vDosZXUS-py3.12
/home/sai/.cache/pypoetry/virtualenvs/cover-agent-vDosZXUS-py3.12/lib/python3.12/site-packages/pydantic/_internal/_config.py:341: UserWarning: Valid config keys have changed in V2:
* 'fields' has been removed
  warnings.warn(message, UserWarning)
usage: cover-agent [-h] --source-file-path SOURCE_FILE_PATH --test-file-path TEST_FILE_PATH [--project-root PROJECT_ROOT] [--test-file-output-path TEST_FILE_OUTPUT_PATH] --code-coverage-report-path CODE_COVERAGE_REPORT_PATH --test-command
                   TEST_COMMAND [--test-command-dir TEST_COMMAND_DIR] [--included-files [INCLUDED_FILES ...]] [--coverage-type COVERAGE_TYPE] [--report-filepath REPORT_FILEPATH] [--desired-coverage DESIRED_COVERAGE] [--max-iterations MAX_ITERATIONS]
                   [--additional-instructions ADDITIONAL_INSTRUCTIONS] [--model MODEL] [--api-base API_BASE] [--strict-coverage] [--run-tests-multiple-times RUN_TESTS_MULTIPLE_TIMES] [--log-db-path LOG_DB_PATH] [--branch BRANCH]
                   [--use-report-coverage-feature-flag | --diff-coverage] [--run-each-test-separately RUN_EACH_TEST_SEPARATELY]

Cover Agent v0.2.15

options:
  -h, --help            show this help message and exit
  --source-file-path SOURCE_FILE_PATH
                        Path to the source file.
  --test-file-path TEST_FILE_PATH
                        Path to the input test file.
  --project-root PROJECT_ROOT
                        Path to the root of the project.
  --test-file-output-path TEST_FILE_OUTPUT_PATH
                        Path to the output test file.
  --code-coverage-report-path CODE_COVERAGE_REPORT_PATH
                        Path to the code coverage report file.
  --test-command TEST_COMMAND
                        The command to run tests and generate coverage report.
  --test-command-dir TEST_COMMAND_DIR
                        The directory to run the test command in. Default: /home/sai/workspace/python/cover-agent.
  --included-files [INCLUDED_FILES ...]
                        List of files to include in the coverage. For example, "--included-files library1.c library2.c." Default: None.
  --coverage-type COVERAGE_TYPE
                        Type of coverage report. Default: cobertura.
  --report-filepath REPORT_FILEPATH
                        Path to the output report file. Default: test_results.html.
  --desired-coverage DESIRED_COVERAGE
                        The desired coverage percentage. Default: 90.
  --max-iterations MAX_ITERATIONS
                        The maximum number of iterations. Default: 10.
  --additional-instructions ADDITIONAL_INSTRUCTIONS
                        Any additional instructions you wish to append at the end of the prompt. Default: .
  --model MODEL         Which LLM model to use. Default: gpt-4o.
  --api-base API_BASE   The API url to use for Ollama or Hugging Face. Default: http://localhost:11434.
  --strict-coverage     If set, Cover-Agent will return a non-zero exit code if the desired code coverage is not achieved. Default: False.
  --run-tests-multiple-times RUN_TESTS_MULTIPLE_TIMES
                        Number of times to run the tests generated by Cover Agent. Default: 1.
  --log-db-path LOG_DB_PATH
                        Path to optional log database. Default: .
  --branch BRANCH       The branch to compare against when using --diff-coverage. Default: main.
  --use-report-coverage-feature-flag
                        Setting this to True considers the coverage of all the files in the coverage report. This means we consider a test as good if it increases coverage for a different file other than the source file. Default: False. Not
                        compatible with --diff-coverage.
  --diff-coverage       If set, Cover-Agent will only generate tests based on the diff between branches. Default: False. Not compatible with --use-report-coverage-feature-flag.
  --run-each-test-separately RUN_EACH_TEST_SEPARATELY
                        Run each test separately. Default: False

@coderustic
Copy link
Contributor

Btw why dont you go back and try using pipx installed version?

@j-ro
Copy link
Author

j-ro commented Jan 11, 2025

I'm using poetry version 2.0.0

I can go back to pipx, I just wouldn't be able to try this branch right? Or can I install branches with pipx?

@coderustic
Copy link
Contributor

Thanks for being supportive and offering to help. I dont think this branch is ready yet, but I will try a different approach for you to test next time when my branch is ready.

@j-ro
Copy link
Author

j-ro commented Jan 11, 2025

ok! I downgraded poetry and I have a different error now, but maybe I should just go back to pipx instead:

poetry run -vvv cover-agent --help
The currently activated Python version 3.13.1 is not supported by the project (>=3.9,<3.13).
Trying to find and use a compatible version. 
Trying python3
Trying python3.9
Using python3.9 (3.9.21)
Virtualenv cover-agent-QB1wIuOP-py3.9 already exists.
Using virtualenv: /Users/jasonrosenbaum/Library/Caches/pypoetry/virtualenvs/cover-agent-QB1wIuOP-py3.9
/Users/jasonrosenbaum/Library/Caches/pypoetry/virtualenvs/cover-agent-QB1wIuOP-py3.9/lib/python3.9/site-packages/pydantic/_internal/_config.py:341: UserWarning: Valid config keys have changed in V2:
* 'fields' has been removed
  warnings.warn(message, UserWarning)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/Cellar/[email protected]/3.9.21/Frameworks/Python.framework/Versions/3.9/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/Users/jasonrosenbaum/CAN/site/qodo-cover/cover_agent/main.py", line 3, in <module>
    from cover_agent.CoverAgent import CoverAgent
  File "/Users/jasonrosenbaum/CAN/site/qodo-cover/cover_agent/CoverAgent.py", line 13, in <module>
    from cover_agent.UnitTestValidator import UnitTestValidator
  File "/Users/jasonrosenbaum/CAN/site/qodo-cover/cover_agent/UnitTestValidator.py", line 16, in <module>
    from cover_agent.coverage.processor import process_coverage, CoverageReport, CoverageData
  File "/Users/jasonrosenbaum/CAN/site/qodo-cover/cover_agent/coverage/processor.py", line 215, in <module>
    class JacocoProcessor(CoverageProcessor):
  File "/Users/jasonrosenbaum/CAN/site/qodo-cover/cover_agent/coverage/processor.py", line 239, in JacocoProcessor
    def _get_file_extension(self, filename: str) -> str | None:
TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'

@coderustic
Copy link
Contributor

This is due to pydantic version. We have a deprecated warning currently which is probably removed in Pydantic version 2. I suggest you try using python 3.12 (if not use the pipx installed version so you dont have to deal with setting up a dev environment)

@j-ro
Copy link
Author

j-ro commented Jan 11, 2025

ok great, poetry seems to be working at least somewhat. Still more work to do on my end but I may be able to get back running that way. If you have a branch to test at some point or something else do let me know!

@j-ro
Copy link
Author

j-ro commented Jan 12, 2025

I'm also realizing as I test the main branch with poetry that the new (and fairly undocumented) use-report-coverage-feature-flag option probably obviates this issue if you use it, since it'll consider the entire coverage report and not just a part of it when deciding whether to keep tests or not.

@coderustic
Copy link
Contributor

Yes, you are spot on (though I would name the flag as consider_global_coverage. I was in a middle of refactoring and as of now on main the default behavior is to consider global coverage (which I am embarrassed to say it out loud). My part two of the refactoring is bringing the default behaviour to false and also add fqdn to the class names. See if on main it will work even without setting the flag.

@j-ro
Copy link
Author

j-ro commented Jan 12, 2025

I will try it when I can, interesting!

@coderustic
Copy link
Contributor

You might see that on the main file 1 data is overwritten by file 2 data (which is being fixed by #264) so it will be good to wait for few days and when I see all in progress work is merged I can let you know.

@j-ro
Copy link
Author

j-ro commented Jan 12, 2025

sounds good!

@j-ro
Copy link
Author

j-ro commented Jan 12, 2025

Though I did find kind of a weird behavior with the new option -- when we hit 100% coverage for the target file the loop keeps going until it runs out of iterations. That seems a bit unexpected? I can open another issue for that if you want.

@EmbeddedDevops1
Copy link
Collaborator

@j-ro thanks for pointing that out. @coderustic is going to address that in the next PR. Really really appreciate all the thorough feedback.

@EmbeddedDevops1
Copy link
Collaborator

FYI, I've been working on trying to get Python > 3.12 working but there are some libraries that haven't been playing nicely in the pyproject.toml. I'll create an issue for it for posterity.

@EmbeddedDevops1 EmbeddedDevops1 added the bug fix Something isn't working label Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug fix Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants