Skip to content

Commit 725cf86

Browse files
authored
Portability Improvements (#262)
* Support multiprocessing start methods other than fork() * Support Windows * Treat all paths within rst as POSIX-style paths * Add workaround for primitive os.kill() on Windows
1 parent 96b3d44 commit 725cf86

File tree

13 files changed

+72
-39
lines changed

13 files changed

+72
-39
lines changed

snooty/gizaparser/test_extracts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def create_page(filename: Optional[str]) -> Tuple[Page, EmbeddedRstParser]:
4444
return (page, EmbeddedRstParser(project_config, page, all_diagnostics[path]))
4545

4646
pages = category.to_pages(path, create_page, giza_node.data)
47-
assert [str(page.fake_full_path()) for page in pages] == [
47+
assert [page.fake_full_path().as_posix() for page in pages] == [
4848
"test_data/test_gizaparser/source/includes/extracts/installation-directory-rhel.rst",
4949
"test_data/test_gizaparser/source/includes/extracts/broken-inherit.rst",
5050
"test_data/test_gizaparser/source/includes/extracts/another-file.rst",

snooty/gizaparser/test_release.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def create_page(filename: Optional[str]) -> Tuple[Page, EmbeddedRstParser]:
4343
return (page, EmbeddedRstParser(project_config, page, all_diagnostics[path]))
4444

4545
pages = category.to_pages(path, create_page, giza_node.data)
46-
assert [str(page.fake_full_path()) for page in pages] == [
46+
assert [page.fake_full_path().as_posix() for page in pages] == [
4747
"test_data/test_gizaparser/source/includes/release/untar-release-osx-x86_64.rst",
4848
"test_data/test_gizaparser/source/includes/release/install-ent-windows-default.rst",
4949
]

snooty/gizaparser/test_steps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def create_page(filename: Optional[str]) -> Tuple[Page, EmbeddedRstParser]:
3636
return (page, EmbeddedRstParser(project_config, page, all_diagnostics[path]))
3737

3838
pages = category.to_pages(path, create_page, giza_node.data)
39-
assert [str(page.fake_full_path()) for page in pages] == [
39+
assert [page.fake_full_path().as_posix() for page in pages] == [
4040
"test_data/test_gizaparser/source/includes/steps/test.rst"
4141
]
4242
# Ensure that no diagnostics were raised

snooty/language_server.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,29 @@ class TextDocumentEdit:
151151
edits: List[TextEdit]
152152

153153

154-
def pid_exists(pid: int) -> bool:
155-
try:
156-
os.kill(pid, 0)
157-
except OSError:
154+
if sys.platform == "win32":
155+
import ctypes
156+
157+
kernel32 = ctypes.windll.kernel32
158+
PROCESS_QUERY_INFROMATION = 0x1000
159+
160+
def pid_exists(pid: int) -> bool:
161+
process = kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0, pid)
162+
if process != 0:
163+
kernel32.CloseHandle(process)
164+
return True
158165
return False
159-
else:
160-
return True
166+
167+
168+
else:
169+
170+
def pid_exists(pid: int) -> bool:
171+
try:
172+
os.kill(pid, 0)
173+
except ProcessLookupError:
174+
return False
175+
else:
176+
return True
161177

162178

163179
class Backend:

snooty/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import getpass
2020
import json
2121
import logging
22+
import multiprocessing
2223
import os
2324
import sys
2425
from collections import defaultdict
@@ -269,6 +270,8 @@ def _generate_build_identifiers(args: Dict[str, Optional[str]]) -> BuildIdentifi
269270

270271

271272
def main() -> None:
273+
multiprocessing.freeze_support()
274+
272275
# docopt will terminate here and display usage instructions if snooty is run improperly
273276
args = docopt(__doc__)
274277

snooty/n.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ class FileId(PurePosixPath):
5454

5555
PAT_FILE_EXTENSIONS = re.compile(r"\.((txt)|(rst)|(yaml))$")
5656

57+
def collapse_dots(self) -> "FileId":
58+
result: List[str] = []
59+
for part in self.parts:
60+
if part == "..":
61+
result.pop()
62+
elif part == ".":
63+
continue
64+
else:
65+
result.append(part)
66+
return FileId(*result)
67+
5768
@property
5869
def without_known_suffix(self) -> str:
5970
"""Returns the fileid without any of its known file extensions (txt, rst, yaml)"""

snooty/parser.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@
6666
)
6767
from .util import RST_EXTENSIONS
6868

69-
# XXX: Work around to get snooty working with Python 3.8 until we can fix
70-
# our implicit data flow issues.
71-
multiprocessing.set_start_method("fork")
72-
7369
NO_CHILDREN = (n.SubstitutionReference,)
7470
logger = logging.getLogger(__name__)
7571

@@ -581,7 +577,7 @@ def handle_directive(
581577
return doc
582578

583579
openapi_fileid, filepath = util.reroot_path(
584-
Path(argument_text), self.docpath, self.project_config.source_path
580+
FileId(argument_text), self.docpath, self.project_config.source_path
585581
)
586582

587583
try:
@@ -619,7 +615,7 @@ def create_page() -> Tuple[Page, EmbeddedRstParser]:
619615
return doc
620616

621617
_, filepath = util.reroot_path(
622-
Path(argument_text), self.docpath, self.project_config.source_path
618+
FileId(argument_text), self.docpath, self.project_config.source_path
623619
)
624620

625621
# Attempt to read the literally included file
@@ -747,7 +743,7 @@ def _locate_text(text: str) -> int:
747743
return doc
748744

749745
fileid, path = util.reroot_path(
750-
Path(argument_text), self.docpath, self.project_config.source_path
746+
FileId(argument_text), self.docpath, self.project_config.source_path
751747
)
752748

753749
# Validate if file exists
@@ -855,9 +851,8 @@ def validate_list_table(
855851
return
856852

857853
def add_static_asset(self, raw_path: str, upload: bool) -> StaticAsset:
858-
path = Path(raw_path)
859854
fileid, path = util.reroot_path(
860-
path, self.docpath, self.project_config.source_path
855+
FileId(raw_path), self.docpath, self.project_config.source_path
861856
)
862857
static_asset = StaticAsset.load(raw_path, fileid, path, upload)
863858
self.static_assets.add(static_asset)
@@ -1190,9 +1185,7 @@ def create_page(filename: str) -> Tuple[Page, EmbeddedRstParser]:
11901185
giza_node.path,
11911186
filename,
11921187
text,
1193-
n.Root(
1194-
(-1,), [], self.config.get_fileid(PurePath(filename)), {}
1195-
),
1188+
n.Root((-1,), [], self.config.get_fileid(FileId(filename)), {}),
11961189
)
11971190
return (
11981191
page,
@@ -1272,9 +1265,7 @@ def create_page(filename: str) -> Tuple[Page, EmbeddedRstParser]:
12721265
giza_node.path,
12731266
filename,
12741267
giza_node.text,
1275-
n.Root(
1276-
(-1,), [], self.config.get_fileid(PurePath(filename)), {}
1277-
),
1268+
n.Root((-1,), [], self.config.get_fileid(FileId(filename)), {}),
12781269
)
12791270
return (
12801271
page,

snooty/rstparser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,9 +1146,10 @@ class Parser(Generic[_V]):
11461146
def __init__(self, project_config: ProjectConfig, visitor_class: Type[_V]) -> None:
11471147
self.project_config = project_config
11481148
self.visitor_class = visitor_class
1149-
Registry.get(project_config.default_domain).activate()
11501149

11511150
def parse(self, path: Path, text: Optional[str]) -> Tuple[_V, str]:
1151+
Registry.get(self.project_config.default_domain).activate()
1152+
11521153
diagnostics: List[Diagnostic] = []
11531154
text, diagnostics = self.project_config.read(path, text)
11541155

snooty/test_language_server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def inc() -> None:
6262

6363

6464
def test_pid_exists() -> None:
65-
assert language_server.pid_exists(0)
65+
assert language_server.pid_exists(os.getpid())
6666
# Test that an invalid PID returns False
6767
assert not language_server.pid_exists(537920)
6868

@@ -263,7 +263,7 @@ def test_reporting_config_error() -> None:
263263
with language_server.LanguageServer(sys.stdin.buffer, sys.stdout.buffer) as server:
264264
server.m_initialize(None, CWD_URL + "/test_data/bad_project")
265265
doc = {
266-
"uri": f"file://{CWD_URL}/test_data/bad_project/snooty.toml",
266+
"uri": f"{CWD_URL}/test_data/bad_project/snooty.toml",
267267
"languageId": "",
268268
"version": 0,
269269
"text": "",

snooty/test_main.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import os
44
import subprocess
5+
import sys
56
from typing import Any, List
67

78
from . import main
@@ -77,5 +78,7 @@ def test_print(*values: Any, **kwargs: Any) -> None:
7778

7879

7980
def test_parser_failure() -> None:
80-
return_code = subprocess.call(["snooty", "build", "test_data/test_parser_failure"])
81+
return_code = subprocess.call(
82+
[sys.executable, "-m", "snooty", "build", "test_data/test_parser_failure"]
83+
)
8184
assert return_code == 1

0 commit comments

Comments
 (0)