atsfill 0.0.5.dev188__tar.gz → 0.0.5.dev189__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/PKG-INFO +1 -1
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/pyproject.toml +1 -1
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/pyproject.toml.orig +1 -1
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/phenom.py +24 -3
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/LICENSE +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/README.md +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/__init__.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/__init__.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/adp.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/adpmyjobs.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/ashby.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/bamboohr.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/breezy.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/dayforce.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/eightfold.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/greenhouse.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/gupy.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/hireology.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/hiringthing.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/hrmdirect.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/isolvedhire.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/jazzhr.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/jobaffinity.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/jobstreet.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/join.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/lever.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/manatal.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/oracle.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/paycor.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/paylocity.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/personio.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/pinpoint.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/recruitee.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/recruiterflow.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/rippling.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/smartrecruiters.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/successfactors.js +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/successfactors.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/taleo.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/teamtailor.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/ukg.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/welcomekit.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/workable.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/workatastartup.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/workday.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/wttj.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/adapters/zohorecruit.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/cli.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/__init__.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/accounts.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/adapter.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/attempts.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/browser.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/commands.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/conditions.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/html.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/matching.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/otp.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/passwords.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/paths.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/registry.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/results.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/snapshot.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/core/telemetry.py +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/py.typed +0 -0
- {atsfill-0.0.5.dev188 → atsfill-0.0.5.dev189}/src/atsfill/registry.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atsfill
|
|
3
|
-
Version: 0.0.5.
|
|
3
|
+
Version: 0.0.5.dev189
|
|
4
4
|
Summary: Read, dry-run and submit job application forms on hiring systems: Ashby, Greenhouse, Teamtailor, Welcome to the Jungle.
|
|
5
5
|
Keywords: job-applications,ats,ashby,greenhouse,teamtailor,ai-agents,cli
|
|
6
6
|
Author: shbernal
|
|
@@ -73,6 +73,7 @@ YES_NO = ["Yes", "No"]
|
|
|
73
73
|
NO_YES = ["No", "Yes"]
|
|
74
74
|
MONTH = " (MM/YYYY)"
|
|
75
75
|
YEAR = " (year)"
|
|
76
|
+
NUMBER = " (a number)" # an input that takes only digits
|
|
76
77
|
PICKER = ".react-datepicker"
|
|
77
78
|
MONTHS: list[str] = [
|
|
78
79
|
"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
|
|
@@ -365,7 +366,7 @@ class Phenom:
|
|
|
365
366
|
self._open(page, fresh=True)
|
|
366
367
|
self._accept_terms(page)
|
|
367
368
|
self._kept, self._shown = {}, {}
|
|
368
|
-
if RESUME_ID in answers and page
|
|
369
|
+
if RESUME_ID in answers and _shows_upload(page):
|
|
369
370
|
_upload(page, _one(answers[RESUME_ID]))
|
|
370
371
|
self._kept[RESUME_ID] = PurePath(_one(answers[RESUME_ID])).name
|
|
371
372
|
for number in range(1, MAX_STEPS + 1):
|
|
@@ -664,7 +665,8 @@ class _Config:
|
|
|
664
665
|
if html == "daterangepicker" or widget == "daterangepicker":
|
|
665
666
|
return self.date_range(p, u, path, nav, when)
|
|
666
667
|
if p.get("type") == "array" and get(p, "items.properties") and html not in WIDGETS:
|
|
667
|
-
|
|
668
|
+
shown = p.get("minItems"), p.get("defaultEntries"), u.get("minItemsRequired")
|
|
669
|
+
if not any(int(n or 0) for n in shown):
|
|
668
670
|
return [] # entries only once Add is clicked
|
|
669
671
|
return self.object(p["items"], u.get("items") or {}, f"{path}[0].", nav, False, when)
|
|
670
672
|
if p.get("type") == "object" or html in ("object", "phoneNumber_v2"):
|
|
@@ -681,6 +683,7 @@ class _Config:
|
|
|
681
683
|
# a signature's date: today's, the only one the page takes
|
|
682
684
|
"prefilled": date.today().isoformat() if p.get("defaultTodayDate") is True else None,
|
|
683
685
|
"max_length": p.get("maxLength") if isinstance(p.get("maxLength"), int) else None,
|
|
686
|
+
"number": kind == "text" and _number(p, html, widget),
|
|
684
687
|
}
|
|
685
688
|
self.labels[path] = raw["label"]
|
|
686
689
|
if kind in ("select", "typeahead", "radio", "checkboxes"):
|
|
@@ -1084,7 +1087,10 @@ class _Config:
|
|
|
1084
1087
|
held = get(
|
|
1085
1088
|
{"phApp": self.ph}, get(self.config, f"uiSchema.{name}.preFillWindowObj") or ""
|
|
1086
1089
|
)
|
|
1087
|
-
held
|
|
1090
|
+
if held is None: # the job's data by its name (`jobCountry`), or the page's locale
|
|
1091
|
+
held = ({"locale": self.ph.get("locale")} | self.ddo).get(name)
|
|
1092
|
+
if "pattern" in test: # a job location naming a county
|
|
1093
|
+
return isinstance(held, str) and re.search(test["pattern"], held) is not None
|
|
1088
1094
|
return True if values is None else held in values
|
|
1089
1095
|
return Is(f"{path}{name}", values)
|
|
1090
1096
|
|
|
@@ -1249,6 +1255,11 @@ def _kind(p: dict, html: Any, widget: Any, path: str) -> str:
|
|
|
1249
1255
|
return "text"
|
|
1250
1256
|
|
|
1251
1257
|
|
|
1258
|
+
def _number(p: dict, html: Any, widget: Any) -> bool:
|
|
1259
|
+
"""Whether the input takes only digits (`input[type=number]`)."""
|
|
1260
|
+
return p.get("type") in ("integer", "number") or bool({html, widget} & {"number", "updown"})
|
|
1261
|
+
|
|
1262
|
+
|
|
1252
1263
|
def _picker(form: str) -> str:
|
|
1253
1264
|
"""The calendar a format picks from: `date` (a day), `month` (`MM/yyyy`), `year`."""
|
|
1254
1265
|
tokens = {t[0] for t in re.findall(r"y+|m+|d+", form.lower())}
|
|
@@ -1312,6 +1323,7 @@ def _field(raw: dict[str, Any]) -> Field:
|
|
|
1312
1323
|
if kind == "checkbox": # an optional box starts clear
|
|
1313
1324
|
options = YES_NO if raw["required"] else NO_YES
|
|
1314
1325
|
label = raw["label"] + {"month": MONTH, "year": YEAR}.get(kind, "")
|
|
1326
|
+
label += NUMBER if raw.get("number") else ""
|
|
1315
1327
|
sets = raw.get("option_sets")
|
|
1316
1328
|
field_type = (
|
|
1317
1329
|
FieldType.TYPEAHEAD if kind == "typeahead" and not options and not sets else TYPES[kind]
|
|
@@ -1469,6 +1481,15 @@ def _one(answer: Answer) -> str:
|
|
|
1469
1481
|
return answer if isinstance(answer, str) else answer[0]
|
|
1470
1482
|
|
|
1471
1483
|
|
|
1484
|
+
def _shows_upload(page: Page) -> bool:
|
|
1485
|
+
"""Whether the resume upload shows: on one site a moment after the form, past its terms."""
|
|
1486
|
+
try:
|
|
1487
|
+
page.locator(RESUME).first.wait_for(state="attached", timeout=FIELD_TIMEOUT_MS)
|
|
1488
|
+
except Timeout:
|
|
1489
|
+
return False
|
|
1490
|
+
return True
|
|
1491
|
+
|
|
1492
|
+
|
|
1472
1493
|
def _upload(page: Page, path: str) -> None:
|
|
1473
1494
|
"""Attaches the resume, taken once Phenom's `/fileUpload` answers or the page shows its
|
|
1474
1495
|
name, and waits for its parse, which fills and clears fields when it comes back: until
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|