atsfill 0.0.4.dev95__tar.gz → 0.0.4.dev98__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 (47) hide show
  1. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/PKG-INFO +4 -2
  2. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/README.md +1 -1
  3. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/pyproject.toml +3 -1
  4. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/pyproject.toml.orig +3 -1
  5. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/browser.py +12 -16
  6. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/paths.py +3 -3
  7. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/LICENSE +0 -0
  8. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/__init__.py +0 -0
  9. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/__init__.py +0 -0
  10. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/ashby.py +0 -0
  11. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/bamboohr.py +0 -0
  12. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/breezy.py +0 -0
  13. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/dayforce.py +0 -0
  14. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/eightfold.py +0 -0
  15. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/greenhouse.py +0 -0
  16. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/hireology.py +0 -0
  17. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/hiringthing.py +0 -0
  18. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/jazzhr.py +0 -0
  19. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/lever.py +0 -0
  20. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/manatal.py +0 -0
  21. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/oracle.py +0 -0
  22. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/paycor.py +0 -0
  23. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/paylocity.py +0 -0
  24. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/personio.py +0 -0
  25. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/phenom.py +0 -0
  26. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/pinpoint.py +0 -0
  27. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/recruitee.py +0 -0
  28. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/rippling.py +0 -0
  29. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/smartrecruiters.py +0 -0
  30. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/teamtailor.py +0 -0
  31. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/workable.py +0 -0
  32. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/workday.py +0 -0
  33. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/wttj.py +0 -0
  34. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/adapters/zohorecruit.py +0 -0
  35. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/cli.py +0 -0
  36. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/__init__.py +0 -0
  37. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/accounts.py +0 -0
  38. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/adapter.py +0 -0
  39. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/attempts.py +0 -0
  40. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/commands.py +0 -0
  41. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/conditions.py +0 -0
  42. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/matching.py +0 -0
  43. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/passwords.py +0 -0
  44. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/registry.py +0 -0
  45. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/core/results.py +0 -0
  46. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/py.typed +0 -0
  47. {atsfill-0.0.4.dev95 → atsfill-0.0.4.dev98}/src/atsfill/registry.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atsfill
3
- Version: 0.0.4.dev95
3
+ Version: 0.0.4.dev98
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
@@ -10,12 +10,14 @@ Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Environment :: Console
11
11
  Classifier: Intended Audience :: End Users/Desktop
12
12
  Classifier: Operating System :: MacOS
13
+ Classifier: Operating System :: Microsoft :: Windows
13
14
  Classifier: Operating System :: POSIX :: Linux
14
15
  Classifier: Programming Language :: Python :: 3
15
16
  Classifier: Programming Language :: Python :: 3.14
16
17
  Classifier: Topic :: Office/Business
17
18
  Classifier: Typing :: Typed
18
19
  Requires-Dist: camoufox==0.5.8
20
+ Requires-Dist: filelock==4.1.1
19
21
  Requires-Dist: keyring==25.7.0
20
22
  Requires-Dist: packaging==26.3
21
23
  Requires-Python: >=3.14
@@ -82,7 +84,7 @@ atsfill moves the quirks into one adapter per system and makes the check code: a
82
84
 
83
85
  ## Install
84
86
 
85
- atsfill runs on Linux and macOS with Python 3.14, which `uvx` fetches if needed.
87
+ atsfill runs on Linux, macOS and Windows with Python 3.14, which `uvx` fetches if needed.
86
88
 
87
89
  ```sh
88
90
  uvx atsfill install-browser
@@ -56,7 +56,7 @@ atsfill moves the quirks into one adapter per system and makes the check code: a
56
56
 
57
57
  ## Install
58
58
 
59
- atsfill runs on Linux and macOS with Python 3.14, which `uvx` fetches if needed.
59
+ atsfill runs on Linux, macOS and Windows with Python 3.14, which `uvx` fetches if needed.
60
60
 
61
61
  ```sh
62
62
  uvx atsfill install-browser
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "atsfill"
3
- version = "0.0.4.dev95"
3
+ version = "0.0.4.dev98"
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"
@@ -20,6 +20,7 @@ classifiers = [
20
20
  "Environment :: Console",
21
21
  "Intended Audience :: End Users/Desktop",
22
22
  "Operating System :: MacOS",
23
+ "Operating System :: Microsoft :: Windows",
23
24
  "Operating System :: POSIX :: Linux",
24
25
  "Programming Language :: Python :: 3",
25
26
  "Programming Language :: Python :: 3.14",
@@ -28,6 +29,7 @@ classifiers = [
28
29
  ]
29
30
  dependencies = [
30
31
  "camoufox==0.5.8",
32
+ "filelock==4.1.1",
31
33
  "keyring==25.7.0",
32
34
  "packaging==26.3",
33
35
  ]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "atsfill"
3
- version = "0.0.4.dev95"
3
+ version = "0.0.4.dev98"
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"
@@ -13,6 +13,7 @@ classifiers = [
13
13
  "Environment :: Console",
14
14
  "Intended Audience :: End Users/Desktop",
15
15
  "Operating System :: MacOS",
16
+ "Operating System :: Microsoft :: Windows",
16
17
  "Operating System :: POSIX :: Linux",
17
18
  "Programming Language :: Python :: 3",
18
19
  "Programming Language :: Python :: 3.14",
@@ -21,6 +22,7 @@ classifiers = [
21
22
  ]
22
23
  dependencies = [
23
24
  "camoufox==0.5.8",
25
+ "filelock==4.1.1",
24
26
  "keyring==25.7.0",
25
27
  "packaging==26.3",
26
28
  ]
@@ -1,7 +1,6 @@
1
1
  """The browser launcher, the only module that imports camoufox and playwright (ADR 0002)."""
2
2
 
3
3
  import asyncio
4
- import fcntl
5
4
  import json
6
5
  import locale
7
6
  import platform
@@ -24,6 +23,8 @@ from camoufox.exceptions import CamoufoxNotInstalled
24
23
  from camoufox.fingerprints import Screen, generate_fingerprint
25
24
  from camoufox.pkgman import installed_verstr
26
25
  from camoufox.sync_api import Camoufox
26
+ from filelock import FileLock
27
+ from filelock import Timeout as LockTimeout
27
28
  from playwright.sync_api import APIRequestContext as Request
28
29
  from playwright.sync_api import Browser, Locator, Page, Response, sync_playwright
29
30
  from playwright.sync_api import Error as BrowserError
@@ -107,8 +108,7 @@ def _build_blocker() -> None:
107
108
  from disk: fetched by each launch, they would hold its first page for seconds, and each
108
109
  list on is compiled by each launch before the blocker starts."""
109
110
  ADDONS_DIR.mkdir(parents=True, exist_ok=True)
110
- with (ADDONS_DIR / f"{BLOCKER.name}.lock").open("w") as f:
111
- fcntl.flock(f, fcntl.LOCK_EX)
111
+ with FileLock(ADDONS_DIR / f"{BLOCKER.name}.lock"):
112
112
  build = BLOCKER.with_name(f"{BLOCKER.name}.build")
113
113
  shutil.rmtree(build, ignore_errors=True)
114
114
  shutil.copytree(get_addon_path(DefaultAddons.UBO.name), build)
@@ -171,19 +171,15 @@ def machine_locale() -> str | None:
171
171
  @contextmanager
172
172
  def lock(data_dir: Path, deadline: float) -> Generator[None]:
173
173
  """Holds the data directory; a second command waits here until its deadline."""
174
- with (data_dir / "lock").open("w") as f:
175
- while True:
176
- try:
177
- fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
178
- break
179
- except BlockingIOError:
180
- if time.monotonic() > deadline:
181
- raise OutOfTime("time budget ran out waiting for another command") from None
182
- time.sleep(LOCK_POLL_S)
183
- try:
184
- yield
185
- finally:
186
- fcntl.flock(f, fcntl.LOCK_UN)
174
+ held = FileLock(data_dir / "lock", poll_interval=LOCK_POLL_S)
175
+ try:
176
+ held.acquire(timeout=max(0.0, deadline - time.monotonic()))
177
+ except LockTimeout:
178
+ raise OutOfTime("time budget ran out waiting for another command") from None
179
+ try:
180
+ yield
181
+ finally:
182
+ held.release()
187
183
 
188
184
 
189
185
  @contextmanager
@@ -1,10 +1,11 @@
1
- import fcntl
2
1
  import os
3
2
  import platform
4
3
  import re
5
4
  import tomllib
6
5
  from pathlib import Path
7
6
 
7
+ from filelock import FileLock
8
+
8
9
  LINUX = platform.system() == "Linux"
9
10
  DEFAULT_USER = "default"
10
11
  TEST_USER = "test"
@@ -50,8 +51,7 @@ def _move_to_default(data: Path) -> None:
50
51
  user, once, under the lock."""
51
52
  if not any((data / name).exists() for name in MOVED):
52
53
  return
53
- with (data / "lock").open("w") as lock:
54
- fcntl.flock(lock, fcntl.LOCK_EX)
54
+ with FileLock(data / "lock"):
55
55
  default = data / "users" / DEFAULT_USER
56
56
  default.mkdir(mode=0o700, parents=True, exist_ok=True)
57
57
  for name in MOVED:
File without changes