atsfill 0.0.5.dev191__tar.gz → 0.0.5.dev192__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 (67) hide show
  1. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/PKG-INFO +1 -1
  2. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/pyproject.toml +1 -1
  3. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/pyproject.toml.orig +1 -1
  4. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/phenom.py +20 -10
  5. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/LICENSE +0 -0
  6. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/README.md +0 -0
  7. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/__init__.py +0 -0
  8. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/__init__.py +0 -0
  9. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/adp.py +0 -0
  10. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/adpmyjobs.py +0 -0
  11. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/ashby.py +0 -0
  12. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/bamboohr.py +0 -0
  13. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/breezy.py +0 -0
  14. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/dayforce.py +0 -0
  15. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/eightfold.py +0 -0
  16. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/greenhouse.py +0 -0
  17. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/gupy.py +0 -0
  18. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/hireology.py +0 -0
  19. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/hiringthing.py +0 -0
  20. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/hrmdirect.py +0 -0
  21. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/isolvedhire.py +0 -0
  22. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/jazzhr.py +0 -0
  23. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/jobaffinity.py +0 -0
  24. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/jobstreet.py +0 -0
  25. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/join.py +0 -0
  26. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/lever.py +0 -0
  27. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/manatal.py +0 -0
  28. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/oracle.py +0 -0
  29. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/paycor.py +0 -0
  30. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/paylocity.py +0 -0
  31. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/personio.py +0 -0
  32. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/pinpoint.py +0 -0
  33. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/recruitee.py +0 -0
  34. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/recruiterflow.py +0 -0
  35. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/rippling.py +0 -0
  36. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/smartrecruiters.py +0 -0
  37. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/successfactors.js +0 -0
  38. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/successfactors.py +0 -0
  39. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/taleo.py +0 -0
  40. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/teamtailor.py +0 -0
  41. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/ukg.py +0 -0
  42. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/welcomekit.py +0 -0
  43. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/workable.py +0 -0
  44. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/workatastartup.py +0 -0
  45. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/workday.py +0 -0
  46. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/wttj.py +0 -0
  47. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/adapters/zohorecruit.py +0 -0
  48. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/cli.py +0 -0
  49. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/__init__.py +0 -0
  50. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/accounts.py +0 -0
  51. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/adapter.py +0 -0
  52. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/attempts.py +0 -0
  53. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/browser.py +0 -0
  54. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/commands.py +0 -0
  55. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/conditions.py +0 -0
  56. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/countries.py +0 -0
  57. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/html.py +0 -0
  58. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/matching.py +0 -0
  59. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/otp.py +0 -0
  60. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/passwords.py +0 -0
  61. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/paths.py +0 -0
  62. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/registry.py +0 -0
  63. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/results.py +0 -0
  64. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/snapshot.py +0 -0
  65. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/core/telemetry.py +0 -0
  66. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/src/atsfill/py.typed +0 -0
  67. {atsfill-0.0.5.dev191 → atsfill-0.0.5.dev192}/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.dev191
3
+ Version: 0.0.5.dev192
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.5.dev191"
3
+ version = "0.0.5.dev192"
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.5.dev191"
3
+ version = "0.0.5.dev192"
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"
@@ -25,7 +25,7 @@ from typing import Any
25
25
  from urllib.parse import parse_qs, urlsplit
26
26
 
27
27
  from atsfill.core import browser, matching, paths
28
- from atsfill.core.adapter import Gap, NotTaken, Unsupported, known_gap
28
+ from atsfill.core.adapter import Blocked, Gap, NotTaken, Unsupported, known_gap
29
29
  from atsfill.core.browser import HTTP_TIMEOUT_S, BrowserError, Locator, Overlaid, Page, Timeout
30
30
  from atsfill.core.results import (
31
31
  AllOf,
@@ -238,22 +238,24 @@ _FETCH = """async url => {
238
238
  return response.json();
239
239
  }"""
240
240
 
241
- # Posts each body to `/applySubmit`, `most` at a time; null for one that fails.
241
+ # Posts each body to `/applySubmit`, `most` at a time; null for one that fails. With the
242
+ # answers, whether one was refused (403), after which none is posted.
242
243
  _POSTS = """async ([bodies, token, most]) => {
243
244
  const out = bodies.map(() => null);
244
- let next = 0;
245
+ let next = 0, refused = false;
245
246
  const post = async () => {
246
- for (let i = next++; i < bodies.length; i = next++) {
247
+ for (let i = next++; i < bodies.length && !refused; i = next++) {
247
248
  try {
248
249
  const response = await fetch('/applySubmit', {method: 'POST',
249
250
  body: JSON.stringify(bodies[i]),
250
251
  headers: {'Content-Type': 'application/json', 'x-csrf-token': token}});
251
252
  if (response.ok) out[i] = await response.json();
253
+ refused ||= response.status === 403;
252
254
  } catch {}
253
255
  }
254
256
  };
255
257
  await Promise.all(Array.from({length: most}, post));
256
- return out;
258
+ return [out, refused];
257
259
  }"""
258
260
 
259
261
 
@@ -350,14 +352,22 @@ class Phenom:
350
352
  except ValueError as e:
351
353
  raise RuntimeError(str(e)) from None
352
354
  token = get(ph, "sessionParams.csrfToken") or ""
355
+
356
+ refused = False
357
+
358
+ def posts(bodies: list[dict[str, Any]]) -> list[Any]:
359
+ nonlocal refused
360
+ out, now = page.evaluate(_POSTS, [bodies, token, LOADERS_AT_ONCE])
361
+ refused |= now
362
+ return out
363
+
353
364
  try:
354
- fields, raws = _read(
355
- ph,
356
- lambda url: page.evaluate(_FETCH, url),
357
- lambda bodies: page.evaluate(_POSTS, [bodies, token, LOADERS_AT_ONCE]),
358
- )
365
+ fields, raws = _read(ph, lambda url: page.evaluate(_FETCH, url), posts)
359
366
  except (BrowserError, ValueError, KeyError) as e:
360
367
  raise RuntimeError(f"no configuration for the wizard ({e})") from None
368
+ finally: # raised once the read ends, so the answers that came are kept
369
+ if refused:
370
+ raise Blocked("rate_limited: the careers site answers /applySubmit 403")
361
371
  self._raws = {raw["id"]: raw for raw in raws}
362
372
  return fields
363
373
 
File without changes
File without changes