Skip to content

v0.19.0 - #164

Open
eda-s-claude-bot[bot] wants to merge 21 commits into
mainfrom
dev
Open

v0.19.0#164
eda-s-claude-bot[bot] wants to merge 21 commits into
mainfrom
dev

Conversation

@eda-s-claude-bot

@eda-s-claude-bot eda-s-claude-bot Bot commented Aug 16, 2026

Copy link
Copy Markdown

New Features

  • pyEDAA.Reports.Unittesting:
    • Testsuite records the host a test suite was executed on: a new optional hostname parameter and the
      read-only property Testsuite.Hostname. The unified data model had no field for it, so the information was
      dropped as soon as a report was read.
    • Merging combines hostnames: the common value while every input agrees on it, "various" once two inputs
      disagree. A test suite without a hostname was executed somewhere unrecorded rather than somewhere else, so it
      leaves an otherwise unanimous hostname alone.

Breaking Changes

  • ⚠️ pyEDAA.Reports.Unittesting: Testsuite.__init__ takes hostname as its third parameter, before
    startTime, matching the order the JUnit dialects use. Code constructing a Testsuite with more than two
    positional arguments has to pass hostname or switch to keyword arguments:

    Testsuite("name", TestsuiteKind.Module, startTime, ...)              # before
    Testsuite("name", TestsuiteKind.Module, hostname, startTime, ...)    # now
    Testsuite("name", TestsuiteKind.Module, startTime=startTime, ...)    # or by keyword

    Nothing else in the package or its tests still constructs a test suite positionally past kind.

Changes

  • pyEDAA.Reports.Unittesting: parent=parent is the common style at every hand-over in the unit testing data
    model, as in the other data models. Five call sites passed it positionally.

Bug Fixes

  • pyEDAA.Reports.Unittesting.JUnit:
    • A merged report could not be read back with the dialect it was written in. Testsuite.FromTestsuite() had no
      hostname to pass on and every writer emits the attribute only when it is set, so a merged pyTest-JUnit report
      carried none - and the pyTest-JUnit reader rejects that with
      Required parameter 'hostname' not found in tag 'testsuite', exit code 255. Any two-stage merge hit it, which
      is what a CI pipeline does when it merges per platform and then merges the results.
    • Ant-JUnit4 and CTest-JUnit root their report at <testsuite>, so Document.Convert() builds that test
      suite itself - from name, timestamp and time only. The hostname on the root element was dropped, although
      the same dialect's _ConvertTestsuite() reads it for nested suites.
    • CTestJUnit wrote str(testsuite._hostname), so a report with no recorded host got the literal
      hostname="None". CTest-JUnit.xsd requires the attribute, so it is written as unknownhost now.
  • pyEDAA.Reports.Unittesting:
    • Testsuite.Copy() raised TypeError: Parameter 'teardownDuration' is not of type 'timedelta' for any test
      suite carrying a status. It passed nine arguments positionally against a signature whose second parameter is
      kind, omitting kind and testDuration, so every value landed one position too early.
    • MergedTestsuite.__init__() passed parent positionally into the testsuites slot, so
      MergedTestsuite(suite, parent=x) silently produced a test suite whose Parent is None.

Documentation

  • doc/Dependency.rst matches the requirement files again: eleven required packages that were never listed are
    added, two that are no longer required are removed, and the version floors are taken from the requirements.

Unit Tests

  • tests/unit/Unittesting/Hostname.py is new: 12 testcases covering the data model, the six hostname merge cases,
    the <testsuite>-rooted dialects and both round trips.
  • tests/unit: 86 → 98 passed.

GitHub Pipeline

  • PublishTestResults is enabled again.
  • Tag pipelines are named after the tag, via run-name.

Dependencies

  • pyTooling =8.18 → **=8.19**, lxml >=6.1 → >=6.1.1, setuptools >=83.0 → >=84.0.0,
    sphinx_reports =0.11.1 → **=0.11.2**, twine =6.2 → **=7.0**.

Others

  • Schema/Coverage/Cobertura.dtd was added.

Related Issues and Pull-Requests

Paebbels and others added 8 commits July 31, 2026 08:12
`TagReleaseCommit` starts the tag pipeline through `createWorkflowDispatch`, so
the run is a `workflow_dispatch` event and GitHub titles it with the workflow's
name instead of the tag. A top-level `run-name` overrides the title without
changing the event:

    run-name: ${{ github.ref_type == 'tag' && github.ref_name || '' }}

The empty string is the documented fallback to GitHub's event-specific default,
so pushes keep their commit message as the title and only tag runs are renamed.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
A merged report never named the host it came from: the unified Testsuite had no field for it, so
Testsuite.FromTestsuite() could not pass one on and every writer skipped the attribute it only emits
when set. pytest and Ant write 'hostname' on every <testsuite> - 48 of 48 and 4 of 4 of the reference
outputs in tests/data - so a merged pyTest-JUnit report without it is something pytest itself would
never produce, and the pyTest-JUnit reader rightly rejects it with "Required parameter 'hostname' not
found in tag 'testsuite'".

Testsuite gains an optional 'hostname' with a matching @readonly property, and it is carried through
Testsuite.ToTestsuite(), the four dialects' FromTestsuite() and MergedTestsuite.

Merging combines the hostnames: a single value while every input agrees on it, "various" once two
inputs disagree. A test suite without a hostname ran somewhere unrecorded rather than somewhere else,
so it leaves an otherwise unanimous hostname alone.

Two defects in the code this had to touch:

* Testsuite.Copy() raised 'TypeError: Parameter 'teardownDuration' is not of type timedelta' for any
  test suite carrying a status - it passed nine arguments positionally against a signature whose
  second parameter is 'kind', so everything was shifted by one. It uses keyword arguments now.
* MergedTestsuite.__init__() passed 'parent' positionally into the 'testsuites' slot, so the parent
  was silently dropped. Also keyword arguments now.

CTestJUnit wrote str(None), producing hostname="None"; with no hostname recorded it now writes the
same 'localhost' default the reader applies for an absent attribute.

tests/unit/Unittesting/Hostname.py covers the data model, the six merge cases and both round trips;
all 11 testcases fail without this change.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
* 'hostname' sits before 'startTime' in Testsuite.__init__, as it does in the JUnit dialects, and is passed
  positionally at the call sites.
* Copy() is positional again, now listing every field in signature order - the previous list was missing 'kind'
  and 'testDuration', which is what made it raise.
* _MergeHostname is a normal method taking only the other hostname, and its doc-string is compact.
* CTestJUnit writes 'unknownhost' rather than 'localhost': a valid hostname would claim knowledge we don't have.
* No empty line before the '_hostname' assignment.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
'parent=parent' is now the common style at every hand-over in the unit testing data model, matching how
the other data models pass it as the last associated parameter. Five call sites in
pyEDAA/Reports/Unittesting/__init__.py passed it positionally.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
Ant-JUnit4 and CTest-JUnit root their report at <testsuite>, so its attributes belong to the document itself.
Document.Convert() built that test suite from name, timestamp and time only, dropping the hostname the element
carries - while the same dialect's _ConvertTestsuite(), used for nested suites, reads it.

Found by converting between dialects: an Ant or CTest report written out as pyTest-JUnit could not be read back,
because the hostname never reached the model in the first place.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
Minor, not patch: Testsuite gained a 'hostname' parameter and a matching read-only property, and the parameter
sits before 'startTime' as it does in the JUnit dialects - which shifts anyone passing arguments positionally.

run.ps1 carries the version too, and was left at 0.18.0 by the previous bump.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
@eda-s-claude-bot
eda-s-claude-bot Bot requested a review from Paebbels as a code owner August 16, 2026 11:17
@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 21.87500% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 31.74%. Comparing base (f344d1a) to head (469beb1).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
...yEDAA/Reports/Unittesting/JUnit/GoogleTestJUnit.py 10.00% 9 Missing ⚠️
pyEDAA/Reports/Unittesting/__init__.py 27.27% 8 Missing ⚠️
pyEDAA/Reports/Unittesting/JUnit/CTestJUnit.py 14.28% 6 Missing ⚠️
pyEDAA/Reports/Unittesting/JUnit/AntJUnit4.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main     #164       +/-   ##
===========================================
- Coverage   70.93%   31.74%   -39.19%     
===========================================
  Files           9        9               
  Lines        2477     2498       +21     
  Branches      393      396        +3     
===========================================
- Hits         1757      793      -964     
- Misses        540     1705     +1165     
+ Partials      180        0      -180     
Flag Coverage Δ
unittests 31.74% <21.87%> (-39.19%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Incorporates Dependabot's #157, #158, #159, #160 and #161:

* twine     ~= 6.2      -> ~= 7.0        (dist/requirements.txt)
* setuptools >= 83.0    -> >= 84.0.0     (pyproject.toml)
* sphinx_reports ~= 0.11.1 -> ~= 0.11.2  (doc/requirements.txt)
* pyTooling ~= 8.18     -> ~= 8.19       (pyproject.toml, requirements.txt)
* lxml      >= 6.1      -> >= 6.1.1      (requirements.txt, tests/typing/requirements.txt)

Each requirements file resolves with 'pip install --dry-run', which is what catches a bump that a passing test
suite cannot - a resolver conflict between transitive pins.

doc/Dependency.rst had drifted from the requirement files. Every version floor is taken from the requirements now,
eleven packages that are required but were never listed are added - docstr_coverage, lxml-stubs, docutils,
docutils_stubs, sphinx_rtd_theme, sphinxcontrib-mermaid, sphinxcontrib-autoprogram, autoapi, sphinx_design,
sphinx-copybutton and sphinx_reports - and two that are no longer required are dropped: sphinx_btd_theme and
sphinx_fontawesome, the latter already marked '!!' in the table.

Licences and project links for the new rows are from PyPI.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
…ach other

The defects fixed in #162 all lived between a writer and a reader, and no test looked there: nothing validated
written output against the bundled schemas, and nothing converted one dialect into another. 24 test files and 94
testcases, zero schema assertions.

tests/unit/JUnitDialects/ adds that level:

* Schemas.py - every reference output in tests/data validates against its dialect's schema, and the reader accepts
  what the schema accepts. The reference outputs are ground truth: the schemas were reverse-engineered from them.
* RoundTrip.py - per dialect: read a reference report, write it in the same dialect, validate it, read it back, and
  compare test case count, test case names and hostnames.
* Translation.py - the 5x5 conversion matrix, each cell validated against the target schema and read back with the
  target dialect.

Where a conversion cannot work today, KNOWN_GAPS names the pair and the reason and the test asserts that it *still*
fails, so a fix turns the expectation red instead of passing unnoticed. Six pairs are listed; two of them are
format limits rather than defects. The same pattern records that Any-JUnit rejects a <testsuite>-rooted report
although it is the permissive dialect.

tests/README.md writes down the strategy: the two phases, the four structural levels and how they map onto this
repository, why tests/data is evidence rather than fixtures, and the known-gap convention.

tests/unit: 98 -> 155 passed, 65 subtests.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
@Paebbels Paebbels added bug Something isn't working Dependencies documentation Improvements or additions to documentation enhancement New feature or request FileFormat: XML XML file format Unit Testing Unit test summaries labels Aug 16, 2026
claude-code and others added 4 commits August 16, 2026 12:01
… from pyproject.toml

* The version cells list major and minor only. A patch release does not change behaviour under semantic
  versioning, so the patch number is noise. A 0.0.x version is the exception - there the patch number is the only
  part that carries information - so docutils_stubs stays at 0.0.22.
* requirements.txt: 'pyTooling[terminal] >= 8.19' rather than '>= 8.19.0', per the review suggestion.
* The Packaging table listed pyTooling 8.18 and wheel, neither of which builds this package. It is generated from
  pyproject.toml's [build-system] requires now: setuptools and pyTooling.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
* Dialect uses the ExtendedType metaclass with slots, declares its fields with type hints, and its read-only
  properties are marked @readonly - including the Dialect property of the three test modules.
* readReference() calls Aggregate() before handing the summary over, as the command line does before writing. Two
  of the four "defects" the matrix reported were this missing call: without it the writers see zero test cases and
  no duration, so they omitted 'time' and the target schema rejected the result.
* KNOWN_GAPS is FORMAT_LIMITS. Every remaining entry names data the target format requires and the source does not
  carry - a timestamp, or more than the one test suite the format holds. A conversion failing for any other reason
  is a defect and does not belong in that table.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
CTest-JUnit.xsd and GoogleTest-JUnit.xsd require 'timestamp' - on <testsuite> and <testsuites>, and GoogleTest
down to <testcase>. Both writers emitted the attribute only when the model had a start time, so a report without
one produced a document their own reader and schema reject. GoogleTest was worse: the <testcase> timestamp was
written unguarded, so it raised 'AttributeError: NoneType object has no attribute isoformat' - the line carried a
'TODO: find a value'.

Both raise UnittestException naming the format, the element and what is missing:

    The GoogleTest + JUnit format requires a timestamp on <testsuites>, but the report has none.

Refusing is the honest answer here: the value is not ours to invent, and a report without timestamps is not
expressible in these dialects. Deriving a summary's start time from its children would remove the restriction for
sources that do carry timestamps deeper in the hierarchy - worth doing, but that changes what Aggregate() means
and belongs in its own pull-request.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
claude-code and others added 5 commits August 16, 2026 17:12
* _DIALECT is declared on the base Document beside _TESTCASE, _TESTCLASS and _TESTSUITE, defaulting to "JUnit";
  the dialects override it in the same aligned block, without the stray blank line.
* The timestamp check is written where it is used instead of going through a helper - once in CTestJUnit, three
  times in GoogleTestJUnit, whose schema requires the attribute down to <testcase>.
* tests/unit/Unittesting/Hostname.py: the import block is aligned to the longest module path again.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
The base classes derived from TestCase, so unittest collected them and pytest reported 11 skipped testcases that
test nothing. They are mixins now - SchemaMixin, RoundTripMixin, TranslationMixin - and each dialect class derives
from the mixin and TestCase.

They use 'metaclass=ExtendedType' without 'mixin=True': that option raises
'BaseClassWithoutSlotsError: Base-classes TestCase doesn't use __slots__', because unittest.TestCase has no
__slots__ and mixin=True requires them from every base class.

With the skip guard gone, tests/unit/JUnitDialects reports 57 passed and no skips.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
unittest.TestCase is not created by ExtendedType and has no __slots__, so a mixin created by ExtendedType cannot
be combined with it. Classic mixins are the right tool there: plain classes, no metaclass.

The doc-strings and tests/README.md say why, so the next reader doesn't 'fix' them back.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
claude-code and others added 2 commits August 16, 2026 17:35
'JUnit' names no dialect - a JUnit XML file is whatever the tool writing it produces. This class is not purely
infrastructure either: it is the implementation the command line uses for '--merge=Any-JUnit', so the accurate
value is that one.

Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Dependencies documentation Improvements or additions to documentation enhancement New feature or request FileFormat: XML XML file format Unit Testing Unit test summaries

Development

Successfully merging this pull request may close these issues.

2 participants