atsfill 0.0.8.dev226__tar.gz → 0.0.8.dev228__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 (69) hide show
  1. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/PKG-INFO +1 -1
  2. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/pyproject.toml +1 -1
  3. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/pyproject.toml.orig +1 -1
  4. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/join.py +4 -2
  5. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/ukg.py +0 -1
  6. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/workatastartup.py +0 -1
  7. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/workday.py +0 -1
  8. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/browser.py +5 -2
  9. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/LICENSE +0 -0
  10. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/README.md +0 -0
  11. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/__init__.py +0 -0
  12. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/__init__.py +0 -0
  13. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/adp.py +0 -0
  14. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/adpmyjobs.py +0 -0
  15. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/ashby.py +0 -0
  16. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/bamboohr.py +0 -0
  17. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/breezy.py +0 -0
  18. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/dayforce.py +0 -0
  19. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/eightfold.py +0 -0
  20. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/greenhouse.py +0 -0
  21. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/gupy.py +0 -0
  22. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/hireology.py +0 -0
  23. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/hiringthing.py +0 -0
  24. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/hrmdirect.py +0 -0
  25. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/isolvedhire.py +0 -0
  26. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/jazzhr.py +0 -0
  27. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/jobaffinity.py +0 -0
  28. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/jobstreet.py +0 -0
  29. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/lever.py +0 -0
  30. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/manatal.py +0 -0
  31. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/oracle.py +0 -0
  32. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/paycor.py +0 -0
  33. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/paylocity.py +0 -0
  34. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/personio.py +0 -0
  35. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/phenom.py +0 -0
  36. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/pinpoint.py +0 -0
  37. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/recruitee.py +0 -0
  38. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/recruiterflow.py +0 -0
  39. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/rippling.py +0 -0
  40. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/smartrecruiters.py +0 -0
  41. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/successfactors.js +0 -0
  42. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/successfactors.py +0 -0
  43. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/taleo.py +0 -0
  44. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/teamtailor.py +0 -0
  45. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/welcomekit.py +0 -0
  46. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/wellfound.py +0 -0
  47. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/werecruit.py +0 -0
  48. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/workable.py +0 -0
  49. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/wttj.py +0 -0
  50. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/adapters/zohorecruit.py +0 -0
  51. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/cli.py +0 -0
  52. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/__init__.py +0 -0
  53. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/accounts.py +0 -0
  54. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/adapter.py +0 -0
  55. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/attempts.py +0 -0
  56. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/commands.py +0 -0
  57. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/conditions.py +0 -0
  58. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/countries.py +0 -0
  59. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/html.py +0 -0
  60. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/matching.py +0 -0
  61. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/otp.py +0 -0
  62. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/passwords.py +0 -0
  63. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/paths.py +0 -0
  64. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/registry.py +0 -0
  65. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/results.py +0 -0
  66. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/snapshot.py +0 -0
  67. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/core/telemetry.py +0 -0
  68. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/src/atsfill/py.typed +0 -0
  69. {atsfill-0.0.8.dev226 → atsfill-0.0.8.dev228}/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.dev226
3
+ Version: 0.0.8.dev228
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.8.dev226"
3
+ version = "0.0.8.dev228"
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"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "atsfill"
3
- version = "0.0.8.dev226"
3
+ version = "0.0.8.dev228"
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"
@@ -376,8 +376,9 @@ class Join:
376
376
  return {k: v for k, v in values.items() if v}
377
377
 
378
378
  def save(self, page: Page) -> None:
379
- """Save changes posts `UpdateTalentPersonalInformation`; the button stays disabled while
380
- a required field is empty or nothing changed."""
379
+ """Save changes posts `UpdateTalentPersonalInformation`, then the page returns to the
380
+ account page: a navigation started before that would be aborted by it. The button stays
381
+ disabled while a required field is empty or nothing changed."""
381
382
  button = page.locator("form button[type=submit]").last
382
383
  try: # it is enabled a moment after the last change
383
384
  page.wait_for_function(
@@ -397,6 +398,7 @@ class Join:
397
398
  raise RuntimeError(f"UpdateTalentPersonalInformation answered {response.status}")
398
399
  if errors := response.json().get("errors"):
399
400
  raise Refused(f"step_refused: {GENERAL}: {errors[0].get('message')}")
401
+ page.wait_for_url(lambda url: url != PROFILE, timeout=SAVE_TIMEOUT_MS)
400
402
 
401
403
  def _file(self, page: Page, field_id: str, answer: Answer | None) -> None:
402
404
  if not isinstance(answer, str):
@@ -33,7 +33,6 @@ UPLOAD_TIMEOUT_MS = 30_000
33
33
  SUBMIT_TIMEOUT_MS = 90_000
34
34
  SETTLE_MS = 500
35
35
  YES_NO = ["Yes", "No"]
36
- DATE_SHOWN = re.compile(r"(\d\d)/(\d\d)/(\d{4})")
37
36
  COUNTRY, STATE = "Country", "State"
38
37
  DECLINE_BOX = "input[type=checkbox][data-automation$='-decline-checkbox']"
39
38
  DAYS, DOCUMENTS = "availability_days", "documents"
@@ -437,7 +437,6 @@ def _in_entry(form: Locator, entry: str | None, node: str) -> Locator:
437
437
  ENGINEERING = Is("role", ["Engineering"])
438
438
  A_ROLE = Is("role") # shown once a role is picked
439
439
  YES_NO = ["Yes", "No"]
440
- SIZES = ["Not Interested", "OK", "Preferred"]
441
440
  T, C, M, TA = FieldType.TEXT, FieldType.CHOICE, FieldType.MULTI_CHOICE, FieldType.TYPEAHEAD
442
441
  STEPS: dict[str, list[Control]] = {
443
442
  "personal": [
@@ -112,7 +112,6 @@ ENTRY_LISTS: list[EntryList] = [
112
112
  ("lastYearAttended", "To (Actual or Expected)", "year", "To (Actual or Expected)"),
113
113
  ]),
114
114
  ] # fmt: skip
115
- SCHOOL_SEARCH = "university" # finds schools where the tenant lists them
116
115
  # The school: a search prompt where the tenant lists schools, else a text input; one field
117
116
  SCHOOL_IDS = {"education--schoolName": "education--school"}
118
117
  BRACKETED = re.compile(r"\(([^()]+)\)")
@@ -66,7 +66,7 @@ FILTERS = "assets/atsfill/filters.txt"
66
66
  INCLUDE = re.compile(r"^!#include (\S+)$", re.M)
67
67
  # A page holding a banner the lists hide: until they do, the blocker is still starting.
68
68
  PROBE = ("https://blocker.invalid/", '<div id="cookie-banner">probe</div>')
69
- BLOCKER_TIMEOUT_MS = 30_000 # its lists take seconds to compile on each launch, more under load
69
+ BLOCKER_TIMEOUT_MS = 120_000 # its lists compile on each launch: 4s alone, 47s at load 150
70
70
  OVERLAY_GRACE_MS = 1_000 # how long a cover may stay on a click target before it counts
71
71
  OVERLAY_POLL_MS = 100
72
72
 
@@ -226,7 +226,10 @@ def _wait_for_blocker(browser: Browser) -> None:
226
226
  try:
227
227
  page.locator("#cookie-banner").wait_for(state="hidden", timeout=BLOCKER_TIMEOUT_MS)
228
228
  except Timeout:
229
- raise BrowserError("the blocker hid no banner: run `atsfill install-browser`") from None
229
+ raise BrowserError(
230
+ f"the blocker hid no banner within {BLOCKER_TIMEOUT_MS // 1000}s: try again if the"
231
+ " machine is busy; if it is idle, run `atsfill install-browser`"
232
+ ) from None
230
233
  finally:
231
234
  context.close()
232
235
 
File without changes
File without changes