Tipragot
628be439b8
Cela permet de ne pas avoir de problèmes de compatibilité car python est dans le git.
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any, Dict, Optional, Tuple
|
|
|
|
|
|
class TrieNode:
|
|
def __init__(self, config_file: str = "", config_data: Optional[Dict[str, Any]] = None) -> None:
|
|
if not config_data:
|
|
config_data = {}
|
|
|
|
self.nodes: Dict[str, TrieNode] = {}
|
|
self.config_info: Tuple[str, Dict[str, Any]] = (config_file, config_data)
|
|
|
|
|
|
class Trie:
|
|
"""
|
|
A prefix tree to store the paths of all config files and to search the nearest config
|
|
associated with each file
|
|
"""
|
|
|
|
def __init__(self, config_file: str = "", config_data: Optional[Dict[str, Any]] = None) -> None:
|
|
self.root: TrieNode = TrieNode(config_file, config_data)
|
|
|
|
def insert(self, config_file: str, config_data: Dict[str, Any]) -> None:
|
|
resolved_config_path_as_tuple = Path(config_file).parent.resolve().parts
|
|
|
|
temp = self.root
|
|
|
|
for path in resolved_config_path_as_tuple:
|
|
if path not in temp.nodes:
|
|
temp.nodes[path] = TrieNode()
|
|
|
|
temp = temp.nodes[path]
|
|
|
|
temp.config_info = (config_file, config_data)
|
|
|
|
def search(self, filename: str) -> Tuple[str, Dict[str, Any]]:
|
|
"""
|
|
Returns the closest config relative to filename by doing a depth
|
|
first search on the prefix tree.
|
|
"""
|
|
resolved_file_path_as_tuple = Path(filename).resolve().parts
|
|
|
|
temp = self.root
|
|
|
|
last_stored_config: Tuple[str, Dict[str, Any]] = ("", {})
|
|
|
|
for path in resolved_file_path_as_tuple:
|
|
if temp.config_info[0]:
|
|
last_stored_config = temp.config_info
|
|
|
|
if path not in temp.nodes:
|
|
break
|
|
|
|
temp = temp.nodes[path]
|
|
|
|
return last_stored_config
|
|
|
|
|
|
def exists_case_sensitive(path: str) -> bool:
|
|
"""Returns if the given path exists and also matches the case on Windows.
|
|
|
|
When finding files that can be imported, it is important for the cases to match because while
|
|
file os.path.exists("module.py") and os.path.exists("MODULE.py") both return True on Windows,
|
|
Python can only import using the case of the real file.
|
|
"""
|
|
result = os.path.exists(path)
|
|
if (sys.platform.startswith("win") or sys.platform == "darwin") and result: # pragma: no cover
|
|
directory, basename = os.path.split(path)
|
|
result = basename in os.listdir(directory)
|
|
return result
|