multiple fixes and re-subclass path to str
This commit is contained in:
parent
1ea42aeca9
commit
b728df4bc0
|
@ -12,9 +12,9 @@ __version__ = '.'.join([str(v) for v in __version_tpl__])
|
|||
|
||||
from . import logging
|
||||
|
||||
izzylog = logging.get_logger('IzzyLib')
|
||||
izzylog = logging.logger['IzzyLib']
|
||||
|
||||
from .dotdict import DotDict, LowerDotDict, DefaultDotDict, JsonEncoder
|
||||
from .dotdict import DotDict, LowerDotDict, DefaultDotDict, MultiDotDict, JsonEncoder
|
||||
from .misc import *
|
||||
from .cache import LruCache, TtlCache
|
||||
from .connection import Connection
|
||||
|
|
|
@ -107,6 +107,64 @@ class LowerDotDict(DotDict):
|
|||
return super().update(data)
|
||||
|
||||
|
||||
class MultiDotDict(DotDict):
|
||||
def __getattr__(self, key):
|
||||
return self.__getitem__(key)
|
||||
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
try:
|
||||
self.__getitem__(key.lower(), False).append(value)
|
||||
|
||||
except KeyError as e:
|
||||
super().__setitem__(key.lower(), [value])
|
||||
|
||||
|
||||
def __getitem__(self, key, single=True):
|
||||
values = super().__getitem__(key.lower())
|
||||
|
||||
if single:
|
||||
try:
|
||||
return values[0]
|
||||
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
return values
|
||||
|
||||
|
||||
def update(self, data):
|
||||
for k,v in data.items():
|
||||
self[k] = v
|
||||
|
||||
|
||||
def get(self, key, default=None):
|
||||
try:
|
||||
return self.__getitem__(key)
|
||||
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
|
||||
def getall(self, key):
|
||||
try:
|
||||
return super().__getitem__(key)
|
||||
|
||||
except KeyError as e:
|
||||
if not default:
|
||||
raise e from None
|
||||
|
||||
return default
|
||||
|
||||
|
||||
def delone(self, key, value):
|
||||
self.__getitem__(key, False).remove(value)
|
||||
|
||||
|
||||
def delete(self, key):
|
||||
self.pop(key)
|
||||
|
||||
|
||||
class JsonEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if not any(map(isinstance, [obj], [str, int, float, dict])):
|
||||
|
|
|
@ -81,12 +81,12 @@ class HttpUrllibClient:
|
|||
filepath = Path(filepath)
|
||||
path = filepath.parent
|
||||
|
||||
if not path.exists() and not create_dirs:
|
||||
if not path.exists and not create_dirs:
|
||||
raise FileNotFoundError(f'Path does not exist: {path}')
|
||||
|
||||
path.mkdir()
|
||||
|
||||
if filepath.exists():
|
||||
if filepath.exists:
|
||||
kwargs['headers']['range'] = f'bytes={filepath.size}'
|
||||
|
||||
resp = self.request(url, *args, stream=True, **kwargs)
|
||||
|
@ -111,7 +111,7 @@ class HttpUrllibClient:
|
|||
filepath = Path(filepath)
|
||||
path = filepath.parent
|
||||
|
||||
if not path.exists() and not create_dirs:
|
||||
if not path.exists and not create_dirs:
|
||||
raise FileNotFoundError(f'Path does not exist: {path}')
|
||||
|
||||
path.mkdir()
|
||||
|
@ -122,7 +122,7 @@ class HttpUrllibClient:
|
|||
raise exceptions.HttpFileDownloadedError(f'Failed to download {url}: {resp.status}, body: {resp.body}')
|
||||
|
||||
if not filename:
|
||||
filename = Path(url).stem()
|
||||
filename = Path(url).stem
|
||||
|
||||
byte = BytesIO()
|
||||
image = Image.open(BytesIO(resp.body))
|
||||
|
|
|
@ -159,7 +159,7 @@ def import_from_path(mod_path):
|
|||
|
||||
mod_path = Path(mod_path)
|
||||
|
||||
if mod_path.isdir():
|
||||
if mod_path.isdir:
|
||||
path = mod_path.join('__init__.py')
|
||||
name = path.name
|
||||
|
||||
|
@ -167,7 +167,7 @@ def import_from_path(mod_path):
|
|||
path = mod_path
|
||||
name = path.name.replace('.py', '', -1)
|
||||
|
||||
spec = util.spec_from_file_location(name, path.str())
|
||||
spec = util.spec_from_file_location(name, path)
|
||||
module = util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
@ -189,16 +189,16 @@ def nfs_check(path):
|
|||
return
|
||||
|
||||
proc = Path('/proc/mounts')
|
||||
path = Path(path).resolve()
|
||||
path = Path(path).resolve
|
||||
|
||||
if not proc.exists():
|
||||
if not proc.exists:
|
||||
return True
|
||||
|
||||
with proc.open() as fd:
|
||||
for line in fd:
|
||||
line = line.split()
|
||||
|
||||
if line[2] == 'nfs' and line[1] in path.str():
|
||||
if line[2] == 'nfs' and line[1] in path:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -281,7 +281,7 @@ def prompt(prompt, default=None, valtype=str, options=[], password=False):
|
|||
|
||||
ret = valtype(value)
|
||||
|
||||
while valtype == Path and not ret.parent().exists():
|
||||
while valtype == Path and not ret.parent.exists:
|
||||
input_func('Parent directory doesn\'t exist')
|
||||
ret = Path(input(prompt))
|
||||
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import pathlib
|
||||
import os, shutil
|
||||
|
||||
from datetime import datetime
|
||||
from functools import cached_property
|
||||
|
||||
from . import DotDict, JsonEncoder
|
||||
|
||||
|
||||
class Path(pathlib.Path):
|
||||
class Path(str):
|
||||
def __init__(self, path, exist=True, missing=True, parents=True):
|
||||
if str(path).startswith('~'):
|
||||
path = pathlib.Path(path).expanduser()
|
||||
str.__new__(Path, os.path.expanduser(path))
|
||||
|
||||
super().__init__(path)
|
||||
else:
|
||||
str.__new__(Path, path)
|
||||
|
||||
self.config = {
|
||||
'missing': missing,
|
||||
|
@ -17,18 +21,18 @@ class Path(pathlib.Path):
|
|||
}
|
||||
|
||||
|
||||
def __new__(cls, content):
|
||||
return str.__new__(cls, content)
|
||||
|
||||
|
||||
def __check_dir(self, path=None):
|
||||
target = self if not path else Path(path)
|
||||
|
||||
if not self.parents and not target.parent().exists():
|
||||
raise FileNotFoundError('Parent directories do not exist:', target.str())
|
||||
if not self.parents and not target.parent.exists:
|
||||
raise FileNotFoundError('Parent directories do not exist:', target)
|
||||
|
||||
if not self.exist and target.exists():
|
||||
raise FileExistsError('File or directory already exists:', target.str())
|
||||
|
||||
|
||||
def __parse_perm_octal(self, mode):
|
||||
return mode if type(mode) == oct else eval(f'0o{mode}')
|
||||
if not self.exist and target.exists:
|
||||
raise FileExistsError('File or directory already exists:', target)
|
||||
|
||||
|
||||
def append(self, text):
|
||||
|
@ -41,8 +45,7 @@ class Path(pathlib.Path):
|
|||
|
||||
|
||||
def chmod(self, mode=None):
|
||||
octal = self.__parse_perm_octal(mode)
|
||||
super().chmod(octal)
|
||||
os.chmod(self, mode)
|
||||
|
||||
|
||||
def copy(self, path, overwrite=False):
|
||||
|
@ -51,21 +54,31 @@ class Path(pathlib.Path):
|
|||
self.__check_dir(path)
|
||||
|
||||
if target.exists and overwrite:
|
||||
target.delete
|
||||
target.delete()
|
||||
|
||||
copyfile(self, target)
|
||||
|
||||
|
||||
def join(self, path):
|
||||
return Path(self.joinpath(path))
|
||||
def delete(self):
|
||||
if self.isdir:
|
||||
rmtree(self)
|
||||
|
||||
else:
|
||||
os.remove(self)
|
||||
|
||||
return not self.exists
|
||||
|
||||
|
||||
def join(self, new_path):
|
||||
return Path(os.path.join(self, new_path))
|
||||
|
||||
|
||||
def json_load(self):
|
||||
return DotDict(self.read())
|
||||
return DotDict(read(self))
|
||||
|
||||
|
||||
def json_save(self, data, indent=None):
|
||||
with self.open('w') as fp:
|
||||
with open(self, 'w') as fp:
|
||||
fp.write(json.dumps(data, indent=indent, cls=JsonEncoder))
|
||||
|
||||
|
||||
|
@ -74,97 +87,121 @@ class Path(pathlib.Path):
|
|||
|
||||
self.__check_dir(path)
|
||||
|
||||
if target.exists():
|
||||
if target.exists:
|
||||
target.delete()
|
||||
|
||||
self.symlink_to(path, target.isdir())
|
||||
self.symlink_to(path, target.isdir)
|
||||
|
||||
|
||||
def listdir(self, recursive=True):
|
||||
if recursive:
|
||||
return tuple(self.join(f) for dp, dn, fn in os.walk(self) for f in fn)
|
||||
|
||||
return [self.join(path) for path in os.listdir(self)]
|
||||
|
||||
|
||||
def mkdir(self, mode=0o755):
|
||||
self.__path.mkdir(mode, self.parents, self.exist)
|
||||
if self.parents:
|
||||
os.makedirs(self, mode, exist_ok=self.exist)
|
||||
|
||||
return True if self.__path.exists() else False
|
||||
else:
|
||||
os.makedir(self, mode, exist_ok=self.exist)
|
||||
|
||||
return self.exists
|
||||
|
||||
|
||||
def move(self, path, overwrite=False):
|
||||
self.copy(path, overwrite=overwrite)
|
||||
self.delete()
|
||||
if not overwrite and self.exists:
|
||||
raise FileExistsError(f'Refusing to move file to existing destination: {path}')
|
||||
|
||||
shutil.move(self, path)
|
||||
|
||||
|
||||
def touch(self, mode=0o666):
|
||||
octal = __parse_perm_octal(mode)
|
||||
self.__path.touch(octal, self.exist)
|
||||
|
||||
return self.exists()
|
||||
def open(self, *args, **kwargs):
|
||||
return open(self, *args, **kwargs)
|
||||
|
||||
|
||||
@property
|
||||
def delete(self):
|
||||
if self.isdir():
|
||||
rmtree(self)
|
||||
def read(self):
|
||||
fd = open(self)
|
||||
data = fd.read()
|
||||
fd.close()
|
||||
|
||||
else:
|
||||
self.unlink()
|
||||
return data
|
||||
|
||||
return not self.exists
|
||||
|
||||
def readlines(self):
|
||||
fd = open(self)
|
||||
data = fd.readlines()
|
||||
fd.close()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def touch(self, mode=0o644, utime=None):
|
||||
timestamp = utime or datetime.now().timestamp()
|
||||
|
||||
with self.open('w+') as fd:
|
||||
os.utime(self, (timestamp, timestamp))
|
||||
self.chmod(mode)
|
||||
|
||||
return self.exists
|
||||
|
||||
|
||||
@property
|
||||
def exists(self):
|
||||
return super().exists()
|
||||
return os.path.exists(self)
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def home(self):
|
||||
return Path(pathlib.Path.home())
|
||||
return Path('~')
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def isdir(self):
|
||||
return self.is_dir()
|
||||
return os.path.isdir(self)
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def isfile(self):
|
||||
return self.is_file()
|
||||
return os.path.isfile(self)
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def islink(self):
|
||||
return self.is_symlink()
|
||||
|
||||
|
||||
@property
|
||||
def listdir(self, recursive=True):
|
||||
paths = self.iterdir() if recursive else os.listdir(self)
|
||||
return [Path(path) for path in paths]
|
||||
return os.path.islink(self)
|
||||
|
||||
|
||||
@property
|
||||
def mtime(self):
|
||||
return os.path.getmtime(self.str())
|
||||
return os.path.getmtime(self)
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def name(self):
|
||||
return os.path.basename(self)
|
||||
|
||||
|
||||
@cached_property
|
||||
def parent(self):
|
||||
return Path(super().parent)
|
||||
return Path(os.path.dirname(self))
|
||||
|
||||
|
||||
@property
|
||||
def read(self):
|
||||
return self.open().read()
|
||||
|
||||
|
||||
@property
|
||||
def readlines(self):
|
||||
return self.open().readlines()
|
||||
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def resolve(self):
|
||||
return Path(super().resolve())
|
||||
return Path(os.path.abspath(self))
|
||||
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self.stat().st_size
|
||||
return os.path.getsize(self)
|
||||
|
||||
|
||||
@cached_property
|
||||
def stem(self):
|
||||
return os.path.basename(self).split('.')[0]
|
||||
|
||||
|
||||
@cached_property
|
||||
def suffix(self):
|
||||
return os.path.splitext(self)[1]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_namespace_packages
|
||||
|
||||
|
||||
setup(
|
||||
name="IzzyLib Base",
|
||||
version='0.6.0',
|
||||
packages=['izzylib'],
|
||||
packages=find_namespace_packages(include=['izzylib']),
|
||||
python_requires='>=3.7.0',
|
||||
include_package_data=False,
|
||||
author='Zoey Mae',
|
||||
|
|
|
@ -19,7 +19,7 @@ requires = [
|
|||
setup(
|
||||
name="IzzyLib HTTP Server",
|
||||
version='0.6.0',
|
||||
packages=['izzylib.http_server'],
|
||||
packages=find_namespace_packages(include=['izzylib.http_server']),
|
||||
python_requires='>=3.7.0',
|
||||
install_requires=requires,
|
||||
include_package_data=False,
|
||||
|
|
|
@ -12,7 +12,7 @@ requires = [
|
|||
setup(
|
||||
name="IzzyLib Requests Client",
|
||||
version='0.6.0',
|
||||
packages=['izzylib.http_requests_client'],
|
||||
packages=find_namespace_packages(include=['izzylib.http_requests_client']),
|
||||
python_requires='>=3.7.0',
|
||||
install_requires=requires,
|
||||
include_package_data=False,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_namespace_packages
|
||||
|
||||
|
||||
requires = [
|
||||
|
@ -15,7 +15,7 @@ requires = [
|
|||
setup(
|
||||
name="IzzyLib SQL",
|
||||
version='0.6.0',
|
||||
packages=['izzylib.sql'],
|
||||
packages=find_namespace_packages(include=['izzylib.sql']),
|
||||
python_requires='>=3.7.0',
|
||||
install_requires=requires,
|
||||
include_package_data=False,
|
||||
|
|
|
@ -22,7 +22,7 @@ class Template(Environment):
|
|||
self.func_context = context
|
||||
|
||||
for path in search:
|
||||
self.__add_search_path(path)
|
||||
self.__add_search_path(Path(path))
|
||||
|
||||
super().__init__(
|
||||
loader=ChoiceLoader([FileSystemLoader(path) for path in self.search]),
|
||||
|
@ -46,13 +46,12 @@ class Template(Environment):
|
|||
|
||||
|
||||
def __add_search_path(self, path):
|
||||
tpl_path = Path(path)
|
||||
if not path.exists:
|
||||
raise FileNotFoundError(f'Cannot find search path: {path}')
|
||||
|
||||
if not tpl_path.exists():
|
||||
raise FileNotFoundError('Cannot find search path:', tpl_path.str())
|
||||
if path not in self.search:
|
||||
self.search.append(path)
|
||||
|
||||
if tpl_path.str() not in self.search:
|
||||
self.search.append(tpl_path.str())
|
||||
|
||||
def setContext(self, context):
|
||||
if not hasattr(context, '__call__'):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_namespace_packages
|
||||
|
||||
|
||||
requires = [
|
||||
|
@ -13,7 +13,7 @@ requires = [
|
|||
setup(
|
||||
name="IzzyLib Templates",
|
||||
version='0.6.0',
|
||||
packages=['izzylib.template'],
|
||||
packages=find_namespace_packages(include=['izzylib.template']),
|
||||
python_requires='>=3.7.0',
|
||||
install_requires=requires,
|
||||
include_package_data=False,
|
||||
|
|
|
@ -13,7 +13,7 @@ requires = [
|
|||
setup(
|
||||
name="IzzyLib TinyDB",
|
||||
version='0.6.0',
|
||||
packages=['izzylib.tinydb'],
|
||||
packages=find_namespace_packages(include=['izzylib.tinydb']),
|
||||
python_requires='>=3.7.0',
|
||||
install_requires=requires,
|
||||
include_package_data=False,
|
||||
|
|
Loading…
Reference in a new issue