Europass import: the SkillsPassport XML reader reads its own fixture, not the files Cedefop's editor wrote #632

Closed
opened 2026-10-01 10:48:31 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, running the SkillsPassport XML reader on a document shaped like Cedefop's own published example.

Related to #54.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at plugins/europass/reader.py:370-376 (_read_experience), :403-407 (_read_education), :471-475 (_read_achievements), :440-453 (_read_skills), :338-342 (_read_person) and :259-264 (_date); _make_date moved to plugins/europass/common.py:55-77, with the int() calls at :68-73. The fixture and the test are unchanged, and the wiki sentence is now at Your-career-record.md:192-194.

The XML reader for the pre-2020 format expects a shape Cedefop's editor did not write, so a real file imports the person's name, address and headline and almost nothing of the career, and the review page does not say anything was left out. The JSON reader is not affected: the JSON form does keep its entries in an array under the singular key, with numeric months.

  • Where:

    • plugins/europass/reader.py:494-500 (_read_experience), :527-531 (_read_education), :595-599 (_read_achievements): each looks for a WorkExperience inside a WorkExperience, an Education inside an Education, an Achievement inside an Achievement.
    • plugins/europass/reader.py:564-577 (_read_skills): MotherTongue and ForeignLanguage as direct children of Linguistic.
    • plugins/europass/reader.py:465-469 (_read_person): Telephone and Website as direct children of ContactInfo.
    • plugins/europass/reader.py:382-387 (_date) into plugins/europass/reader.py:156-161 (_make_date): the month and day attributes go to int().
    • tests/data/europass.xml:2-9 and tests/test_europass.py:56 (test_it_reads_the_shape_a_real_export_has): the fixture was written to the reader's shape.
    • The wiki, Your-career-record.md:185-187: "the XML or the PDF the Europass CV editor made before 2020" is said to read.
  • What happens:

    1. Cedefop's schema (v3.x) wraps each list: WorkExperienceList, EducationList, AchievementList, MotherTongueList, ForeignLanguageList, TelephoneList (and, by the same schema, WebsiteList). Its own example, europass-cv-example-v3.3.0.xml in the europass/rest-examples-java repository (src/main/resources/assets/input/), has LearnerInfo children Identification, Headline, WorkExperienceList, EducationList, Skills, AchievementList.
    2. The same example writes a month as month="--08" and a day as day="---01" (xs:gMonth, xs:gDay). _make_date passes them to int(), catches the ValueError and returns no date.
    3. Run against the snapshot with a document of that shape: experience [], education [], languages [], projects [], no telephone number, skipped []. Only the name, email, address, headline and the free-prose skill blocks are read. With no skill prose in the file the answer is "That file was read, and there was nothing in it to import."
    4. With the wrappers renamed so that the entries are found, every entry dated with a month comes out as ('Independent consultant', None, None): no start date, so importing.apply then leaves the job out as having no start.

    The fixture has month="03" and nested same-name wrappers, so the tests pass. Nothing in the package handles a *List element or a leading hyphen. The same reader handles the XML attached to a pre-2020 Europass PDF (pdf-xml).

  • Why it matters: this format exists only to rescue what people still have on their disks, and for those files the import silently reads next to nothing. The XML reader has no "was in the file but could not be read" note, as the JSON and Candidate readers have, so the person cannot tell a short record from an unread one.

  • Fix: in the XML reader, find each list under either name (the *List wrapper, or the nested form the fixture uses) for work experience, education, achievements, mother tongues, foreign languages, telephones and websites. Strip the leading hyphens of gMonth and gDay before _make_date. Add a fixture cut down from Cedefop's published example, with its provenance in the first comment as tests/data/europass-candidate-sample.xml has. Give the XML reader the notes in record.skipped that the other two readers have, so an unknown shape is named on the review page.

Related to #318, which checks the Candidate reader against a real download and does not cover this format. A separate finding of this review (the SkillsPassport readers keeping HTML markup) touches the same functions.

Done when

  • A test in tests/test_europass.py reads a fixture in Cedefop's own shape (*List wrappers, month="--08", day="---01") and asserts the counts of experience, education, languages and projects, the telephone number, and one entry's start date with its month.
  • tests/data/europass.xml no longer claims to be the shape a real export has, or is replaced by the fixture above.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, running the SkillsPassport XML reader on a document shaped like Cedefop's own published example. Related to #54. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `plugins/europass/reader.py:370-376` (`_read_experience`), `:403-407` (`_read_education`), `:471-475` (`_read_achievements`), `:440-453` (`_read_skills`), `:338-342` (`_read_person`) and `:259-264` (`_date`); `_make_date` moved to `plugins/europass/common.py:55-77`, with the `int()` calls at `:68-73`. The fixture and the test are unchanged, and the wiki sentence is now at `Your-career-record.md:192-194`. The XML reader for the pre-2020 format expects a shape Cedefop's editor did not write, so a real file imports the person's name, address and headline and almost nothing of the career, and the review page does not say anything was left out. The JSON reader is not affected: the JSON form does keep its entries in an array under the singular key, with numeric months. - **Where:** - `plugins/europass/reader.py:494-500` (`_read_experience`), `:527-531` (`_read_education`), `:595-599` (`_read_achievements`): each looks for a `WorkExperience` inside a `WorkExperience`, an `Education` inside an `Education`, an `Achievement` inside an `Achievement`. - `plugins/europass/reader.py:564-577` (`_read_skills`): `MotherTongue` and `ForeignLanguage` as direct children of `Linguistic`. - `plugins/europass/reader.py:465-469` (`_read_person`): `Telephone` and `Website` as direct children of `ContactInfo`. - `plugins/europass/reader.py:382-387` (`_date`) into `plugins/europass/reader.py:156-161` (`_make_date`): the month and day attributes go to `int()`. - `tests/data/europass.xml:2-9` and `tests/test_europass.py:56` (`test_it_reads_the_shape_a_real_export_has`): the fixture was written to the reader's shape. - The wiki, `Your-career-record.md:185-187`: "the **XML** or the **PDF** the Europass CV editor made before 2020" is said to read. - **What happens:** 1. Cedefop's schema (v3.x) wraps each list: `WorkExperienceList`, `EducationList`, `AchievementList`, `MotherTongueList`, `ForeignLanguageList`, `TelephoneList` (and, by the same schema, `WebsiteList`). Its own example, `europass-cv-example-v3.3.0.xml` in the `europass/rest-examples-java` repository (`src/main/resources/assets/input/`), has `LearnerInfo` children `Identification`, `Headline`, `WorkExperienceList`, `EducationList`, `Skills`, `AchievementList`. 2. The same example writes a month as `month="--08"` and a day as `day="---01"` (`xs:gMonth`, `xs:gDay`). `_make_date` passes them to `int()`, catches the `ValueError` and returns no date. 3. Run against the snapshot with a document of that shape: `experience []`, `education []`, `languages []`, `projects []`, no telephone number, `skipped []`. Only the name, email, address, headline and the free-prose skill blocks are read. With no skill prose in the file the answer is "That file was read, and there was nothing in it to import." 4. With the wrappers renamed so that the entries are found, every entry dated with a month comes out as `('Independent consultant', None, None)`: no start date, so `importing.apply` then leaves the job out as having no start. The fixture has `month="03"` and nested same-name wrappers, so the tests pass. Nothing in the package handles a `*List` element or a leading hyphen. The same reader handles the XML attached to a pre-2020 Europass PDF (`pdf-xml`). - **Why it matters:** this format exists only to rescue what people still have on their disks, and for those files the import silently reads next to nothing. The XML reader has no "was in the file but could not be read" note, as the JSON and Candidate readers have, so the person cannot tell a short record from an unread one. - **Fix:** in the XML reader, find each list under either name (the `*List` wrapper, or the nested form the fixture uses) for work experience, education, achievements, mother tongues, foreign languages, telephones and websites. Strip the leading hyphens of `gMonth` and `gDay` before `_make_date`. Add a fixture cut down from Cedefop's published example, with its provenance in the first comment as `tests/data/europass-candidate-sample.xml` has. Give the XML reader the notes in `record.skipped` that the other two readers have, so an unknown shape is named on the review page. Related to #318, which checks the Candidate reader against a real download and does not cover this format. A separate finding of this review (the SkillsPassport readers keeping HTML markup) touches the same functions. ## Done when - A test in `tests/test_europass.py` reads a fixture in Cedefop's own shape (`*List` wrappers, `month="--08"`, `day="---01"`) and asserts the counts of experience, education, languages and projects, the telephone number, and one entry's start date with its month. - `tests/data/europass.xml` no longer claims to be the shape a real export has, or is replaced by the fixture above.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:48:31 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#632
No description provided.