atsfill 0.0.6.dev196__tar.gz → 0.0.6.dev197__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.6.dev196 → atsfill-0.0.6.dev197}/PKG-INFO +1 -1
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/pyproject.toml +1 -1
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/pyproject.toml.orig +1 -1
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/phenom.py +3 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/teamtailor.py +11 -1
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/LICENSE +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/README.md +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/__init__.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/__init__.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/adp.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/adpmyjobs.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/ashby.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/bamboohr.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/breezy.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/dayforce.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/eightfold.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/greenhouse.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/gupy.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/hireology.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/hiringthing.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/hrmdirect.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/isolvedhire.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/jazzhr.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/jobaffinity.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/jobstreet.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/join.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/lever.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/manatal.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/oracle.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/paycor.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/paylocity.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/personio.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/pinpoint.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/recruitee.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/recruiterflow.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/rippling.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/smartrecruiters.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/successfactors.js +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/successfactors.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/taleo.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/ukg.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/welcomekit.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/werecruit.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/workable.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/workatastartup.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/workday.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/wttj.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/adapters/zohorecruit.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/cli.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/__init__.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/accounts.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/adapter.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/attempts.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/browser.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/commands.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/conditions.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/countries.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/html.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/matching.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/otp.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/passwords.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/paths.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/registry.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/results.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/snapshot.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/core/telemetry.py +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/py.typed +0 -0
- {atsfill-0.0.6.dev196 → atsfill-0.0.6.dev197}/src/atsfill/registry.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atsfill
|
|
3
|
-
Version: 0.0.6.
|
|
3
|
+
Version: 0.0.6.dev197
|
|
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
|
|
@@ -1088,6 +1088,9 @@ class _Config:
|
|
|
1088
1088
|
|
|
1089
1089
|
def test(self, name: str, test: dict, path: str, props: dict) -> bool | Condition:
|
|
1090
1090
|
values = [test["const"]] if "const" in test else test.get("enum")
|
|
1091
|
+
if "matchesAnyOf" in test: # Phenom's own keyword, one value a part of an `anyOf`
|
|
1092
|
+
held = test["matchesAnyOf"]
|
|
1093
|
+
values = held if isinstance(held, list) else [held]
|
|
1091
1094
|
if name == "resumeName": # `isNotEmpty`: a resume given
|
|
1092
1095
|
return Is(RESUME_ID)
|
|
1093
1096
|
if (
|
|
@@ -27,6 +27,7 @@ FORM = "#job-application-form"
|
|
|
27
27
|
QUESTION = ".question, [data-careersite--form-target=qualifyingAnswers]"
|
|
28
28
|
LOCKED = "[data-careersite--form-target=formContentWrapper].cursor-not-allowed"
|
|
29
29
|
LOCATION = "candidate[location][query]"
|
|
30
|
+
COOKIES = "dialog[data-controller~='common--cookies--alert']"
|
|
30
31
|
VIDEO = "[data-controller~='questions--tt-video-answer']"
|
|
31
32
|
UPLOAD = "forms--inputs--upload" # a drop zone's controller
|
|
32
33
|
CAREER_SITE = "a[href*='//www.teamtailor.com'], script[src*='teamtailor-cdn.com/assets/careersite']"
|
|
@@ -39,6 +40,7 @@ UPLOAD_TIMEOUT_S = 60
|
|
|
39
40
|
UPLOAD_TIMEOUT_MS = UPLOAD_TIMEOUT_S * 1000
|
|
40
41
|
UPLOAD_POLL_MS = 500
|
|
41
42
|
KEY_DELAY_MS = 30
|
|
43
|
+
SUGGESTION_TIMEOUT_MS = 10_000
|
|
42
44
|
QUESTION_TYPES = {
|
|
43
45
|
"text": FieldType.TEXT,
|
|
44
46
|
"number": FieldType.TEXT,
|
|
@@ -65,6 +67,10 @@ NOT_ASKED = re.compile(r"linkedin|referrer|social_image")
|
|
|
65
67
|
STANDARD_KINDS = ("text", "email", "tel", "textarea", "checkbox", "choices", "file", "location")
|
|
66
68
|
ANSWER_KIND = re.compile(r"\]\[(\w+)\](\[\])?$")
|
|
67
69
|
|
|
70
|
+
# Declines the optional cookies on a banner open as a modal (a "takeover"): hidden by the
|
|
71
|
+
# blocker, it still leaves the rest of the page inert, deaf to keys and clicks.
|
|
72
|
+
_DECLINE_TAKEOVER = """banners => banners.filter(b => b.matches(":modal"))
|
|
73
|
+
.forEach(b => b.querySelector("[data-action$='#disableAll']")?.click())"""
|
|
68
74
|
# Whether each custom or qualifying question shows, in the order `_read` lists them.
|
|
69
75
|
_VISIBLE = "(form, QUESTION) => [...form.querySelectorAll(QUESTION)].map(q => q.checkVisibility())"
|
|
70
76
|
# What the form will send: each field's value, a choice as its option's text, a file as the
|
|
@@ -203,6 +209,7 @@ class Teamtailor:
|
|
|
203
209
|
|
|
204
210
|
def fill(self, page: Page, answers: dict[str, Answer]) -> None:
|
|
205
211
|
form = page.locator(FORM)
|
|
212
|
+
page.locator(COOKIES).evaluate_all(_DECLINE_TAKEOVER)
|
|
206
213
|
self._videos = {}
|
|
207
214
|
for field_id in [i for i in answers if i in self._qualifying]:
|
|
208
215
|
self._fill(form, field_id, answers[field_id])
|
|
@@ -368,7 +375,10 @@ def _suggest(field: Field, host: Locator, answer: str) -> None:
|
|
|
368
375
|
box.fill("")
|
|
369
376
|
box.press_sequentially(answer, delay=KEY_DELAY_MS)
|
|
370
377
|
options = host.locator("[role=option]")
|
|
371
|
-
|
|
378
|
+
try:
|
|
379
|
+
options.first.wait_for(timeout=SUGGESTION_TIMEOUT_MS)
|
|
380
|
+
except browser.Timeout:
|
|
381
|
+
raise NotTaken(f"no suggestion for {answer!r} in {field.id}") from None
|
|
372
382
|
for i in range(options.count()):
|
|
373
383
|
if matching.matches(field, answer, options.nth(i).get_attribute("data-description") or ""):
|
|
374
384
|
browser.click(options.nth(i))
|
|
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
|