mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(salary): parse Unicode whitespace grouping (#592)
* fix(salary): parse Unicode whitespace grouping * docs(changelog): record fix for #592
This commit is contained in:
1 parent
8cc2efbf21
commit
ef4d12711c
3 files changed
+68
-1
No files matched your search
@@ -200,6 +200,8 @@ per-file diff commands.
|
|||||||
command that does not exist and prompted instead; the string now names the real path, matching
|
command that does not exist and prompted instead; the string now names the real path, matching
|
||||||
the six shipped `SKILL.md` files.
|
the six shipped `SKILL.md` files.
|
||||||
|
|
||||||
|
- **Salary workbook conversion accepts Unicode whitespace grouping** (#592) - numeric cells written as text with non-breaking or narrow non-breaking grouping spaces now parse without losing their values.
|
||||||
|
|
||||||
- **`robots_check` unquotes incoming query strings and restricts `$` anchors to pattern end**
|
- **`robots_check` unquotes incoming query strings and restricts `$` anchors to pattern end**
|
||||||
(#543, `tools/robots_check.py`, `tests/test_robots_check.py`) - two path-matching edge cases in
|
(#543, `tools/robots_check.py`, `tests/test_robots_check.py`) - two path-matching edge cases in
|
||||||
the robots.txt gate failed open. First, `gate(url)` called `unquote(parts.path)` but concatenated
|
the robots.txt gate failed open. First, `gate(url)` called `unquote(parts.path)` but concatenated
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
"""Preserve space-grouped numbers through the real workbook converter CLI."""
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
try:
|
||||||
|
import openpyxl
|
||||||
|
except ImportError:
|
||||||
|
openpyxl = None
|
||||||
|
|
||||||
|
|
||||||
|
TOOL = Path(__file__).resolve().parent.parent / "tools" / "convert_salary_excel.py"
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(openpyxl, "requires optional openpyxl (installed in CI)")
|
||||||
|
class GroupingCLI(unittest.TestCase):
|
||||||
|
def convert(self, rows):
|
||||||
|
with TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
workbook, output = root / "salary.xlsx", root / "salary_data.json"
|
||||||
|
book = openpyxl.Workbook()
|
||||||
|
try:
|
||||||
|
book.active.append(["Company", "Count", "Salary"])
|
||||||
|
for row in rows:
|
||||||
|
book.active.append(row)
|
||||||
|
book.save(workbook)
|
||||||
|
finally:
|
||||||
|
book.close()
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, str(TOOL), str(workbook), "--output", str(output)],
|
||||||
|
cwd=root, capture_output=True, text=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
|
||||||
|
return json.loads(output.read_text(encoding="utf-8"))["companies"]
|
||||||
|
|
||||||
|
def test_unicode_space_grouping_preserves_count_and_salary(self):
|
||||||
|
rows = [
|
||||||
|
["Narrow Space Corp", "1\u202f234", "42\u202f000,50"],
|
||||||
|
["Thin Space Corp", "2\u2009234", "52\u2009000.50"],
|
||||||
|
]
|
||||||
|
companies = self.convert(rows)
|
||||||
|
self.assertEqual([entry["categories"] for entry in companies], [
|
||||||
|
{"all_employees": {"count": 1234, "index": 42000.5}},
|
||||||
|
{"all_employees": {"count": 2234, "index": 52000.5}},
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_existing_space_groups_and_ambiguous_separators_are_unchanged(self):
|
||||||
|
rows = [
|
||||||
|
["ASCII Corp", "1 234", "42 000,50"],
|
||||||
|
["NBSP Corp", "1\u00a0234", "42\u00a0000.50"],
|
||||||
|
["Numeric Corp", 1234, 42000.5],
|
||||||
|
["Ambiguous Corp", "1,234", "42.000"],
|
||||||
|
]
|
||||||
|
companies = self.convert(rows)
|
||||||
|
expected = {"all_employees": {"count": 1234, "index": 42000.5}}
|
||||||
|
self.assertEqual([entry["categories"] for entry in companies[:3]], [expected] * 3)
|
||||||
|
self.assertEqual(companies[3]["categories"], {})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -65,7 +65,8 @@ def parse_numeric_cell(value):
|
|||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError("not numeric")
|
raise ValueError("not numeric")
|
||||||
|
|
||||||
text = value.strip().replace("\u00a0", " ").replace(" ", "")
|
# Localized exports also use narrow no-break and thin spaces for grouping.
|
||||||
|
text = "".join(value.split())
|
||||||
if not text:
|
if not text:
|
||||||
raise ValueError("not numeric")
|
raise ValueError("not numeric")
|
||||||
if "," in text and "." in text:
|
if "," in text and "." in text:
|
||||||
|
|||||||
Reference in new issue
Block a user