singleserver 0.1.0__tar.gz → 0.2.0__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 (29) hide show
  1. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/workspace.xml +51 -35
  2. {singleserver-0.1.0 → singleserver-0.2.0}/PKG-INFO +1 -1
  3. {singleserver-0.1.0 → singleserver-0.2.0}/pyproject.toml +1 -1
  4. {singleserver-0.1.0 → singleserver-0.2.0}/src/singleserver/__init__.py +1 -1
  5. {singleserver-0.1.0 → singleserver-0.2.0}/src/singleserver/server.py +14 -5
  6. {singleserver-0.1.0 → singleserver-0.2.0}/tests/test_server.py +58 -0
  7. {singleserver-0.1.0 → singleserver-0.2.0}/.claude/settings.local.json +0 -0
  8. {singleserver-0.1.0 → singleserver-0.2.0}/.github/workflows/ci.yml +0 -0
  9. {singleserver-0.1.0 → singleserver-0.2.0}/.gitignore +0 -0
  10. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/.gitignore +0 -0
  11. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/git_toolbox_prj.xml +0 -0
  12. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  13. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/misc.xml +0 -0
  14. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/modules.xml +0 -0
  15. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/singleserver.iml +0 -0
  16. {singleserver-0.1.0 → singleserver-0.2.0}/.idea/vcs.xml +0 -0
  17. {singleserver-0.1.0 → singleserver-0.2.0}/BOSTAD_INTEGRATION.md +0 -0
  18. {singleserver-0.1.0 → singleserver-0.2.0}/LICENSE +0 -0
  19. {singleserver-0.1.0 → singleserver-0.2.0}/README.md +0 -0
  20. {singleserver-0.1.0 → singleserver-0.2.0}/SINGLESERVER_LIBRARY_PLAN.md +0 -0
  21. {singleserver-0.1.0 → singleserver-0.2.0}/src/singleserver/client.py +0 -0
  22. {singleserver-0.1.0 → singleserver-0.2.0}/src/singleserver/lock.py +0 -0
  23. {singleserver-0.1.0 → singleserver-0.2.0}/src/singleserver/process.py +0 -0
  24. {singleserver-0.1.0 → singleserver-0.2.0}/tests/conftest.py +0 -0
  25. {singleserver-0.1.0 → singleserver-0.2.0}/tests/helpers.py +0 -0
  26. {singleserver-0.1.0 → singleserver-0.2.0}/tests/test_client.py +0 -0
  27. {singleserver-0.1.0 → singleserver-0.2.0}/tests/test_lock.py +0 -0
  28. {singleserver-0.1.0 → singleserver-0.2.0}/tests/test_process.py +0 -0
  29. {singleserver-0.1.0 → singleserver-0.2.0}/uv.lock +0 -0
@@ -4,14 +4,11 @@
4
4
  <option name="autoReloadType" value="SELECTIVE" />
5
5
  </component>
6
6
  <component name="ChangeListManager">
7
- <list default="true" id="d2f5ee2f-f4f5-4e60-a900-7af76aae6765" name="Changes" comment="feat: initial implementation of singleserver lib">
7
+ <list default="true" id="d2f5ee2f-f4f5-4e60-a900-7af76aae6765" name="Changes" comment="fix: add missing __init__.py">
8
8
  <change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
9
- <change beforePath="$PROJECT_DIR$/src/singleserver/client.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/singleserver/client.py" afterDir="false" />
10
- <change beforePath="$PROJECT_DIR$/src/singleserver/lock.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/singleserver/lock.py" afterDir="false" />
11
- <change beforePath="$PROJECT_DIR$/src/singleserver/process.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/singleserver/process.py" afterDir="false" />
9
+ <change beforePath="$PROJECT_DIR$/src/singleserver/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/singleserver/__init__.py" afterDir="false" />
12
10
  <change beforePath="$PROJECT_DIR$/src/singleserver/server.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/singleserver/server.py" afterDir="false" />
13
11
  <change beforePath="$PROJECT_DIR$/tests/test_server.py" beforeDir="false" afterPath="$PROJECT_DIR$/tests/test_server.py" afterDir="false" />
14
- <change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
15
12
  </list>
16
13
  <option name="SHOW_DIALOG" value="false" />
17
14
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -21,41 +18,41 @@
21
18
  <component name="Git.Settings">
22
19
  <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
23
20
  </component>
24
- <component name="GitHubPullRequestSearchHistory"><![CDATA[{
25
- "lastFilter": {
26
- "state": "OPEN",
27
- "assignee": "CaptainDuck"
21
+ <component name="GitHubPullRequestSearchHistory">{
22
+ &quot;lastFilter&quot;: {
23
+ &quot;state&quot;: &quot;OPEN&quot;,
24
+ &quot;assignee&quot;: &quot;CaptainDuck&quot;
28
25
  }
29
- }]]></component>
30
- <component name="GithubPullRequestsUISettings"><![CDATA[{
31
- "selectedUrlAndAccountId": {
32
- "url": "https://github.com/Technology-Company/singleserver",
33
- "accountId": "6034dab7-a252-4088-9244-0346eb837ae6"
26
+ }</component>
27
+ <component name="GithubPullRequestsUISettings">{
28
+ &quot;selectedUrlAndAccountId&quot;: {
29
+ &quot;url&quot;: &quot;https://github.com/Technology-Company/singleserver&quot;,
30
+ &quot;accountId&quot;: &quot;6034dab7-a252-4088-9244-0346eb837ae6&quot;
34
31
  }
35
- }]]></component>
36
- <component name="ProjectColorInfo"><![CDATA[{
37
- "associatedIndex": 2
38
- }]]></component>
32
+ }</component>
33
+ <component name="ProjectColorInfo">{
34
+ &quot;associatedIndex&quot;: 2
35
+ }</component>
39
36
  <component name="ProjectId" id="3999htGGq4BCphGNFp4WkmpfpRs" />
40
37
  <component name="ProjectViewState">
41
38
  <option name="hideEmptyMiddlePackages" value="true" />
42
39
  <option name="showLibraryContents" value="true" />
43
40
  </component>
44
- <component name="PropertiesComponent"><![CDATA[{
45
- "keyToString": {
46
- "RunOnceActivity.ShowReadmeOnStart": "true",
47
- "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
48
- "RunOnceActivity.git.unshallow": "true",
49
- "git-widget-placeholder": "main",
50
- "last_opened_file_path": "/Users/johanna/Documents/GitHub/singleserver",
51
- "node.js.detected.package.eslint": "true",
52
- "node.js.detected.package.tslint": "true",
53
- "node.js.selected.package.eslint": "(autodetect)",
54
- "node.js.selected.package.tslint": "(autodetect)",
55
- "nodejs_package_manager_path": "npm",
56
- "vue.rearranger.settings.migration": "true"
41
+ <component name="PropertiesComponent">{
42
+ &quot;keyToString&quot;: {
43
+ &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
44
+ &quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
45
+ &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
46
+ &quot;git-widget-placeholder&quot;: &quot;main&quot;,
47
+ &quot;last_opened_file_path&quot;: &quot;/Users/johanna/Documents/GitHub/singleserver&quot;,
48
+ &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
49
+ &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
50
+ &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
51
+ &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
52
+ &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
53
+ &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
57
54
  }
58
- }]]></component>
55
+ }</component>
59
56
  <component name="RecentsManager">
60
57
  <key name="CopyFile.RECENT_KEYS">
61
58
  <recent name="$PROJECT_DIR$" />
@@ -76,7 +73,8 @@
76
73
  <option name="number" value="Default" />
77
74
  <option name="presentableId" value="Default" />
78
75
  <updated>1770097541742</updated>
79
- <workItem from="1770097542784" duration="5523000" />
76
+ <workItem from="1770097542784" duration="7499000" />
77
+ <workItem from="1770121674396" duration="2602000" />
80
78
  </task>
81
79
  <task id="LOCAL-00001" summary="feat: initial implementation of singleserver lib">
82
80
  <option name="closed" value="true" />
@@ -86,7 +84,23 @@
86
84
  <option name="project" value="LOCAL" />
87
85
  <updated>1770101696339</updated>
88
86
  </task>
89
- <option name="localTasksCounter" value="2" />
87
+ <task id="LOCAL-00002" summary="fix: mypy type errors and add types-requests dependency">
88
+ <option name="closed" value="true" />
89
+ <created>1770103097453</created>
90
+ <option name="number" value="00002" />
91
+ <option name="presentableId" value="LOCAL-00002" />
92
+ <option name="project" value="LOCAL" />
93
+ <updated>1770103097453</updated>
94
+ </task>
95
+ <task id="LOCAL-00003" summary="fix: add missing __init__.py">
96
+ <option name="closed" value="true" />
97
+ <created>1770103235277</created>
98
+ <option name="number" value="00003" />
99
+ <option name="presentableId" value="LOCAL-00003" />
100
+ <option name="project" value="LOCAL" />
101
+ <updated>1770103235277</updated>
102
+ </task>
103
+ <option name="localTasksCounter" value="4" />
90
104
  <servers />
91
105
  </component>
92
106
  <component name="TypeScriptGeneratedFilesManager">
@@ -94,7 +108,9 @@
94
108
  </component>
95
109
  <component name="VcsManagerConfiguration">
96
110
  <MESSAGE value="feat: initial implementation of singleserver lib" />
97
- <option name="LAST_COMMIT_MESSAGE" value="feat: initial implementation of singleserver lib" />
111
+ <MESSAGE value="fix: mypy type errors and add types-requests dependency" />
112
+ <MESSAGE value="fix: add missing __init__.py" />
113
+ <option name="LAST_COMMIT_MESSAGE" value="fix: add missing __init__.py" />
98
114
  </component>
99
115
  <component name="XDebuggerManager">
100
116
  <breakpoint-manager>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: singleserver
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Manage singleton server processes across multiple workers using atomic socket binding
5
5
  Project-URL: Homepage, https://github.com/Technology-Company/singleserver
6
6
  Project-URL: Documentation, https://github.com/Technology-Company/singleserver#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "singleserver"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "Manage singleton server processes across multiple workers using atomic socket binding"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -24,7 +24,7 @@ from .lock import LockFile, SocketLock
24
24
  from .process import ProcessOwner, ProcessState
25
25
  from .server import ManagedServer, SingleServer
26
26
 
27
- __version__ = "0.1.0"
27
+ __version__ = "0.2.0"
28
28
 
29
29
  __all__ = [
30
30
  # Main classes
@@ -45,6 +45,7 @@ class SingleServer:
45
45
  name: str,
46
46
  command: list[str],
47
47
  port: int | None = None,
48
+ host: str = "127.0.0.1",
48
49
  socket: str | Path | None = None,
49
50
  lock_port: int | None = None,
50
51
  lock_socket: str | Path | None = None,
@@ -66,8 +67,9 @@ class SingleServer:
66
67
 
67
68
  Args:
68
69
  name: Identifier for logging/debugging.
69
- command: Command to run. Can include {port} placeholder.
70
+ command: Command to run. Can include {port}, {host}, {socket} placeholders.
70
71
  port: TCP port the server will listen on.
72
+ host: IP address to bind to (default: 127.0.0.1 for localhost only).
71
73
  socket: Unix socket path the server will listen on.
72
74
  lock_port: Separate port for the coordination lock (defaults to port - 1).
73
75
  lock_socket: Separate socket path for coordination lock.
@@ -90,6 +92,7 @@ class SingleServer:
90
92
  self.name = name
91
93
  self._command_template = command
92
94
  self.port = port
95
+ self.host = host
93
96
  self.socket_path = Path(socket) if socket else None
94
97
 
95
98
  # Determine lock address (separate from server address)
@@ -132,6 +135,8 @@ class SingleServer:
132
135
  for part in self._command_template:
133
136
  if "{port}" in part:
134
137
  part = part.replace("{port}", str(self.port))
138
+ if "{host}" in part:
139
+ part = part.replace("{host}", self.host)
135
140
  if "{socket}" in part:
136
141
  part = part.replace("{socket}", str(self.socket_path))
137
142
  result.append(part)
@@ -153,7 +158,7 @@ class SingleServer:
153
158
  def check() -> bool:
154
159
  try:
155
160
  client = ServerClient(
156
- host="127.0.0.1",
161
+ host=self.host,
157
162
  port=self.port,
158
163
  socket_path=self.socket_path,
159
164
  health_check_url=self.health_check_url,
@@ -271,7 +276,7 @@ class SingleServer:
271
276
 
272
277
  # Create client
273
278
  self._client = ServerClient(
274
- host="127.0.0.1",
279
+ host=self.host,
275
280
  port=self.port,
276
281
  socket_path=self.socket_path,
277
282
  health_check_url=self.health_check_url,
@@ -332,6 +337,7 @@ class ManagedServer:
332
337
  name: str,
333
338
  command: list[str],
334
339
  port: int | None = None,
340
+ host: str = "127.0.0.1",
335
341
  socket: str | Path | None = None,
336
342
  **kwargs: Any,
337
343
  ):
@@ -343,6 +349,7 @@ class ManagedServer:
343
349
  self.name = name
344
350
  self._command_template = command
345
351
  self.port = port
352
+ self.host = host
346
353
  self.socket_path = Path(socket) if socket else None
347
354
  self._kwargs = kwargs
348
355
  self._owner: ProcessOwner | None = None
@@ -355,6 +362,8 @@ class ManagedServer:
355
362
  for part in self._command_template:
356
363
  if "{port}" in part:
357
364
  part = part.replace("{port}", str(self.port))
365
+ if "{host}" in part:
366
+ part = part.replace("{host}", self.host)
358
367
  if "{socket}" in part:
359
368
  part = part.replace("{socket}", str(self.socket_path))
360
369
  result.append(part)
@@ -371,7 +380,7 @@ class ManagedServer:
371
380
  def check() -> bool:
372
381
  try:
373
382
  client = ServerClient(
374
- host="127.0.0.1",
383
+ host=self.host,
375
384
  port=self.port,
376
385
  socket_path=self.socket_path,
377
386
  health_check_url=health_check_url,
@@ -401,7 +410,7 @@ class ManagedServer:
401
410
  self._owner.start()
402
411
 
403
412
  self._client = ServerClient(
404
- host="127.0.0.1",
413
+ host=self.host,
405
414
  port=self.port,
406
415
  socket_path=self.socket_path,
407
416
  health_check_url=health_check_url,
@@ -75,6 +75,35 @@ class TestSingleServerBasic:
75
75
  )
76
76
  assert server.command == ["server", "-p", str(free_port)]
77
77
 
78
+ def test_default_host_is_localhost(self, free_port: int):
79
+ """Test that default host is 127.0.0.1."""
80
+ server = SingleServer(
81
+ name="test",
82
+ command=["echo", "hello"],
83
+ port=free_port,
84
+ )
85
+ assert server.host == "127.0.0.1"
86
+
87
+ def test_custom_host(self, free_port: int):
88
+ """Test that custom host can be set."""
89
+ server = SingleServer(
90
+ name="test",
91
+ command=["echo", "hello"],
92
+ port=free_port,
93
+ host="0.0.0.0",
94
+ )
95
+ assert server.host == "0.0.0.0"
96
+
97
+ def test_host_placeholder_replacement(self, free_port: int):
98
+ """Test that {host} placeholder is replaced."""
99
+ server = SingleServer(
100
+ name="test",
101
+ command=["server", "-h", "{host}", "-p", "{port}"],
102
+ port=free_port,
103
+ host="0.0.0.0",
104
+ )
105
+ assert server.command == ["server", "-h", "0.0.0.0", "-p", str(free_port)]
106
+
78
107
 
79
108
  class TestSingleServerConnect:
80
109
  """Tests for SingleServer.connect()."""
@@ -316,6 +345,35 @@ class TestManagedServer:
316
345
  )
317
346
  assert server.command == ["server", "--port", str(free_port)]
318
347
 
348
+ def test_default_host(self, free_port: int):
349
+ """Test that default host is 127.0.0.1."""
350
+ server = ManagedServer(
351
+ name="test",
352
+ command=["echo"],
353
+ port=free_port,
354
+ )
355
+ assert server.host == "127.0.0.1"
356
+
357
+ def test_custom_host(self, free_port: int):
358
+ """Test that custom host can be set."""
359
+ server = ManagedServer(
360
+ name="test",
361
+ command=["echo"],
362
+ port=free_port,
363
+ host="0.0.0.0",
364
+ )
365
+ assert server.host == "0.0.0.0"
366
+
367
+ def test_host_placeholder(self, free_port: int):
368
+ """Test that {host} placeholder is replaced."""
369
+ server = ManagedServer(
370
+ name="test",
371
+ command=["server", "-h", "{host}", "-p", "{port}"],
372
+ port=free_port,
373
+ host="192.168.1.1",
374
+ )
375
+ assert server.command == ["server", "-h", "192.168.1.1", "-p", str(free_port)]
376
+
319
377
 
320
378
  class TestSingleServerOutputRedirect:
321
379
  """Tests for output redirection."""
File without changes
File without changes
File without changes
File without changes
File without changes