atsfill 0.0.4.dev44__tar.gz → 0.0.4.dev47__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.
Files changed (38) hide show
  1. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/PKG-INFO +3 -3
  2. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/README.md +2 -2
  3. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/pyproject.toml +2 -3
  4. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/pyproject.toml.orig +2 -5
  5. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/__init__.py +2 -0
  6. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/breezy.py +0 -3
  7. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/dayforce.py +0 -3
  8. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/jazzhr.py +0 -3
  9. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/lever.py +0 -3
  10. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/oracle.py +0 -3
  11. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/paycor.py +0 -3
  12. atsfill-0.0.4.dev47/src/atsfill/adapters/phenom.py +1353 -0
  13. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/recruitee.py +0 -3
  14. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/smartrecruiters.py +0 -3
  15. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/teamtailor.py +0 -3
  16. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/wttj.py +0 -3
  17. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/adapter.py +9 -4
  18. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/browser.py +5 -3
  19. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/commands.py +3 -1
  20. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/registry.py +23 -5
  21. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/registry.toml +5 -0
  22. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/LICENSE +0 -0
  23. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/__init__.py +0 -0
  24. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/ashby.py +0 -0
  25. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/bamboohr.py +0 -0
  26. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/greenhouse.py +0 -0
  27. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/hireology.py +0 -0
  28. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/manatal.py +0 -0
  29. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/paylocity.py +0 -0
  30. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/adapters/workable.py +0 -0
  31. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/cli.py +0 -0
  32. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/__init__.py +0 -0
  33. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/accounts.py +0 -0
  34. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/attempts.py +0 -0
  35. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/matching.py +0 -0
  36. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/paths.py +0 -0
  37. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/core/results.py +0 -0
  38. {atsfill-0.0.4.dev44 → atsfill-0.0.4.dev47}/src/atsfill/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atsfill
3
- Version: 0.0.4.dev44
3
+ Version: 0.0.4.dev47
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
@@ -54,7 +54,7 @@ It is built for agents with a shell: every command prints one JSON document and
54
54
  ## Supported hiring systems
55
55
 
56
56
  <!-- badges -->
57
- ![oracle: dry run verified 2026-10-20](https://img.shields.io/badge/oracle-dry%20run%20verified%202026--10--20-7aa2f7) ![smartrecruiters: dry run verified 2026-10-20](https://img.shields.io/badge/smartrecruiters-dry%20run%20verified%202026--10--20-7aa2f7) ![greenhouse: dry run verified 2026-10-19](https://img.shields.io/badge/greenhouse-dry%20run%20verified%202026--10--19-7aa2f7) ![manatal: dry run verified 2026-10-20](https://img.shields.io/badge/manatal-dry%20run%20verified%202026--10--20-7aa2f7) ![paylocity: dry run verified 2026-10-20](https://img.shields.io/badge/paylocity-dry%20run%20verified%202026--10--20-7aa2f7) ![dayforce: dry run verified 2026-10-20](https://img.shields.io/badge/dayforce-dry%20run%20verified%202026--10--20-7aa2f7) ![workable: dry run verified 2026-10-20](https://img.shields.io/badge/workable-dry%20run%20verified%202026--10--20-7aa2f7) ![ashby: send verified 2026-10-19](https://img.shields.io/badge/ashby-send%20verified%202026--10--19-9ece6a) ![bamboohr: dry run verified 2026-10-21](https://img.shields.io/badge/bamboohr-dry%20run%20verified%202026--10--21-7aa2f7) ![teamtailor: send verified 2026-10-20](https://img.shields.io/badge/teamtailor-send%20verified%202026--10--20-9ece6a) ![jazzhr: dry run verified 2026-10-20](https://img.shields.io/badge/jazzhr-dry%20run%20verified%202026--10--20-7aa2f7) ![lever: dry run verified 2026-10-20](https://img.shields.io/badge/lever-dry%20run%20verified%202026--10--20-7aa2f7) ![hireology: dry run verified 2026-10-20](https://img.shields.io/badge/hireology-dry%20run%20verified%202026--10--20-7aa2f7) ![paycor: dry run verified 2026-10-20](https://img.shields.io/badge/paycor-dry%20run%20verified%202026--10--20-7aa2f7) ![breezy: dry run verified 2026-10-21](https://img.shields.io/badge/breezy-dry%20run%20verified%202026--10--21-7aa2f7) ![recruitee: dry run verified 2026-10-21](https://img.shields.io/badge/recruitee-dry%20run%20verified%202026--10--21-7aa2f7) ![wttj: send verified 2026-10-20](https://img.shields.io/badge/wttj-send%20verified%202026--10--20-9ece6a)
57
+ ![oracle: dry run verified 2026-10-20](https://img.shields.io/badge/oracle-dry%20run%20verified%202026--10--20-7aa2f7) ![smartrecruiters: dry run verified 2026-10-20](https://img.shields.io/badge/smartrecruiters-dry%20run%20verified%202026--10--20-7aa2f7) ![greenhouse: dry run verified 2026-10-19](https://img.shields.io/badge/greenhouse-dry%20run%20verified%202026--10--19-7aa2f7) ![manatal: dry run verified 2026-10-20](https://img.shields.io/badge/manatal-dry%20run%20verified%202026--10--20-7aa2f7) ![paylocity: dry run verified 2026-10-20](https://img.shields.io/badge/paylocity-dry%20run%20verified%202026--10--20-7aa2f7) ![dayforce: dry run verified 2026-10-20](https://img.shields.io/badge/dayforce-dry%20run%20verified%202026--10--20-7aa2f7) ![workable: dry run verified 2026-10-20](https://img.shields.io/badge/workable-dry%20run%20verified%202026--10--20-7aa2f7) ![ashby: send verified 2026-10-19](https://img.shields.io/badge/ashby-send%20verified%202026--10--19-9ece6a) ![bamboohr: dry run verified 2026-10-21](https://img.shields.io/badge/bamboohr-dry%20run%20verified%202026--10--21-7aa2f7) ![teamtailor: send verified 2026-10-20](https://img.shields.io/badge/teamtailor-send%20verified%202026--10--20-9ece6a) ![jazzhr: dry run verified 2026-10-20](https://img.shields.io/badge/jazzhr-dry%20run%20verified%202026--10--20-7aa2f7) ![lever: dry run verified 2026-10-20](https://img.shields.io/badge/lever-dry%20run%20verified%202026--10--20-7aa2f7) ![hireology: dry run verified 2026-10-20](https://img.shields.io/badge/hireology-dry%20run%20verified%202026--10--20-7aa2f7) ![paycor: dry run verified 2026-10-20](https://img.shields.io/badge/paycor-dry%20run%20verified%202026--10--20-7aa2f7) ![phenom: dry run verified 2026-10-21](https://img.shields.io/badge/phenom-dry%20run%20verified%202026--10--21-7aa2f7) ![breezy: dry run verified 2026-10-21](https://img.shields.io/badge/breezy-dry%20run%20verified%202026--10--21-7aa2f7) ![recruitee: dry run verified 2026-10-21](https://img.shields.io/badge/recruitee-dry%20run%20verified%202026--10--21-7aa2f7) ![wttj: send verified 2026-10-20](https://img.shields.io/badge/wttj-send%20verified%202026--10--20-9ece6a)
58
58
  <!-- /badges -->
59
59
 
60
60
  | System | Account needed | `read` without a browser |
@@ -89,7 +89,7 @@ uvx atsfill install-browser
89
89
 
90
90
  This downloads the Camoufox browser build atsfill is pinned to: 1.3 GB, about 2.5 GB once unpacked.
91
91
 
92
- Every push to `main` that passes CI is also published as a dev release, listed on GitHub as the [`next` pre-release](https://github.com/shbernal/atsfill/releases/tag/next); `uvx --prerelease allow atsfill` runs the newest.
92
+ Every push to `main` that passes CI is also published as a dev release; `uvx --prerelease allow atsfill` runs the newest.
93
93
 
94
94
  ## Quickstart
95
95
 
@@ -29,7 +29,7 @@ It is built for agents with a shell: every command prints one JSON document and
29
29
  ## Supported hiring systems
30
30
 
31
31
  <!-- badges -->
32
- ![oracle: dry run verified 2026-10-20](https://img.shields.io/badge/oracle-dry%20run%20verified%202026--10--20-7aa2f7) ![smartrecruiters: dry run verified 2026-10-20](https://img.shields.io/badge/smartrecruiters-dry%20run%20verified%202026--10--20-7aa2f7) ![greenhouse: dry run verified 2026-10-19](https://img.shields.io/badge/greenhouse-dry%20run%20verified%202026--10--19-7aa2f7) ![manatal: dry run verified 2026-10-20](https://img.shields.io/badge/manatal-dry%20run%20verified%202026--10--20-7aa2f7) ![paylocity: dry run verified 2026-10-20](https://img.shields.io/badge/paylocity-dry%20run%20verified%202026--10--20-7aa2f7) ![dayforce: dry run verified 2026-10-20](https://img.shields.io/badge/dayforce-dry%20run%20verified%202026--10--20-7aa2f7) ![workable: dry run verified 2026-10-20](https://img.shields.io/badge/workable-dry%20run%20verified%202026--10--20-7aa2f7) ![ashby: send verified 2026-10-19](https://img.shields.io/badge/ashby-send%20verified%202026--10--19-9ece6a) ![bamboohr: dry run verified 2026-10-21](https://img.shields.io/badge/bamboohr-dry%20run%20verified%202026--10--21-7aa2f7) ![teamtailor: send verified 2026-10-20](https://img.shields.io/badge/teamtailor-send%20verified%202026--10--20-9ece6a) ![jazzhr: dry run verified 2026-10-20](https://img.shields.io/badge/jazzhr-dry%20run%20verified%202026--10--20-7aa2f7) ![lever: dry run verified 2026-10-20](https://img.shields.io/badge/lever-dry%20run%20verified%202026--10--20-7aa2f7) ![hireology: dry run verified 2026-10-20](https://img.shields.io/badge/hireology-dry%20run%20verified%202026--10--20-7aa2f7) ![paycor: dry run verified 2026-10-20](https://img.shields.io/badge/paycor-dry%20run%20verified%202026--10--20-7aa2f7) ![breezy: dry run verified 2026-10-21](https://img.shields.io/badge/breezy-dry%20run%20verified%202026--10--21-7aa2f7) ![recruitee: dry run verified 2026-10-21](https://img.shields.io/badge/recruitee-dry%20run%20verified%202026--10--21-7aa2f7) ![wttj: send verified 2026-10-20](https://img.shields.io/badge/wttj-send%20verified%202026--10--20-9ece6a)
32
+ ![oracle: dry run verified 2026-10-20](https://img.shields.io/badge/oracle-dry%20run%20verified%202026--10--20-7aa2f7) ![smartrecruiters: dry run verified 2026-10-20](https://img.shields.io/badge/smartrecruiters-dry%20run%20verified%202026--10--20-7aa2f7) ![greenhouse: dry run verified 2026-10-19](https://img.shields.io/badge/greenhouse-dry%20run%20verified%202026--10--19-7aa2f7) ![manatal: dry run verified 2026-10-20](https://img.shields.io/badge/manatal-dry%20run%20verified%202026--10--20-7aa2f7) ![paylocity: dry run verified 2026-10-20](https://img.shields.io/badge/paylocity-dry%20run%20verified%202026--10--20-7aa2f7) ![dayforce: dry run verified 2026-10-20](https://img.shields.io/badge/dayforce-dry%20run%20verified%202026--10--20-7aa2f7) ![workable: dry run verified 2026-10-20](https://img.shields.io/badge/workable-dry%20run%20verified%202026--10--20-7aa2f7) ![ashby: send verified 2026-10-19](https://img.shields.io/badge/ashby-send%20verified%202026--10--19-9ece6a) ![bamboohr: dry run verified 2026-10-21](https://img.shields.io/badge/bamboohr-dry%20run%20verified%202026--10--21-7aa2f7) ![teamtailor: send verified 2026-10-20](https://img.shields.io/badge/teamtailor-send%20verified%202026--10--20-9ece6a) ![jazzhr: dry run verified 2026-10-20](https://img.shields.io/badge/jazzhr-dry%20run%20verified%202026--10--20-7aa2f7) ![lever: dry run verified 2026-10-20](https://img.shields.io/badge/lever-dry%20run%20verified%202026--10--20-7aa2f7) ![hireology: dry run verified 2026-10-20](https://img.shields.io/badge/hireology-dry%20run%20verified%202026--10--20-7aa2f7) ![paycor: dry run verified 2026-10-20](https://img.shields.io/badge/paycor-dry%20run%20verified%202026--10--20-7aa2f7) ![phenom: dry run verified 2026-10-21](https://img.shields.io/badge/phenom-dry%20run%20verified%202026--10--21-7aa2f7) ![breezy: dry run verified 2026-10-21](https://img.shields.io/badge/breezy-dry%20run%20verified%202026--10--21-7aa2f7) ![recruitee: dry run verified 2026-10-21](https://img.shields.io/badge/recruitee-dry%20run%20verified%202026--10--21-7aa2f7) ![wttj: send verified 2026-10-20](https://img.shields.io/badge/wttj-send%20verified%202026--10--20-9ece6a)
33
33
  <!-- /badges -->
34
34
 
35
35
  | System | Account needed | `read` without a browser |
@@ -64,7 +64,7 @@ uvx atsfill install-browser
64
64
 
65
65
  This downloads the Camoufox browser build atsfill is pinned to: 1.3 GB, about 2.5 GB once unpacked.
66
66
 
67
- Every push to `main` that passes CI is also published as a dev release, listed on GitHub as the [`next` pre-release](https://github.com/shbernal/atsfill/releases/tag/next); `uvx --prerelease allow atsfill` runs the newest.
67
+ Every push to `main` that passes CI is also published as a dev release; `uvx --prerelease allow atsfill` runs the newest.
68
68
 
69
69
  ## Quickstart
70
70
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "atsfill"
3
- version = "0.0.4.dev44"
3
+ version = "0.0.4.dev47"
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"
@@ -70,8 +70,7 @@ select = [
70
70
 
71
71
  [tool.pytest.ini_options]
72
72
  testpaths = ["tests"]
73
- markers = ["live: drives a real hiring system page with data from .env and .tmp/; opt-in with -m live"]
74
- addopts = "-m 'not live' -n auto --dist loadscope"
73
+ addopts = "-n auto --dist loadscope"
75
74
 
76
75
  [[tool.uv.index]]
77
76
  name = "testpypi"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "atsfill"
3
- version = "0.0.4.dev44"
3
+ version = "0.0.4.dev47"
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"
@@ -53,10 +53,7 @@ select = ["E", "F", "I", "UP", "B", "SIM"]
53
53
 
54
54
  [tool.pytest.ini_options]
55
55
  testpaths = ["tests"]
56
- markers = [
57
- "live: drives a real hiring system page with data from .env and .tmp/; opt-in with -m live",
58
- ]
59
- addopts = "-m 'not live' -n auto --dist loadscope"
56
+ addopts = "-n auto --dist loadscope"
60
57
 
61
58
  [[tool.uv.index]]
62
59
  name = "testpypi"
@@ -10,6 +10,7 @@ from atsfill.adapters.manatal import Manatal
10
10
  from atsfill.adapters.oracle import Oracle
11
11
  from atsfill.adapters.paycor import Paycor
12
12
  from atsfill.adapters.paylocity import Paylocity
13
+ from atsfill.adapters.phenom import Phenom
13
14
  from atsfill.adapters.recruitee import Recruitee
14
15
  from atsfill.adapters.smartrecruiters import SmartRecruiters
15
16
  from atsfill.adapters.teamtailor import Teamtailor
@@ -35,4 +36,5 @@ ADAPTERS: list[Adapter] = [
35
36
  Recruitee(),
36
37
  Breezy(),
37
38
  BambooHR(),
39
+ Phenom(), # last: it claims a URL by its path alone
38
40
  ]
@@ -232,9 +232,6 @@ class Breezy:
232
232
  match = JOB.match(parts.path)
233
233
  return f"https://{parts.hostname}/p/{match[1]}" if match else url
234
234
 
235
- def read_api(self, url: str) -> list[Field] | None:
236
- return None # the form's configuration is only in the page
237
-
238
235
  def read_form(self, page: Page) -> list[Field]:
239
236
  if not urlsplit(page.url).path.rstrip("/").endswith("/apply"):
240
237
  page.goto(f"{self.posting(page.url)}/apply")
@@ -192,9 +192,6 @@ class Dayforce:
192
192
  found = _job(url)
193
193
  return f"https://{HOST}/{found[1]}/{found[2]}/jobs/{found[3]}" if found else url
194
194
 
195
- def read_api(self, url: str) -> list[Field] | None:
196
- return None # the template leaves out the options of the country and contact dropdowns
197
-
198
195
  def read_form(self, page: Page) -> list[Field]:
199
196
  found = _job(page.url)
200
197
  if found is None:
@@ -134,9 +134,6 @@ class JazzHR:
134
134
  job = _job(url)
135
135
  return f"https://{job[0]}/apply/{job[1]}" if job else url
136
136
 
137
- def read_api(self, url: str) -> list[Field] | None:
138
- return None
139
-
140
137
  def read_form(self, page: Page) -> list[Field]:
141
138
  form = page.locator(FORM)
142
139
  try:
@@ -132,9 +132,6 @@ class Lever:
132
132
  parts, job = urlsplit(url), _job(url)
133
133
  return f"https://{parts.hostname}/{job[0]}/{job[1]}" if job else url
134
134
 
135
- def read_api(self, url: str) -> list[Field] | None:
136
- return None # Lever's postings API leaves the application's questions out
137
-
138
135
  def read_form(self, page: Page) -> list[Field]:
139
136
  if not urlsplit(page.url).path.rstrip("/").endswith("/apply"):
140
137
  page.goto(f"{self.posting(page.url)}/apply")
@@ -259,9 +259,6 @@ class Oracle:
259
259
  assert match, url
260
260
  return f"https://{parts.hostname}/hcmUI/CandidateExperience/job/{match[1]}"
261
261
 
262
- def read_api(self, url: str) -> list[Field] | None:
263
- return None # the form's metadata is served only past the email step
264
-
265
262
  def read_form(self, page: Page) -> list[Field]:
266
263
  parts = urlsplit(page.url)
267
264
  match = JOB.search(parts.path)
@@ -160,9 +160,6 @@ class Paycor:
160
160
  job = (query.get("id") or query.get("gni") or [url])[0]
161
161
  return f"{CAREER}JobIntroduction.action?id={job}"
162
162
 
163
- def read_api(self, url: str) -> list[Field] | None:
164
- return None # the form is behind the pages before it, posted in a session
165
-
166
163
  def read_form(self, page: Page) -> list[Field]:
167
164
  self._before, self._codes = [], {}
168
165
  self._walk(page, None)