Created
August 26, 2015 16:37
-
-
Save davtoh/c6fd27541ac98d1f2b90 to your computer and use it in GitHub Desktop.
directory class for mutable string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| __author__ = 'Davtoh' | |
| import os,inspect,functools | |
| import shutil | |
| def getPath(filename=__file__): | |
| """get standard path from filename""" | |
| body,base = os.path.splitext(filename) | |
| if base != "": | |
| body = os.path.dirname(body) | |
| return os.path.abspath(body) | |
| def mkPath(filepath): | |
| """make path for filename""" | |
| path = getPath(filepath) | |
| if not os.path.exists(path): os.makedirs(path) | |
| return path | |
| def rmPath(filepath): | |
| """remove path from filename""" | |
| path = getPath(filepath) | |
| shutil.rmtree(path) | |
| return True | |
| def getPathIndicator(path,pattern='/\\'): | |
| """ | |
| obtain path indicator | |
| :param path: relative or absolute path (str) | |
| :param pattern: guess characters to compare path (str) | |
| :return: indicator (str) | |
| """ | |
| i = len(path) | |
| while i and path[i-1] not in pattern: i -= 1 | |
| head, tail = path[:i], path[i:] # now tail has no slashes | |
| # remove trailing slashes from head, unless it's all slashes | |
| head2 = head | |
| count = 0 | |
| while head2 and head2[-1] in pattern: | |
| head2 = head2[:-1] | |
| count += 1 | |
| character = head[len(head)-count:len(head)] # get the slash character | |
| return character | |
| def getShortenedPath(path,comp): | |
| """ | |
| path is controlled to give absolute path from relative path or integer | |
| :param path: absolute path (str) | |
| :param comp: pattern or relative path (str) or integer representing level of folder | |
| determined by the separator Ex. C://level 1//level 2//...//level N or -1 | |
| :return: path before matched comp Ex: C://level 1//"comp" --> C://level 1 | |
| """ | |
| if type(comp) is str: | |
| if os.path.isabs(comp): | |
| comp = os.path.relpath(path,comp) | |
| return path.split(comp)[0] | |
| else: | |
| indicator = getPathIndicator(path) | |
| return indicator.join(path.split(indicator)[:comp]) | |
| def decoratePath(relative,indicator=os.path.sep): | |
| """ | |
| decorated path is controlled to give absolute path from relative path | |
| :param relative: int or path | |
| :param indicator: | |
| :return: | |
| """ | |
| def decorator(f): | |
| @functools.wraps(f) | |
| def wrapper(*args,**kwargs): | |
| path = f(*args,**kwargs) | |
| return indicator.join(getShortenedPath(path,relative).split(getPathIndicator(path))) | |
| return wrapper | |
| return decorator | |
| def correctPath(relative,filename=__file__): | |
| """ | |
| get path corrected from its relative path or level index | |
| :param relative: pattern or level in directory | |
| :param filename: path or file name | |
| :return: corrected path | |
| """ | |
| return decoratePath(relative)(getPath)(filename) | |
| def joinPath(absolute,relative): | |
| """ | |
| joins an absolute path to a relative path => str | |
| """ | |
| return os.path.join(str(absolute), str(relative)) # ensures updated version is processed | |
| def repr2list(data,level=0): | |
| """ | |
| converts the representation of a directory.repr to pickleable | |
| :param data: directory.repr of the form ["string",directory,...,directory.repr] | |
| :return: pickeable list | |
| """ | |
| if isinstance(data,list): # list defines levels of directories | |
| if level == 0: # [level 0, ..., [level 1, [...[level N]...]], level 0] | |
| for i,value in enumerate(data): # process several objects in the list | |
| data[i] = repr2list(value,level+1) | |
| return data | |
| else: # convert anything to directory if not in level 0 | |
| return directory(data) | |
| elif isinstance(data,str): # if string or directory | |
| return data | |
| else: # try to convert to directory | |
| return directory(data) | |
| def repr2str(data, ispath = True): | |
| """ | |
| converts the representation of a directory.repr to string | |
| :param data: directory.repr of the form ["string",directory,...,directory.repr] | |
| :return: converted string | |
| """ | |
| if isinstance(data,list): | |
| if len(data)>1: | |
| string = str(repr2str(data[0])) | |
| for i in data[1:]: | |
| if ispath: | |
| string = joinPath(string,repr2str(i)) # join paths | |
| else: | |
| string += repr2str(i, ispath) | |
| return string | |
| else: | |
| return str(data[0]) # get single path | |
| elif isinstance(data, directory): | |
| return repr2str(data.repr, data.ispath) | |
| else: | |
| return str(data) # object must be string | |
| def correctSTRBuiltin(self): | |
| """ | |
| decorate all the built-in functions of class directory | |
| :return: built-in decorated function | |
| """ | |
| def decorator(f): | |
| @functools.wraps(f) | |
| def wrapper(*args,**kwargs): | |
| return getattr(str(self),f.__name__,f.__name__)(*args,**kwargs) | |
| return wrapper | |
| return decorator | |
| class directory(str): | |
| #repr = [""] | |
| def __new__(cls, data, ispath = None, copy = False, **kwargs): | |
| # data can be list, str, directory or dictionary | |
| data = directory.filterdata(data,ispath,kwargs) | |
| self = str.__new__(cls, repr2str(data["repr"],data["ispath"])) | |
| if copy: | |
| self.__dict__.update(data) | |
| else: | |
| self.__dict__ = data | |
| return self | |
| @staticmethod | |
| def filterdata(data, ispath = None, kwargs=None): | |
| if isinstance(data,directory): | |
| data = data.__dict__ | |
| elif not isinstance(data,dict): | |
| if isinstance(data,list): | |
| data = {"repr":data} | |
| else: | |
| data = {"repr":[data]} | |
| if ispath: data["ispath"]= ispath | |
| if not data.has_key("ispath"): data["ispath"] = True # repr default | |
| if not data.has_key("repr"): | |
| data["repr"] = [""] # repr default | |
| else: | |
| data["repr"] = repr2list(data["repr"]) # ensure repr is maintained | |
| if kwargs: data.update(kwargs) # update data with kwargs | |
| return data | |
| def __add__(self, other): | |
| if type(other)==str: # it's exactly str an not directory | |
| return joinPath(self,other) | |
| return self.update_right(other) | |
| def __sub__(self, other): | |
| if type(other)==str: # it's exactly str an not directory | |
| return joinPath(other,self) | |
| return self.update_left(other) | |
| def update_right(self, other): | |
| self.repr.append(other) # it will be parsed at directory creation | |
| return directory(self) # string is immutable and must be renewed | |
| def update_left(self, other): | |
| self.repr.insert(0,other) # it will be parsed at directory creation | |
| return directory(self) # string is immutable and must be renewed | |
| def update(self, data = None): | |
| if isinstance(data,list): # if list | |
| if len(data)>len(self.repr): | |
| for i in xrange(len(self.repr)): | |
| self.repr[i] = data[i] | |
| for j in xrange(i+1,len(data)): | |
| self.repr.append(data[j]) | |
| else: | |
| for i in xrange(len(data)): | |
| self.repr[i] = data[i] | |
| del self.repr[i+1:] | |
| return directory(self) # string is immutable and must be renewed | |
| elif isinstance(data,dict): # if dictionary | |
| self.__dict__.update(data) | |
| return directory(self) | |
| elif data: # if not list or dict | |
| return self.update([data]) | |
| else: # if None return updated version | |
| return directory(self) | |
| def __str__(self): | |
| return repr2str(self.repr, self.ispath) | |
| def __repr__(self): | |
| return str(self.repr) | |
| # TODO: implement 2 versions: one with directory-like functionality and other basic for str support | |
| """ | |
| ### MAGIC FUNCTIONS | |
| def __nonzero__(self): | |
| return self == self.update() | |
| def __getitem__(self, item): | |
| return self.repr[item] | |
| def __len__(self): | |
| return len(self.repr)""" | |
| if __name__=="__main__": | |
| import session as sn | |
| import dill | |
| ## TESTS | |
| a = directory("string1",sapo = "mamo") | |
| b = a.update(["string2",["string4","string 5"]]) | |
| result = bool(a) # False | |
| result = bool(b) # True | |
| c = directory(["string3"])-a | |
| sn.saveSession("test.pkl",{"d",a}) | |
| c = sn.readSession("test.pkl") | |
| print type(a)==directory | |
| print type(a) is directory | |
| print a is directory | |
| print a == directory | |
| print "with str" | |
| print type(a)==str | |
| print type(a) is str | |
| print a is str | |
| print a == str | |
| print isinstance(a,str) | |
| print type(a) | |
| print os.path.splitext(os.path.basename(__file__)) ### look here ### |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment