atsfill 0.0.8.dev224__tar.gz → 0.0.8.dev226__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.8.dev224 → atsfill-0.0.8.dev226}/PKG-INFO +1 -1
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/pyproject.toml +1 -1
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/pyproject.toml.orig +1 -1
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/eightfold.py +37 -3
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/LICENSE +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/README.md +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/__init__.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/__init__.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/adp.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/adpmyjobs.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/ashby.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/bamboohr.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/breezy.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/dayforce.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/greenhouse.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/gupy.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/hireology.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/hiringthing.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/hrmdirect.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/isolvedhire.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/jazzhr.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/jobaffinity.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/jobstreet.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/join.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/lever.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/manatal.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/oracle.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/paycor.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/paylocity.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/personio.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/phenom.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/pinpoint.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/recruitee.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/recruiterflow.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/rippling.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/smartrecruiters.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/successfactors.js +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/successfactors.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/taleo.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/teamtailor.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/ukg.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/welcomekit.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/wellfound.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/werecruit.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/workable.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/workatastartup.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/workday.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/wttj.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/adapters/zohorecruit.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/cli.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/__init__.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/accounts.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/adapter.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/attempts.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/browser.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/commands.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/conditions.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/countries.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/html.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/matching.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/otp.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/passwords.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/paths.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/registry.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/results.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/snapshot.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/core/telemetry.py +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/py.typed +0 -0
- {atsfill-0.0.8.dev224 → atsfill-0.0.8.dev226}/src/atsfill/registry.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atsfill
|
|
3
|
-
Version: 0.0.8.
|
|
3
|
+
Version: 0.0.8.dev226
|
|
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
|
|
@@ -36,6 +36,9 @@ PICKER = "[data-testid=picker-dialog]"
|
|
|
36
36
|
FORM_TIMEOUT_MS = 30_000
|
|
37
37
|
SHOWN_TIMEOUT_MS = 2_000
|
|
38
38
|
OPTIONS_TIMEOUT_MS = 5_000
|
|
39
|
+
FOCUS_TIMEOUT_MS = 500
|
|
40
|
+
LIST_CLOSE_TIMEOUT_MS = 2_000 # a list can close late on a page still loading
|
|
41
|
+
PICK_CLICKS = 3 # the list can lose a click on its option
|
|
39
42
|
UPLOAD_TIMEOUT_MS = 30_000
|
|
40
43
|
SUBMIT_TIMEOUT_MS = 90_000
|
|
41
44
|
PARSE_SETTLE_MS = 2_000
|
|
@@ -479,18 +482,49 @@ def _pick(page: Page, combo, value: str, exact: bool) -> None:
|
|
|
479
482
|
if not option.count():
|
|
480
483
|
page.keyboard.press("Escape")
|
|
481
484
|
raise NotTaken(f"no option {value!r}")
|
|
482
|
-
option
|
|
485
|
+
_choose(page, combo, option)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def _choose(page: Page, combo, option) -> None:
|
|
489
|
+
"""Clicks a combobox's option and waits for its list to close and the combobox to take the
|
|
490
|
+
focus back: typed before that, the next answer lands in the combobox. A list still open over
|
|
491
|
+
an unchanged combobox lost the click, so the option is clicked again; clicked once it took,
|
|
492
|
+
it would clear. A list that stays open is dismissed, as it lies over the next control, for
|
|
493
|
+
the read-back to catch what the combobox holds."""
|
|
494
|
+
listbox = page.locator(f"[id={json.dumps(combo.get_attribute('aria-controls'))}]")
|
|
495
|
+
held = combo.input_value()
|
|
496
|
+
for _ in range(PICK_CLICKS):
|
|
497
|
+
with suppress(Timeout):
|
|
498
|
+
option.click(timeout=LIST_CLOSE_TIMEOUT_MS)
|
|
499
|
+
listbox.wait_for(state="hidden", timeout=LIST_CLOSE_TIMEOUT_MS)
|
|
500
|
+
if listbox.is_hidden():
|
|
501
|
+
with suppress(Timeout):
|
|
502
|
+
page.wait_for_function(
|
|
503
|
+
"el => document.activeElement === el",
|
|
504
|
+
arg=combo.element_handle(),
|
|
505
|
+
timeout=FOCUS_TIMEOUT_MS,
|
|
506
|
+
)
|
|
507
|
+
return
|
|
508
|
+
if combo.input_value() != held:
|
|
509
|
+
break
|
|
510
|
+
combo.press("Escape")
|
|
483
511
|
|
|
484
512
|
|
|
485
513
|
def _phone(page: Page, box, value: str) -> None:
|
|
486
514
|
"""Picks the country code the number starts with, the longest that fits, then types the
|
|
487
|
-
rest of the number. Where several countries share it, its main country.
|
|
515
|
+
rest of the number. Where several countries share it, its main country. One already showing
|
|
516
|
+
a code that fits stays: clicking the selected option clears it."""
|
|
488
517
|
digits = re.sub(r"\D", "", value)
|
|
489
518
|
combo = box.locator("input[role=combobox]").first
|
|
490
519
|
number = box.locator("input:not([role=combobox])").first
|
|
491
520
|
if not value.startswith("+"):
|
|
492
521
|
number.fill(value)
|
|
493
522
|
return
|
|
523
|
+
if (held := DIAL.search(combo.input_value())) and digits.startswith(
|
|
524
|
+
code := held[1].replace(" ", "")
|
|
525
|
+
):
|
|
526
|
+
number.fill(digits[len(code) :])
|
|
527
|
+
return
|
|
494
528
|
_click(combo)
|
|
495
529
|
options = page.locator(f"[id={json.dumps(combo.get_attribute('aria-controls'))}] [role=option]")
|
|
496
530
|
options.first.wait_for(timeout=OPTIONS_TIMEOUT_MS)
|
|
@@ -504,7 +538,7 @@ def _phone(page: Page, box, value: str) -> None:
|
|
|
504
538
|
number.fill(digits)
|
|
505
539
|
return
|
|
506
540
|
_, _, i, code = max(fits)
|
|
507
|
-
options.nth(-i)
|
|
541
|
+
_choose(page, combo, options.nth(-i))
|
|
508
542
|
number.fill(digits[len(code) :])
|
|
509
543
|
|
|
510
544
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|