Hand Over OS to Pathlib where possible

This commit is contained in:
David Sangrey committed 2026-06-06 14:24:44 -04:00
1 parent e6a9b6eea9
commit ef8ba7b11f
18 files changed
+112 -147

No files matched your search

+3 -2
View File
@@ -13,6 +13,7 @@ import json
import os
import queue
import sys
from pathlib import Path
from time import sleep, time
from typing import TYPE_CHECKING, Any
from common_utils import log_locale, SERVER_RETRY
@@ -226,14 +227,14 @@ def main() -> None: # noqa: C901, CCR001
# system, chances are its the current locale, and not utf-8. Otherwise if it was copied, its probably
# utf8. Either way, try the system FIRST because reading something like cp1251 in UTF-8 results in garbage
# but the reverse results in an exception.
json_file = os.path.abspath(args.j)
json_file = str(Path(args.j).resolve())
try:
with open(json_file) as file_handle:
data = json.load(file_handle)
except UnicodeDecodeError:
with open(json_file, encoding='utf-8') as file_handle:
data = json.load(file_handle)
config.set('querytime', int(os.path.getmtime(args.j)))
config.set('querytime', int(Path(args.j).stat().st_mtime))
else:
# Get state from latest Journal file
+2 -1
View File
@@ -184,7 +184,6 @@ class InterceptHandler(logging.Handler):
def emit(self, record: logging.LogRecord) -> None:
"""Intercept standard logging and send to Loguru with context."""
level: str | int
try:
level = loguru_logger.level(record.levelname).name
@@ -367,9 +366,11 @@ def get_plugin_logger(plugin_name: str, loglevel: int = _default_loglevel) -> Lo
class EDMCContextFilter(logging.Filter):
"""
Legacy compatibility shim.
EDMC now intercepts standard logging globally via Loguru,
making manual context filtering obsolete.
"""
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
warnings.warn(
+7 -6
View File
@@ -11,7 +11,7 @@ import locale
import webbrowser
import platform
import sys
from os import chdir, environ, path
from os import chdir, environ
import pathlib
import logging
from journal_lock import JournalLock
@@ -19,10 +19,11 @@ from journal_lock import JournalLock
if getattr(sys, "frozen", False):
# Under py2exe sys.path[0] is the executable name
if sys.platform == "win32":
chdir(path.dirname(sys.path[0]))
exe_dir = pathlib.Path(sys.path[0]).parent
chdir(exe_dir)
# Allow executable to be invoked from any cwd
environ["TCL_LIBRARY"] = path.join(path.dirname(sys.path[0]), "lib", "tcl")
environ["TK_LIBRARY"] = path.join(path.dirname(sys.path[0]), "lib", "tk")
environ["TCL_LIBRARY"] = str(exe_dir / "lib" / "tcl")
environ["TK_LIBRARY"] = str(exe_dir / "lib" / "tk")
else:
# We still want to *try* to have CWD be where the main script is, even if
@@ -115,12 +116,12 @@ def main(active_config: config.Config) -> None:
root.withdraw() # Hide the window initially to calculate the dimensions
try:
icon_image = tk.PhotoImage(
file=path.join(active_config.respath_path, "io.edcd.EDMarketConnector.png")
file=pathlib.Path(active_config.respath_path) / "io.edcd.EDMarketConnector.png"
)
root.iconphoto(True, icon_image)
except tk.TclError:
root.iconbitmap(path.join(active_config.respath_path, "EDMarketConnector.ico"))
root.iconbitmap(pathlib.Path(active_config.respath_path) / "EDMarketConnector.ico")
sys_report = get_sys_report(active_config)
+3 -3
View File
@@ -20,7 +20,7 @@ import subprocess
import sys
import threading
import webbrowser
from os import chdir, environ
from os import environ
from time import localtime, strftime, time
from typing import TYPE_CHECKING, Any, Literal, MutableMapping
from constants import applongname, appname, protocolhandler_redirect
@@ -39,7 +39,7 @@ if getattr(sys, 'frozen', False):
else:
# We still want to *try* to have CWD be where the main script is, even if
# not frozen.
chdir(pathlib.Path(__file__).parent)
os.chdir(pathlib.Path(__file__).parent)
# config will now cause an appname logger to be set up, so we need the
# console redirect before this
@@ -412,7 +412,7 @@ if __name__ == '__main__': # noqa: C901
sys.stdout.truncate()
else:
# Potential Git Repo?
if os.path.exists(".git"):
if pathlib.Path(".git").exists():
try:
git_branch = subprocess.check_output(
['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
+15 -19
View File
@@ -6,8 +6,8 @@ Licensed under the GNU General Public License v2 or later.
See LICENSE file.
"""
from collections.abc import Sequence
import datetime
import os
import shutil
import sys
import pathlib
@@ -73,9 +73,9 @@ def system_check(dist_dir: pathlib.Path) -> str:
def generate_data_files(
app_name: str, gitversion_file: str, plugins: list[str]
) -> list[tuple[object, object]]:
) -> Sequence[tuple[object, object]]:
"""Create the required datafiles to build."""
l10n_dir = "L10n"
l10n_dir = pathlib.Path("L10n")
fdevids_dir = pathlib.Path("FDevIDs")
license_dir = pathlib.Path("docs/Licenses")
data_files = [
@@ -97,26 +97,22 @@ def generate_data_files(
],
),
(
l10n_dir,
[
pathlib.Path(l10n_dir) / x
for x in os.listdir(l10n_dir)
if x.endswith(".strings")
],
str(l10n_dir),
[str(x) for x in l10n_dir.iterdir() if x.suffix == ".strings"],
),
(
fdevids_dir,
str(fdevids_dir),
[
pathlib.Path(fdevids_dir / "commodity.csv"),
pathlib.Path(fdevids_dir / "rare_commodity.csv"),
str(fdevids_dir / "commodity.csv"),
str(fdevids_dir / "rare_commodity.csv"),
],
),
("plugins", plugins),
]
# Add all files recursively from license directories
for root, dirs, files in os.walk(license_dir):
file_list = [os.path.join(root, f) for f in files]
dest_dir = os.path.join(license_dir, os.path.relpath(root, license_dir))
for root, dirs, files in license_dir.walk():
file_list = [str(root / f) for f in files]
dest_dir = str(license_dir / root.relative_to(license_dir))
data_files.append((dest_dir, file_list))
return data_files
@@ -131,9 +127,9 @@ def _scan_dist_for_modules( # noqa: C901, CCR001
def add(name: str, origin: str):
modules.setdefault(name, set()).add(origin)
for root, dirs, files in os.walk(dist_dir):
for root, dirs, files in dist_dir.walk():
for name in files:
path = pathlib.Path(root) / name
path = root / name # root is a Path object, name is a string
# Loose files
if path.suffix in (".py", ".pyc"):
@@ -153,12 +149,12 @@ def _scan_dist_for_modules( # noqa: C901, CCR001
add(top, str(rel))
# Zips
if path.suffix == ".zip":
elif path.suffix == ".zip":
try:
with zipfile.ZipFile(path) as z:
for info in z.infolist():
if info.filename.endswith((".py", ".pyc")):
parts = info.filename.split("/") # type: ignore
parts = tuple(info.filename.split("/"))
if not parts:
continue
+2 -6
View File
@@ -14,7 +14,6 @@ file, copy it over the local one.
import csv
import json
import os
import pathlib
import sys
from traceback import print_exc
@@ -33,11 +32,8 @@ def __make_backup(file_name: pathlib.Path, suffix: str = '.bak') -> None:
:param suffix: The suffix to use for backup files (default '.bak')
"""
backup_name = file_name.parent / (file_name.name + suffix)
if pathlib.Path.is_file(backup_name):
os.unlink(backup_name)
os.rename(file_name, backup_name)
backup_name.unlink(missing_ok=True)
file_name.rename(backup_name)
def addcommodities(data) -> None: # noqa: CCR001
+1 -1
View File
@@ -91,7 +91,7 @@ def git_shorthash_from_head() -> str | None:
:return: str | None: None if we couldn't determine the short hash.
"""
if IS_FROZEN or not os.path.exists(".git"):
if IS_FROZEN or not pathlib.Path(".git").exists():
return None
try:
+1
View File
@@ -163,6 +163,7 @@ class Dashboard(FileSystemEventHandler):
def poll(self, first_time: bool = False) -> None:
"""
Legacy compatibility shim for backwards compatibility with plugins.
Status.json is now handled entirely via filesystem event observers.
"""
warnings.warn(
+5 -2
View File
@@ -2,7 +2,6 @@
from __future__ import annotations
import json
import os
import pathlib
import re
import time
@@ -199,7 +198,11 @@ def export(data, filename=None) -> None: # noqa: C901, CCR001
# Look for last ship of this type
ship = util_ships.ship_file_name(data['ship'].get('shipName'), data['ship']['name'])
regexp = re.compile(re.escape(ship) + r'\.\d{4}-\d\d-\d\dT\d\d\.\d\d\.\d\d\.txt')
oldfiles = sorted([x for x in os.listdir(config.get_str('outdir')) if regexp.match(x)])
out_dir = pathlib.Path(config.get_str('outdir'))
oldfiles = sorted(
[x for x in out_dir.iterdir() if regexp.match(x.name)],
key=lambda p: p.name # Sort based on the filename string
)
if oldfiles:
with (pathlib.Path(config.get_str('outdir')) / oldfiles[-1]).open() as h:
if h.read() == string:
+3 -4
View File
@@ -7,7 +7,6 @@ See LICENSE file.
"""
from __future__ import annotations
import os
import pathlib
import sys
import tkinter as tk
@@ -125,10 +124,10 @@ class JournalLock:
self.locked = False
# Physically remove the lockfile from disk on a clean exit
if self.journal_dir_lockfile_name and self.journal_dir_lockfile_name.exists():
if self.journal_dir_lockfile_name:
try:
os.remove(self.journal_dir_lockfile_name)
except Exception:
self.journal_dir_lockfile_name.unlink(missing_ok=True)
except OSError:
pass # Prevent crashing if a file hook holds it open briefly during shutdown
return True
+7 -6
View File
@@ -15,7 +15,6 @@ import numbers
import re
import sys
from contextlib import suppress
from os import listdir, sep
from typing import TextIO, cast
from collections.abc import Iterable
import pathlib
@@ -106,7 +105,7 @@ class Translations:
return
self.translations = {None: self.contents(cast(str, lang))}
for plugin in listdir(config.plugin_dir_path):
for plugin in (x.name for x in pathlib.Path(config.plugin_dir_path).iterdir()):
plugin_path = config.plugin_dir_path / plugin / LOCALISATION_DIR
if pathlib.Path.is_dir(plugin_path):
try:
@@ -162,9 +161,11 @@ class Translations:
plugin_path: pathlib.Path | None = None
if context:
# TODO: There is probably a better way to go about this now.
plugin_name = context[len(config.plugin_dir)+1:].split(sep)[0]
plugin_path = config.plugin_dir_path / plugin_name / LOCALISATION_DIR
context_path = pathlib.Path(context)
# .is_relative_to() prevents crashes if context isn't actually in the plugin dir
if context_path.is_relative_to(config.plugin_dir_path):
plugin_name = context_path.relative_to(config.plugin_dir_path).parts[0]
plugin_path = config.plugin_dir_path / plugin_name / LOCALISATION_DIR
if lang:
contents: dict[str, str] = self.contents(lang=lang, plugin_path=plugin_path)
@@ -192,7 +193,7 @@ class Translations:
"""Return a list of available language codes."""
path = self.respath()
available = {x[:-len('.strings')] for x in listdir(path) if x.endswith('.strings')}
available = {x.stem for x in pathlib.Path(path).iterdir() if x.suffix == '.strings'}
return available
+1 -2
View File
@@ -10,7 +10,6 @@ from __future__ import annotations
import json
import re
import time
from os import listdir
from pathlib import Path
import companion
import util_ships
@@ -43,7 +42,7 @@ def export(data: companion.CAPIData, requested_filename: str | None = None) -> N
# Look for last ship of this type
ship = util_ships.ship_file_name(data['ship'].get('shipName'), data['ship']['name'])
regexp = re.compile(re.escape(ship) + r'\.\d\d\d\d-\d\d-\d\dT\d\d\.\d\d\.\d\d\.txt')
oldfiles = sorted([x for x in listdir(config.get_str('outdir')) if regexp.match(x)])
oldfiles = sorted([x.name for x in Path(config.get_str('outdir')).iterdir() if regexp.match(x.name)])
if oldfiles:
with open(Path(config.get_str('outdir')) / Path(oldfiles[-1])) as h:
if h.read() == string:
+28 -25
View File
@@ -15,8 +15,7 @@ import sys
import threading
from datetime import datetime
from collections import defaultdict
from os import SEEK_END, SEEK_SET, listdir
from os.path import basename, expanduser, getctime, isdir, join
from os import SEEK_END, SEEK_SET
from time import gmtime, localtime, mktime, sleep, strftime, strptime, time
from typing import TYPE_CHECKING, Any, BinaryIO
from collections.abc import MutableMapping
@@ -203,13 +202,15 @@ class EDLogs(FileSystemEventHandler):
if journal_dir == '' or journal_dir is None:
journal_dir = config.default_journal_dir
logdir = expanduser(journal_dir)
logdir_path = pathlib.Path(journal_dir).expanduser()
if not logdir or not isdir(logdir):
logger.error(f'Journal Directory is invalid: "{logdir}"')
if not logdir_path or not logdir_path.is_dir():
logger.error(f'Journal Directory is invalid: "{logdir_path}"')
self.stop()
return False
logdir = str(logdir_path.resolve())
if self.currentdir and self.currentdir != logdir:
logger.debug(f'Journal Directory changed? Was "{self.currentdir}", now "{logdir}"')
self.stop()
@@ -273,14 +274,16 @@ class EDLogs(FileSystemEventHandler):
if journals_dir is None:
return None
journal_files = (x for x in listdir(journals_dir) if self._RE_LOGFILE.search(x))
if journal_files:
# Odyssey Update 11 has, e.g. Journal.2022-03-15T152503.01.log
# Horizons Update 11 equivalent: Journal.220315152335.01.log
# So we can no longer use a naive sort.
journals_dir_path = pathlib.Path(journals_dir)
journal_files = (journals_dir_path / pathlib.Path(x) for x in journal_files)
return str(max(journal_files, key=getctime))
journals_path = pathlib.Path(journals_dir)
try:
journal_files = [x for x in journals_path.iterdir() if self._RE_LOGFILE.search(x.name)]
if journal_files:
# Odyssey Update 11 has, e.g. Journal.2022-03-15T152503.01.log
# Horizons Update 11 equivalent: Journal.220315152335.01.log
# So we can no longer use a naive sort.
return str(max(journal_files, key=lambda x: x.stat().st_ctime))
except Exception:
logger.exception('Failed to find latest logfile')
return None
@@ -350,8 +353,8 @@ class EDLogs(FileSystemEventHandler):
def on_created(self, event: FileSystemEvent) -> None:
"""Watchdog callback when, e.g. client (re)started."""
if not event.is_directory and self._RE_LOGFILE.search(str(basename(event.src_path))):
src_path = event.src_path.decode() if isinstance(event.src_path, bytes) else event.src_path
if not event.is_directory and self._RE_LOGFILE.search(pathlib.Path(src_path).name):
self.logfile = event.src_path # type: ignore
def worker(self) -> None: # noqa: C901, CCR001
@@ -1111,8 +1114,8 @@ class EDLogs(FileSystemEventHandler):
elif event_type == 'cargo' and entry.get('Vessel') == 'Ship':
self.state['Cargo'] = defaultdict(int)
# From 3.3 full Cargo event (after the first one) is written to a separate file
if 'Inventory' not in entry:
with open(join(self.currentdir, 'Cargo.json'), 'rb') as h: # type: ignore
if 'Inventory' not in entry and self.currentdir:
with pathlib.Path(self.currentdir, 'Cargo.json').open('rb') as h:
entry = json.load(h)
self.state['CargoJSON'] = entry
@@ -1583,8 +1586,8 @@ class EDLogs(FileSystemEventHandler):
if fcmaterials := self.__fcmaterials_retry():
entry = fcmaterials
elif event_type == 'moduleinfo':
with open(join(self.currentdir, 'ModulesInfo.json'), 'rb') as mf: # type: ignore
elif event_type == 'moduleinfo' and self.currentdir:
with pathlib.Path(self.currentdir, 'ModulesInfo.json').open('rb') as mf:
try:
entry = json.load(mf)
@@ -2308,17 +2311,17 @@ class EDLogs(FileSystemEventHandler):
ship = util_ships.ship_file_name(self.state['ShipName'], self.state['ShipType'])
regexp = re.compile(re.escape(ship) + r'\.\d{4}-\d\d-\d\dT\d\d\.\d\d\.\d\d\.txt')
oldfiles = sorted(x for x in listdir(config.get_str('outdir')) if regexp.match(x))
oldfiles = sorted(x.name for x in pathlib.Path(config.get_str('outdir')).iterdir() if regexp.match(x.name))
if oldfiles:
try:
with open(join(config.get_str('outdir'), oldfiles[-1]), encoding='utf-8') as h:
with (pathlib.Path(config.get_str('outdir')) / oldfiles[-1]).open(encoding='utf-8') as h:
if h.read() == string:
return # same as last time - don't write
except UnicodeError:
logger.exception("UnicodeError reading old ship loadout with utf-8 encoding, trying without...")
try:
with open(join(config.get_str('outdir'), oldfiles[-1])) as h:
with (pathlib.Path(config.get_str('outdir')) / oldfiles[-1]).open(encoding='utf-8') as h:
if h.read() == string:
return # same as last time - don't write
@@ -2337,7 +2340,7 @@ class EDLogs(FileSystemEventHandler):
# Write
ts = strftime('%Y-%m-%dT%H.%M.%S', localtime(time()))
filename = join(config.get_str('outdir'), f'{ship}.{ts}.txt')
filename = str(pathlib.Path(config.get_str('outdir')) / f'{ship}.{ts}.txt')
try:
with open(filename, 'w', encoding='utf-8') as h:
@@ -2424,7 +2427,7 @@ class EDLogs(FileSystemEventHandler):
try:
with open(join(self.currentdir, 'NavRoute.json')) as f:
with (pathlib.Path(self.currentdir) / 'NavRoute.json').open() as f:
raw = f.read()
except Exception as e:
@@ -2450,7 +2453,7 @@ class EDLogs(FileSystemEventHandler):
try:
with open(join(self.currentdir, 'FCMaterials.json')) as f:
with (pathlib.Path(self.currentdir) / 'FCMaterials.json').open() as f:
raw = f.read()
except Exception as e:
+3 -2
View File
@@ -11,7 +11,6 @@ import copy
import importlib.util
import logging
import operator
import os
import sys
from dataclasses import dataclass, field
import tkinter as tk
@@ -204,7 +203,9 @@ def load_plugins(master: tk.Tk) -> None:
def _load_internal_plugins():
internal = []
for name in sorted(os.listdir(config.internal_plugin_dir_path)):
plugin_dir = Path(config.internal_plugin_dir_path)
for plugin_path in sorted(plugin_dir.iterdir(), key=lambda p: p.name):
name = plugin_path.name
if name.endswith('.py') and name[0] not in ('.', '_'):
try:
plugin_name = name[:-3]
+9 -12
View File
@@ -7,11 +7,11 @@ See LICENSE file.
"""
from __future__ import annotations
import os
import json
import sys
import webbrowser
import tkinter as tk
import pathlib
from tkinter import ttk
import tkinter.font as tkfont
from PIL import Image, ImageTk
@@ -545,10 +545,8 @@ class PluginBrowserMixIn:
def _update_plugin_icon(self, plugin_id: str, plugin: dict) -> None:
icon_url = plugin.get("pluginIcon")
icon_key = plugin_id if icon_url else "__fallback__"
url = icon_url or os.path.join(
os.path.dirname(sys.argv[0]),
"io.edcd.EDMarketConnector.png",
)
script_dir = pathlib.Path(sys.argv[0]).parent
url = icon_url or str(script_dir / "io.edcd.EDMarketConnector.png")
self.__load_plugin_icon(icon_key, url)
def __clear_plugin_details(self) -> None:
@@ -583,13 +581,12 @@ class PluginBrowserMixIn:
try:
# Open PIL image
pil_image = (
Image.open(url).convert("RGBA")
if os.path.isfile(url)
else Image.open(BytesIO(requests.get(url, timeout=5).content)).convert(
"RGBA"
)
)
url_path = pathlib.Path(url)
if url_path.is_file():
pil_image = Image.open(url_path).convert("RGBA")
else:
response = requests.get(url, timeout=5)
pil_image = Image.open(BytesIO(response.content)).convert("RGBA")
# Resize while maintaining aspect ratio
pil_image.thumbnail((64, 64), Image.Resampling.LANCZOS)
+5 -11
View File
@@ -3,7 +3,6 @@ from __future__ import annotations
import logging
import time
from os.path import join, normpath
from pathlib import Path
import subprocess
import sys
@@ -171,7 +170,7 @@ if sys.platform == 'win32':
start_idx = len(config_home.split('\\')) if path.lower().startswith(config_home.lower()) else 0
# Split path into components
components = normpath(path).split('\\')
components = Path(path).parts
display_components = []
# Process each path component
@@ -1340,10 +1339,8 @@ class PreferencesDialog(tk.Toplevel, plugin_browser.PluginBrowserMixIn):
_val = 'SEMICOLON'
config.set('mkt_export_type', _val)
config.set(
'outdir',
join(config.home_path, self.outdir.get()[2:]) if self.outdir.get().startswith('~') else self.outdir.get()
)
out_path = Path(self.outdir.get())
config.set('outdir', str(out_path.expanduser()))
logdir = self.logdir.get()
if config.default_journal_dir_path and logdir.lower() == config.default_journal_dir.lower():
@@ -1386,11 +1383,8 @@ class PreferencesDialog(tk.Toplevel, plugin_browser.PluginBrowserMixIn):
config.set('dark_highlight', self.theme_colors[1])
theme.apply(self.parent)
if self.plugdir.get() != config.get_str('plugin_dir'):
config.set(
'plugin_dir',
join(config.home_path, self.plugdir.get()[2:]) if self.plugdir.get().startswith(
'~') else self.plugdir.get()
)
plug_path = Path(self.plugdir.get())
config.set('plugin_dir', str(plug_path.expanduser()))
self.req_restart = True
# Notify
+15 -45
View File
@@ -5,7 +5,6 @@
from __future__ import annotations
import multiprocessing as mp
import os
import pathlib
from collections.abc import Generator
import pytest
@@ -43,11 +42,7 @@ def other_process_lock(continue_q: mp.Queue, exit_q: mp.Queue, lockfile: pathlib
except Exception as e:
print(f"sub-process: Failed execution handle context: {e!r}")
finally:
try:
if lock_path.exists():
os.unlink(lock_path)
except Exception:
pass
lock_path.unlink(missing_ok=True)
def _obtain_lock_with_filelock(lockfile_path: pathlib.Path) -> bool:
@@ -58,9 +53,7 @@ def _obtain_lock_with_filelock(lockfile_path: pathlib.Path) -> bool:
lock.acquire(timeout=0)
lock.release()
return True
except Timeout:
return False
except Exception:
except (Timeout, Exception):
return False
@@ -115,11 +108,8 @@ class TestJournalLock:
# Tests against JournalLock.__init__()
def test_journal_lock_init(self, mock_journaldir: pathlib.Path):
"""Test JournalLock instantiation."""
tmpdir = str(mock_journaldir)
jlock = JournalLock()
# Check members are properly initialised.
assert jlock.journal_dir == tmpdir
assert jlock.journal_dir == str(mock_journaldir)
assert jlock.journal_dir_path is not None
assert jlock.journal_dir_lockfile_name is None
@@ -136,12 +126,8 @@ class TestJournalLock:
def test_path_from_journaldir_with_tmpdir(self, mock_journaldir: pathlib.Path):
"""Test JournalLock.set_path_from_journaldir() with tmpdir."""
tmpdir = mock_journaldir
jlock = JournalLock()
# Check that an actual journaldir is handled correctly.
jlock.journal_dir = str(tmpdir)
jlock.journal_dir = str(mock_journaldir)
jlock.set_path_from_journaldir()
assert isinstance(jlock.journal_dir_path, pathlib.Path)
@@ -154,7 +140,6 @@ class TestJournalLock:
# Check that 'None' is handled correctly.
jlock.journal_dir = None
jlock.set_path_from_journaldir()
assert jlock.journal_dir_path is None
locked = jlock.obtain_lock()
assert locked == JournalLockResult.JOURNALDIR_IS_NONE
@@ -169,8 +154,8 @@ class TestJournalLock:
# Cleanup, to avoid side-effect on other tests
assert jlock.release_lock()
if jlock.journal_dir_lockfile_name and jlock.journal_dir_lockfile_name.exists():
os.unlink(str(jlock.journal_dir_lockfile_name))
if jlock.journal_dir_lockfile_name:
jlock.journal_dir_lockfile_name.unlink(missing_ok=True)
def test_obtain_lock_already_locked(self, mock_journaldir: pathlib.Path):
"""Test JournalLock.obtain_lock() when already locked by another process."""
@@ -191,8 +176,7 @@ class TestJournalLock:
print("Attempt actual lock test...")
# Now attempt to lock with to-test code
jlock = JournalLock()
second_attempt = jlock.obtain_lock()
assert second_attempt == JournalLockResult.ALREADY_LOCKED
assert jlock.obtain_lock() == JournalLockResult.ALREADY_LOCKED
finally:
print("Telling sub-process to quit...")
exit_q.put("quit")
@@ -215,10 +199,7 @@ class TestJournalLock:
# Check it actually IS unlocked using the filelock backend engine
lock_file_path = mock_journaldir / "edmc-journal-lock.txt"
assert _obtain_lock_with_filelock(lock_file_path)
# Cleanup, to avoid side-effect on other tests
if jlock.journal_dir_lockfile_name and jlock.journal_dir_lockfile_name.exists():
os.unlink(str(jlock.journal_dir_lockfile_name))
jlock.journal_dir_lockfile_name.unlink(missing_ok=True)
def test_release_lock_not_locked(self, mock_journaldir: pathlib.Path):
"""Test JournalLock.release_lock() when not locked."""
@@ -259,21 +240,15 @@ class TestJournalLock:
jlock.obtain_lock()
assert jlock.locked
# Now store the 'current' journaldir for reference and attempt
# to update to a new one.
old_journaldir = jlock.journal_dir
old_journaldir_lockfile_name = jlock.journal_dir_lockfile_name
old_lockfile = jlock.journal_dir_lockfile_name
jlock.update_lock(None) # type: ignore
assert jlock.journal_dir != old_journaldir
assert jlock.locked
# Cleanup, to avoid side-effect on other tests
assert jlock.release_lock()
if jlock.journal_dir_lockfile_name and jlock.journal_dir_lockfile_name.exists():
os.unlink(str(jlock.journal_dir_lockfile_name))
# And the old_journaldir's lockfile too
if old_journaldir_lockfile_name and old_journaldir_lockfile_name.exists():
os.unlink(str(old_journaldir_lockfile_name))
jlock.journal_dir_lockfile_name.unlink(missing_ok=True)
if old_lockfile:
old_lockfile.unlink(missing_ok=True)
def test_update_lock_same(self, mock_journaldir: pathlib.Path):
"""
@@ -282,16 +257,11 @@ class TestJournalLock:
# First actually obtain the lock, and check it worked
jlock = JournalLock()
assert jlock.obtain_lock() == JournalLockResult.LOCKED
assert jlock.locked
# Now store the 'current' journaldir for reference and attempt
# to update to a new one.
old_journaldir = jlock.journal_dir
old_dir = jlock.journal_dir
jlock.update_lock(None) # type: ignore
assert jlock.journal_dir == old_journaldir
assert jlock.locked
assert jlock.journal_dir == old_dir
# Cleanup, to avoid side-effect on other tests
assert jlock.release_lock()
if jlock.journal_dir_lockfile_name and jlock.journal_dir_lockfile_name.exists():
os.unlink(str(jlock.journal_dir_lockfile_name))
jlock.journal_dir_lockfile_name.unlink(missing_ok=True)
+2
View File
@@ -1,5 +1,6 @@
"""
text.py - Dealing with Text and Bytes.
Copyright (c) EDCD, All Rights Reserved
Licensed under the GNU General Public License v2 or later.
See LICENSE file.
@@ -16,6 +17,7 @@ __all__ = ['gzip']
def gzip(data: str | bytes, max_size: int = 512, encoding='utf-8') -> tuple[bytes, bool]:
"""
Compress the given data if the max size is greater than specified.
The default was chosen somewhat arbitrarily, see eddn.py for some more careful
work towards keeping the data almost always compressed
:param data: The data to compress