Fix salary tool edge cases (#75)

* fix: handle salary tool edge cases

* fix: preserve Danish salary compounds
This commit is contained in:
Kushida
2026-07-08 21:12:36 +02:00
committed by GitHub
parent d4415dff16
commit 9e26de2c67
4 changed files with 68 additions and 10 deletions
+5 -2
View File
@@ -204,12 +204,15 @@ def format_entry(entry, metadata):
count = data.get("count")
index = data.get("index")
if count is not None or index is not None:
count_str = str(count) if count else "-"
if index is not None:
count_str = str(count) if count is not None else "-"
if isinstance(index, (int, float)):
diff = index - baseline
sign = "+" if diff >= 0 else ""
index_str = f"{index:.1f}"
diff_str = f"{sign}{diff:.1f}%"
elif index is not None:
index_str = str(index)
diff_str = ""
else:
index_str = "N/A*"
diff_str = ""
+17
View File
@@ -37,6 +37,13 @@ class DetectColumnTypeTests(unittest.TestCase):
with self.subTest(header=header):
self.assertEqual(detect_column_type(header), "count")
def test_count_inside_word_does_not_make_count_header(self):
self.assertIsNone(detect_column_type("Accounting Total"))
self.assertEqual(detect_column_type("Accounting Index"), "index")
def test_danish_compound_headers_still_match(self):
self.assertEqual(detect_column_type("Lønindeks"), "index")
def test_parse_sheet_preserves_category_name_with_letter_n(self):
ws = FakeWorksheet([
("Company", "Engineering Count", "Engineering Index"),
@@ -47,6 +54,16 @@ class DetectColumnTypeTests(unittest.TestCase):
self.assertEqual(companies[0]["categories"]["engineering"], {"count": 12, "index": 105.5})
def test_parse_sheet_groups_accounting_count_index_pair(self):
ws = FakeWorksheet([
("Company", "Accounting Count", "Accounting Index"),
("Example Corp", 12, 105.5),
])
companies = parse_sheet(ws)
self.assertEqual(companies[0]["categories"]["accounting"], {"count": 12, "index": 105.5})
if __name__ == "__main__":
unittest.main()
+41
View File
@@ -0,0 +1,41 @@
import unittest
from salary_lookup import format_entry
class FormatEntryTests(unittest.TestCase):
def test_zero_count_is_displayed_as_zero(self):
entry = {
"company": "Example Corp",
"city": "",
"categories": {
"public_data": {
"count": 0,
"index": 100.0,
},
},
}
rendered = format_entry(entry, {"index_baseline": 100, "index_label": "Index"})
self.assertRegex(rendered, r"Public Data\s+0\s+100\.0")
def test_text_index_does_not_crash(self):
entry = {
"company": "Example Corp",
"city": "",
"categories": {
"sample": {
"count": 3,
"index": "private",
},
},
}
rendered = format_entry(entry, {"index_baseline": 100, "index_label": "Index"})
self.assertIn("private", rendered)
if __name__ == "__main__":
unittest.main()
+5 -8
View File
@@ -42,6 +42,7 @@ COMPANY_PATTERNS = {"firma", "company", "virksomhed", "employer", "arbejdsgiver"
CITY_PATTERNS = {"by", "city", "kommune", "location", "lokation", "sted"}
COUNT_PATTERNS = {"antal", "count", "number", "n", "employees", "medarbejdere"}
INDEX_PATTERNS = {"indeks", "index", "idx", "salary", "løn", "median", "average", "gennemsnit"}
DANISH_COMPOUND_PATTERNS = {"antal", "indeks", "løn", "gennemsnit", "medarbejdere"}
def header_matches(header, patterns):
@@ -50,10 +51,9 @@ def header_matches(header, patterns):
tokens = set(re.findall(r"[a-zæøåöäü0-9]+", h))
for p in patterns:
if len(p) == 1:
if p in tokens:
return True
elif p in h:
if p in tokens:
return True
if p in DANISH_COMPOUND_PATTERNS and p in h:
return True
return False
@@ -62,10 +62,7 @@ def strip_type_patterns(header, patterns):
"""Remove count/index words from a header to derive a category name."""
name = header.lower()
for p in patterns:
if len(p) == 1:
name = re.sub(rf"\b{re.escape(p)}\b", "", name)
else:
name = name.replace(p, "")
name = re.sub(rf"(?<![a-zæøåöäü0-9]){re.escape(p)}(?![a-zæøåöäü0-9])", "", name)
return name.strip(" _-")