From a156b3b416a9549ee439adc36785cca4131c499c Mon Sep 17 00:00:00 2001 From: Izalia Mae Date: Sat, 16 Apr 2022 06:16:39 -0400 Subject: [PATCH] add path.UnixPerms --- izzylib/path.py | 156 +++++++++++++++++++++++++++++++++++++++++++++++- izzylib/url.py | 6 +- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/izzylib/path.py b/izzylib/path.py index b3b2557..b022b46 100644 --- a/izzylib/path.py +++ b/izzylib/path.py @@ -21,6 +21,131 @@ class TinyDotDict(dict): __delattr__ = dict.__delitem__ +class UnixPerms: + PERMS = TinyDotDict( + READ = 4, + WRITE = 2, + EXECUTE = 1 + ) + + SHORT_PERMS = TinyDotDict( + R = 4, + W = 2, + X = 1 + ) + + READ = PERMS.READ + WRITE = PERMS.WRITE + EXECUTE = PERMS.EXECUTE + + R = SHORT_PERMS.R + W = SHORT_PERMS.W + X = SHORT_PERMS.X + + KEYS = ['user', 'group', 'other'] + + + def __init__(self, user=6, group=4, other=4): + self.__perms = [0,0,0] + + self['user'] = user + self['group'] = group + self['other'] = other + + + def __repr__(self): + return f'{self.__class__.__name__}(user={self[0]}, group={self[1]}, other={self[2]})' + + + def __str__(self): + values = ''.join(str(perm) for perm in self.__perms) + return f'0o{values}' + + + def __int__(self): + return int(self.__str__()[2:]) + + + def __iter__(self): + for perm in self.__perms: + yield perm + + + def __getitem__(self, key): + if isinstance(key, str): + key = self.KEYS[key] + + elif not isinstance(key, int): + raise TypeError('Key must be a str for int') + + assert key < 3 + return self.__perms[key] + + + def __setitem__(self, key, value): + if isinstance(key, str): + key = self.KEYS.index(key) + + if isinstance(value, str): + value = self._str_to_int(value) + + self.__perms[key] = value + + + @classmethod + def new(cls, data): + if isinstance(data, int): + try: + data = int(str(data), 8) + + except ValueError: + pass + + data = format(data, 'o') + return cls(*(int(n) for n in data)) + + elif isinstance(data, str): + return cls(data[0:3], data[3:6], data[6:9]) + + raise TypeError('Data must be an int, oct, or str') + + + def _int_to_str(self, value): + new_value = '' + + for name, num in self.SHORT_PERMS.items(): + if num <= value: + new_value += name.lower() + value -= num + + else: + new_value += '-' + + return new_value + + + def _str_to_int(self, string): + assert isinstance(string, str) + + new_value = 0 + + for value in string: + if value == '-': + continue + + new_value += self.SHORT_PERMS[value.upper()] + + return new_value + + + def to_int(self): + return self.__int__() + + + def to_string(self): + return ''.join(self._int_to_str(perm) for perm in self) + + class PathMeta(type): @property def cache(cls): @@ -53,6 +178,34 @@ class PathMeta(type): return cls(module.__file__).parent + def app_data_dir(cls, prefix:str, author:str, name:str): + 'Returns the cache or config path for software' + + assert prefix in ['config', 'cache'] + + if platform.system() == 'Linux': + config = cls('~/.config') + cache = cls('~/.cache') + + elif platform.system() == 'Darwin': + config = cls('~/Application Support') + cache = cls('~/Library/Caches') + + elif platform.system() == 'Windows': + return DotDict( + config = cls('~/Application Data/Local Settings').join(author, name), + cache = cls('~/Application Data').join(author, name, 'Cache') + )[prefix] + + else: + raise TypeError(f'Unknown system: {platform.system()}') + + return DotDict( + config = config.join(author, name), + cache = cache.join(author, name) + )[preifx] + + def unix(cls, prefix, author, software): try: return cls.home.join(linux_prefix[prefix], author, software) @@ -166,7 +319,8 @@ class Path(str, metaclass=PathMeta): def chmod(self, mode): - os.chmod(self, mode) + mode = UnixPerms.new(mode) + os.chmod(self, int(mode)) def contains(self, text): diff --git a/izzylib/url.py b/izzylib/url.py index 2988c74..633fc6c 100644 --- a/izzylib/url.py +++ b/izzylib/url.py @@ -282,10 +282,10 @@ class Url(str): return Url.new(**self.dict) - def hostname(self, return_port=False): - 'Return the domain and port. If return_port is false and the port is the default for the protocol, only return the domain.' + def hostname(self, always_return_port=False): + 'Return the domain and port. If always_return_port is false and the port is the default for the protocol, only return the domain.' - if not return_port and self.port == self.protocol.value: + if not always_return_port and self.port == self.protocol.value: return self.domain return self.host