atsfill 0.0.4.dev37__tar.gz → 0.0.4.dev38__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.4.dev37 → atsfill-0.0.4.dev38}/PKG-INFO +1 -1
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/pyproject.toml +2 -2
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/pyproject.toml.orig +2 -2
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/bamboohr.py +5 -2
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/dayforce.py +2 -1
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/paylocity.py +2 -1
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/recruitee.py +1 -1
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/LICENSE +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/README.md +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/__init__.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/__init__.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/ashby.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/breezy.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/greenhouse.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/hireology.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/jazzhr.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/lever.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/manatal.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/oracle.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/paycor.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/smartrecruiters.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/teamtailor.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/workable.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/adapters/wttj.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/cli.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/__init__.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/accounts.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/adapter.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/attempts.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/browser.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/commands.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/matching.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/paths.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/registry.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/core/results.py +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/py.typed +0 -0
- {atsfill-0.0.4.dev37 → atsfill-0.0.4.dev38}/src/atsfill/registry.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atsfill
|
|
3
|
-
Version: 0.0.4.
|
|
3
|
+
Version: 0.0.4.dev38
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "atsfill"
|
|
3
|
-
version = "0.0.4.
|
|
3
|
+
version = "0.0.4.dev38"
|
|
4
4
|
description = "Read, dry-run and submit job application forms on hiring systems: Ashby, Greenhouse, Teamtailor, Welcome to the Jungle."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -68,7 +68,7 @@ select = [
|
|
|
68
68
|
[tool.pytest.ini_options]
|
|
69
69
|
testpaths = ["tests"]
|
|
70
70
|
markers = ["live: drives a real hiring system page with data from .env and .tmp/; opt-in with -m live"]
|
|
71
|
-
addopts = "-m 'not live' -n 8"
|
|
71
|
+
addopts = "-m 'not live' -n 8 --dist loadscope"
|
|
72
72
|
|
|
73
73
|
[[tool.uv.index]]
|
|
74
74
|
name = "testpypi"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "atsfill"
|
|
3
|
-
version = "0.0.4.
|
|
3
|
+
version = "0.0.4.dev38"
|
|
4
4
|
description = "Read, dry-run and submit job application forms on hiring systems: Ashby, Greenhouse, Teamtailor, Welcome to the Jungle."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -55,7 +55,7 @@ testpaths = ["tests"]
|
|
|
55
55
|
markers = [
|
|
56
56
|
"live: drives a real hiring system page with data from .env and .tmp/; opt-in with -m live",
|
|
57
57
|
]
|
|
58
|
-
addopts = "-m 'not live' -n 8"
|
|
58
|
+
addopts = "-m 'not live' -n 8 --dist loadscope"
|
|
59
59
|
|
|
60
60
|
[[tool.uv.index]]
|
|
61
61
|
name = "testpypi"
|
|
@@ -30,6 +30,7 @@ CHALLENGE = "iframe[src*='recaptcha/api2/bframe']"
|
|
|
30
30
|
FORM_TIMEOUT_MS = 30_000
|
|
31
31
|
UPLOAD_TIMEOUT_MS = 30_000
|
|
32
32
|
SHOWN_TIMEOUT_MS = 2_000
|
|
33
|
+
STATES_TIMEOUT_MS = 15_000 # for the state's list a country change refetches
|
|
33
34
|
SETTLE_MS = 300 # for React to render what a response brought
|
|
34
35
|
CAPTCHA_TIMEOUT_MS = 20_000
|
|
35
36
|
SUBMIT_TIMEOUT_MS = 90_000
|
|
@@ -215,12 +216,14 @@ class BambooHR:
|
|
|
215
216
|
case "file":
|
|
216
217
|
_attach(form, str(name), answer)
|
|
217
218
|
case "select" if field_id == "countryId":
|
|
219
|
+
if _shown(control) == value:
|
|
220
|
+
continue # the state's list stays
|
|
218
221
|
with (
|
|
219
222
|
suppress(Timeout),
|
|
220
223
|
page.expect_response(
|
|
221
|
-
lambda r: "/ajax/get_states" in r.url, timeout=
|
|
224
|
+
lambda r: "/ajax/get_states" in r.url, timeout=STATES_TIMEOUT_MS
|
|
222
225
|
),
|
|
223
|
-
): # the state's list follows the country
|
|
226
|
+
): # the state's list follows the country
|
|
224
227
|
_pick(page, control, value)
|
|
225
228
|
page.wait_for_timeout(SETTLE_MS)
|
|
226
229
|
case "select":
|
|
@@ -35,6 +35,7 @@ STEP_TIMEOUT_MS = 20_000
|
|
|
35
35
|
SUBMIT_TIMEOUT_MS = 90_000
|
|
36
36
|
UPDATE_TRIES = 3
|
|
37
37
|
FOLLOWUP_TIMEOUT_MS = 3_000
|
|
38
|
+
DIAL_TIMEOUT_MS = 2_000 # per dial code tried, longest first
|
|
38
39
|
NEXT_TRIES = 3
|
|
39
40
|
STEP_POLLS = 16 # of POLL_MS, before Next is clicked again
|
|
40
41
|
POLL_MS = 500
|
|
@@ -769,7 +770,7 @@ def _fill_phone(page: Page, selector: str, value: str) -> None:
|
|
|
769
770
|
dial.press_sequentially(f"+{code}", delay=10)
|
|
770
771
|
options = page.locator(_option(dial)).filter(has_text=re.compile(rf"\+{code}(\s|$)"))
|
|
771
772
|
with suppress(Timeout):
|
|
772
|
-
options.first.wait_for(timeout=
|
|
773
|
+
options.first.wait_for(timeout=DIAL_TIMEOUT_MS)
|
|
773
774
|
if options.count():
|
|
774
775
|
main = options.filter(has_text=MAIN_COUNTRY.get(code, "\0"))
|
|
775
776
|
(main if main.count() else options).first.click()
|
|
@@ -31,6 +31,7 @@ SUBMIT = "[data-automation-id=btnSubmit]"
|
|
|
31
31
|
STEP = "#appDetailDiv .type-bold.float-right" # "Step 2 of 5"
|
|
32
32
|
FORCED_RESUME = ".modal.in #btn-forceResume"
|
|
33
33
|
FORM_TIMEOUT_MS = 30_000
|
|
34
|
+
COOKIE_TIMEOUT_MS = 5_000
|
|
34
35
|
STEP_TIMEOUT_MS = 20_000
|
|
35
36
|
UPLOAD_TIMEOUT_MS = 30_000
|
|
36
37
|
SUBMIT_TIMEOUT_MS = 90_000
|
|
@@ -473,7 +474,7 @@ def _present(page: Page, control: Control) -> bool:
|
|
|
473
474
|
def _dismiss_cookies(page: Page) -> None:
|
|
474
475
|
close = page.locator("#onetrust-banner-sdk .onetrust-close-btn-handler")
|
|
475
476
|
with suppress(Timeout):
|
|
476
|
-
close.first.wait_for(state="visible", timeout=
|
|
477
|
+
close.first.wait_for(state="visible", timeout=COOKIE_TIMEOUT_MS)
|
|
477
478
|
close.first.click()
|
|
478
479
|
|
|
479
480
|
|
|
@@ -63,7 +63,7 @@ _READ = """form => {
|
|
|
63
63
|
field = {id: name, required: false, options: [], accept: null,
|
|
64
64
|
maxLength: el.maxLength > 0 ? el.maxLength : null};
|
|
65
65
|
if (el.type === "radio") field.kind = "radio";
|
|
66
|
-
else if (el.type === "checkbox" &&
|
|
66
|
+
else if (el.type === "checkbox" && /\\.(flag|consent)$/.test(name)) {
|
|
67
67
|
field.kind = "legal";
|
|
68
68
|
field.label = text(form.querySelector(`[id="${el.getAttribute("aria-labelledby")}"]`));
|
|
69
69
|
} else if (el.type === "checkbox") field.kind = "checkboxes";
|
|
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
|