atsfill 0.0.5.dev193__tar.gz → 0.0.5.dev194__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.dev193 → atsfill-0.0.5.dev194}/PKG-INFO +1 -1
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/pyproject.toml +1 -1
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/pyproject.toml.orig +1 -1
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/teamtailor.py +6 -2
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/adapter.py +9 -1
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/commands.py +3 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/LICENSE +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/README.md +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/__init__.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/__init__.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/adp.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/adpmyjobs.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/ashby.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/bamboohr.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/breezy.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/dayforce.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/eightfold.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/greenhouse.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/gupy.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/hireology.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/hiringthing.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/hrmdirect.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/isolvedhire.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/jazzhr.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/jobaffinity.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/jobstreet.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/join.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/lever.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/manatal.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/oracle.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/paycor.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/paylocity.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/personio.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/phenom.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/pinpoint.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/recruitee.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/recruiterflow.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/rippling.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/smartrecruiters.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/successfactors.js +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/successfactors.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/taleo.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/ukg.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/welcomekit.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/werecruit.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/workable.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/workatastartup.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/workday.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/wttj.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/adapters/zohorecruit.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/cli.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/__init__.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/accounts.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/attempts.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/browser.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/conditions.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/countries.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/html.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/matching.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/otp.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/passwords.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/paths.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/registry.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/results.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/snapshot.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/core/telemetry.py +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/src/atsfill/py.typed +0 -0
- {atsfill-0.0.5.dev193 → atsfill-0.0.5.dev194}/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.dev194
|
|
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
|
|
@@ -16,7 +16,7 @@ from typing import Any
|
|
|
16
16
|
from urllib.parse import urlsplit
|
|
17
17
|
|
|
18
18
|
from atsfill.core import browser, html, matching
|
|
19
|
-
from atsfill.core.adapter import Gap, NotTaken, Unsupported, known_gap
|
|
19
|
+
from atsfill.core.adapter import Gap, Held, NotTaken, Unsupported, known_gap
|
|
20
20
|
from atsfill.core.browser import HTTP_TIMEOUT_S, Locator, Page, Response
|
|
21
21
|
from atsfill.core.html import Node
|
|
22
22
|
from atsfill.core.results import Answer, Field, FieldType, Is, SideEffect
|
|
@@ -31,6 +31,8 @@ VIDEO = "[data-controller~='questions--tt-video-answer']"
|
|
|
31
31
|
UPLOAD = "forms--inputs--upload" # a drop zone's controller
|
|
32
32
|
CAREER_SITE = "a[href*='//www.teamtailor.com'], script[src*='teamtailor-cdn.com/assets/careersite']"
|
|
33
33
|
JOB = re.compile(r"/jobs/(\d+)[^/]*")
|
|
34
|
+
EMAIL_LINK = "/applications/email_verification_needed"
|
|
35
|
+
SENT = re.compile(rf"/applications/[^/]+/thanks|{EMAIL_LINK}")
|
|
34
36
|
SUBMIT_TIMEOUT_MS = 90_000
|
|
35
37
|
FOLLOW_UP_TIMEOUT_MS = 1_000
|
|
36
38
|
UPLOAD_TIMEOUT_S = 60
|
|
@@ -235,7 +237,9 @@ class Teamtailor:
|
|
|
235
237
|
|
|
236
238
|
def submit(self, page: Page) -> str | None:
|
|
237
239
|
browser.click(page.locator(f"{FORM} [type=submit]"))
|
|
238
|
-
page.wait_for_url(
|
|
240
|
+
page.wait_for_url(SENT, timeout=SUBMIT_TIMEOUT_MS, wait_until="domcontentloaded")
|
|
241
|
+
if page.url.split("?")[0].endswith(EMAIL_LINK):
|
|
242
|
+
raise Held("click the link emailed to the applicant to complete it")
|
|
239
243
|
return page.url
|
|
240
244
|
|
|
241
245
|
def _fill(self, form: Locator, field_id: str, answer: Answer) -> None:
|
|
@@ -15,6 +15,13 @@ class Blocked(Exception):
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
class Held(Exception):
|
|
19
|
+
"""Raised by `submit`: the system has the application but holds it until the applicant
|
|
20
|
+
acts, e.g. clicks an emailed link. The send counts as `submitted`, the message is the
|
|
21
|
+
reason's detail (ADR 0006).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
18
25
|
class SignedOut(Blocked):
|
|
19
26
|
"""The system's page asks to sign in although `signed_in` found the session holding: the
|
|
20
27
|
system ended it its own way. The core signs in again and reads once more (ADR 0015).
|
|
@@ -94,7 +101,8 @@ class Adapter(Protocol):
|
|
|
94
101
|
def submit(self, page: Page) -> str | None:
|
|
95
102
|
"""Clicks submit; returns the evidence (a URL or a network response), None without.
|
|
96
103
|
|
|
97
|
-
Raises `Blocked` when the system refuses the send
|
|
104
|
+
Raises `Blocked` when the system refuses the send, `Held` when it has the application but
|
|
105
|
+
holds it until the applicant acts.
|
|
98
106
|
"""
|
|
99
107
|
...
|
|
100
108
|
|
|
@@ -25,6 +25,7 @@ from atsfill.core.adapter import (
|
|
|
25
25
|
Blocked,
|
|
26
26
|
CreatesAccount,
|
|
27
27
|
CreatesAccountByOtp,
|
|
28
|
+
Held,
|
|
28
29
|
KeepsProfile,
|
|
29
30
|
ListsShownFields,
|
|
30
31
|
NeedsAccount,
|
|
@@ -503,6 +504,8 @@ def _on_page(
|
|
|
503
504
|
result.status = Status.SUBMITTED
|
|
504
505
|
else:
|
|
505
506
|
result.status, result.reason = Status.UNKNOWN, "no_evidence"
|
|
507
|
+
except Held as e:
|
|
508
|
+
result.status, result.evidence, result.reason = Status.SUBMITTED, page.url, f"held: {e}"
|
|
506
509
|
except Blocked as e:
|
|
507
510
|
result.status, result.reason = Status.BLOCKED, str(e)
|
|
508
511
|
except Exception as e: # after the click, nothing tells a failed send from a sent one
|
|
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
|