From 4177eefd7bdaea96a529b00ba9cf751924ede202 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 5 May 2011 19:43:22 +0200 Subject: Added all code from gitdb to gitpython. Next is to make it generally work. Then the tests will need some work --- git/db/py/base.py | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 git/db/py/base.py (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py new file mode 100644 index 00000000..c378b10e --- /dev/null +++ b/git/db/py/base.py @@ -0,0 +1,351 @@ +# Copyright (C) 2010, 2011 Sebastian Thiel (byronimo@gmail.com) and contributors +# +# This module is part of GitDB and is released under +# the New BSD License: http://www.opensource.org/licenses/bsd-license.php +"""Contains basic implementations for the interface building blocks""" + +from gitdb.db.interface import * + +from gitdb.util import ( + pool, + join, + normpath, + abspath, + dirname, + LazyMixin, + hex_to_bin, + bin_to_hex, + expandvars, + expanduser, + exists, + is_git_dir + ) + +from gitdb.config import GitConfigParser +from gitdb.exc import ( + BadObject, + AmbiguousObjectName, + InvalidDBRoot + ) + +from async import ChannelThreadTask + +from itertools import chain +import sys +import os + + +__all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB', + 'PureConfigurationMixin', 'PureRepositoryPathsMixin') + + +class PureObjectDBR(ObjectDBR): + + #{ Query Interface + + def has_object_async(self, reader): + task = ChannelThreadTask(reader, str(self.has_object_async), lambda sha: (sha, self.has_object(sha))) + return pool.add_task(task) + + def info_async(self, reader): + task = ChannelThreadTask(reader, str(self.info_async), self.info) + return pool.add_task(task) + + def stream_async(self, reader): + # base implementation just uses the stream method repeatedly + task = ChannelThreadTask(reader, str(self.stream_async), self.stream) + return pool.add_task(task) + + def partial_to_complete_sha_hex(self, partial_hexsha): + len_partial_hexsha = len(partial_hexsha) + if len_partial_hexsha % 2 != 0: + partial_binsha = hex_to_bin(partial_hexsha + "0") + else: + partial_binsha = hex_to_bin(partial_hexsha) + # END assure successful binary conversion + return self.partial_to_complete_sha(partial_binsha, len(partial_hexsha)) + + #} END query interface + + +class PureObjectDBW(ObjectDBW): + + def __init__(self, *args, **kwargs): + super(PureObjectDBW, self).__init__(*args, **kwargs) + self._ostream = None + + #{ Edit Interface + def set_ostream(self, stream): + cstream = self._ostream + self._ostream = stream + return cstream + + def ostream(self): + return self._ostream + + def store_async(self, reader): + task = ChannelThreadTask(reader, str(self.store_async), self.store) + return pool.add_task(task) + + #} END edit interface + + +class PureRootPathDB(RootPathDB): + + def __init__(self, root_path): + super(PureRootPathDB, self).__init__(root_path) + self._root_path = root_path + + + #{ Interface + def root_path(self): + return self._root_path + + def db_path(self, rela_path): + return join(self._root_path, rela_path) + #} END interface + + +def _databases_recursive(database, output): + """Fill output list with database from db, in order. Deals with Loose, Packed + and compound databases.""" + if isinstance(database, CompoundDB): + compounds = list() + dbs = database.databases() + output.extend(db for db in dbs if not isinstance(db, CompoundDB)) + for cdb in (db for db in dbs if isinstance(db, CompoundDB)): + _databases_recursive(cdb, output) + else: + output.append(database) + # END handle database type + + +class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB): + def _set_cache_(self, attr): + if attr == '_dbs': + self._dbs = list() + elif attr == '_db_cache': + self._db_cache = dict() + else: + super(PureCompoundDB, self)._set_cache_(attr) + + def _db_query(self, sha): + """:return: database containing the given 20 byte sha + :raise BadObject:""" + # most databases use binary representations, prevent converting + # it everytime a database is being queried + try: + return self._db_cache[sha] + except KeyError: + pass + # END first level cache + + for db in self._dbs: + if db.has_object(sha): + self._db_cache[sha] = db + return db + # END for each database + raise BadObject(sha) + + #{ PureObjectDBR interface + + def has_object(self, sha): + try: + self._db_query(sha) + return True + except BadObject: + return False + # END handle exceptions + + def info(self, sha): + return self._db_query(sha).info(sha) + + def stream(self, sha): + return self._db_query(sha).stream(sha) + + def size(self): + return reduce(lambda x,y: x+y, (db.size() for db in self._dbs), 0) + + def sha_iter(self): + return chain(*(db.sha_iter() for db in self._dbs)) + + #} END object DBR Interface + + #{ Interface + + def databases(self): + return tuple(self._dbs) + + def update_cache(self, force=False): + # something might have changed, clear everything + self._db_cache.clear() + stat = False + for db in self._dbs: + if isinstance(db, CachingDB): + stat |= db.update_cache(force) + # END if is caching db + # END for each database to update + return stat + + def partial_to_complete_sha_hex(self, partial_hexsha): + databases = self.databases() + + len_partial_hexsha = len(partial_hexsha) + if len_partial_hexsha % 2 != 0: + partial_binsha = hex_to_bin(partial_hexsha + "0") + else: + partial_binsha = hex_to_bin(partial_hexsha) + # END assure successful binary conversion + + candidate = None + for db in self._dbs: + full_bin_sha = None + try: + if hasattr(db, 'partial_to_complete_sha_hex'): + full_bin_sha = db.partial_to_complete_sha_hex(partial_hexsha) + else: + full_bin_sha = db.partial_to_complete_sha(partial_binsha, len_partial_hexsha) + # END handle database type + except BadObject: + continue + # END ignore bad objects + if full_bin_sha: + if candidate and candidate != full_bin_sha: + raise AmbiguousObjectName(partial_hexsha) + candidate = full_bin_sha + # END handle candidate + # END for each db + if not candidate: + raise BadObject(partial_binsha) + return candidate + + def partial_to_complete_sha(self, partial_binsha, hex_len): + """Simple adaptor to feed into our implementation""" + return self.partial_to_complete_sha_hex(bin_to_hex(partial_binsha)[:hex_len]) + #} END interface + + +class PureRepositoryPathsMixin(RepositoryPathsMixin): + # slots has no effect here, its just to keep track of used attrs + __slots__ = ("_git_path", '_bare') + + #{ Configuration + repo_dir = '.git' + objs_dir = 'objects' + #} END configuration + + #{ Subclass Interface + def _initialize(self, path): + epath = abspath(expandvars(expanduser(path or os.getcwd()))) + + if not exists(epath): + raise InvalidDBRoot(epath) + #END check file + + self._working_tree_dir = None + self._git_path = None + curpath = epath + + # walk up the path to find the .git dir + while curpath: + if is_git_dir(curpath): + self._git_path = curpath + self._working_tree_dir = os.path.dirname(curpath) + break + gitpath = join(curpath, self.repo_dir) + if is_git_dir(gitpath): + self._git_path = gitpath + self._working_tree_dir = curpath + break + curpath, dummy = os.path.split(curpath) + if not dummy: + break + # END while curpath + + if self._git_path is None: + raise InvalidDBRoot(epath) + # END path not found + + self._bare = self._git_path.endswith(self.repo_dir) + if hasattr(self, 'config_reader'): + try: + self._bare = self.config_reader("repository").getboolean('core','bare') + except Exception: + # lets not assume the option exists, although it should + pass + #END check bare flag + + + #} end subclass interface + + #{ Interface + + def is_bare(self): + return self._bare + + def git_path(self): + return self._git_path + + def working_tree_path(self): + if self.is_bare(): + raise AssertionError("Repository at %s is bare and does not have a working tree directory" % self.git_path()) + #END assertion + return dirname(self.git_path()) + + def objects_path(self): + return join(self.git_path(), self.objs_dir) + + def working_dir(self): + if self.is_bare(): + return self.git_path() + else: + return self.working_tree_dir() + #END handle bare state + + #} END interface + + +class PureConfigurationMixin(ConfigurationMixin): + + #{ Configuration + system_config_file_name = "gitconfig" + repo_config_file_name = "config" + #} END + + def __init__(self, *args, **kwargs): + """Verify prereqs""" + assert hasattr(self, 'git_path') + + def _path_at_level(self, level ): + # we do not support an absolute path of the gitconfig on windows , + # use the global config instead + if sys.platform == "win32" and level == "system": + level = "global" + #END handle windows + + if level == "system": + return "/etc/%s" % self.system_config_file_name + elif level == "global": + return normpath(expanduser("~/.%s" % self.system_config_file_name)) + elif level == "repository": + return join(self.git_path(), self.repo_config_file_name) + #END handle level + + raise ValueError("Invalid configuration level: %r" % level) + + #{ Interface + + def config_reader(self, config_level=None): + files = None + if config_level is None: + files = [ self._path_at_level(f) for f in self.config_level ] + else: + files = [ self._path_at_level(config_level) ] + #END handle level + return GitConfigParser(files, read_only=True) + + def config_writer(self, config_level="repository"): + return GitConfigParser(self._path_at_level(config_level), read_only=False) + + #} END interface + -- cgit v1.2.3 From acf5e6ea64a2f24117f1d419c208ed1c38c43690 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 6 May 2011 15:03:14 +0200 Subject: replaced all gitdb strings with git --- git/db/py/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index c378b10e..28bbf258 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -4,9 +4,9 @@ # the New BSD License: http://www.opensource.org/licenses/bsd-license.php """Contains basic implementations for the interface building blocks""" -from gitdb.db.interface import * +from git.db.interface import * -from gitdb.util import ( +from git.util import ( pool, join, normpath, @@ -21,8 +21,8 @@ from gitdb.util import ( is_git_dir ) -from gitdb.config import GitConfigParser -from gitdb.exc import ( +from git.config import GitConfigParser +from git.exc import ( BadObject, AmbiguousObjectName, InvalidDBRoot -- cgit v1.2.3 From 7ae36c3e019a5cc16924d1b6007774bfb625036f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 6 May 2011 18:53:59 +0200 Subject: Started to fix imports - tests still have no chance to work as database changed drastically. Now the actual work begins --- git/db/py/base.py | 1 - 1 file changed, 1 deletion(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index 28bbf258..5c470ba4 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -3,7 +3,6 @@ # This module is part of GitDB and is released under # the New BSD License: http://www.opensource.org/licenses/bsd-license.php """Contains basic implementations for the interface building blocks""" - from git.db.interface import * from git.util import ( -- cgit v1.2.3 From cd26aaebbda94dc3740e41bbd3f91ba6b1a25c10 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 10 May 2011 10:21:26 +0200 Subject: Made repository paths methods a property to be compatible with the existing repo interface. Added submodule interface ... goal is to provide all of the extra repo functionality in custom interfaces --- git/db/py/base.py | 67 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 15 deletions(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index 5c470ba4..f45711d5 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -273,34 +273,70 @@ class PureRepositoryPathsMixin(RepositoryPathsMixin): # lets not assume the option exists, although it should pass #END check bare flag + + #} end subclass interface + + #{ Object Interface + + def __eq__(self, rhs): + if hasattr(rhs, 'git_dir'): + return self.git_dir == rhs.git_dir + return False + + def __ne__(self, rhs): + return not self.__eq__(rhs) + + def __hash__(self): + return hash(self.git_dir) + def __repr__(self): + return "%s(%r)" % (type(self).__name__, self.git_dir) - #} end subclass interface + #} END object interface #{ Interface + @property def is_bare(self): return self._bare - def git_path(self): + @property + def git_dir(self): return self._git_path - def working_tree_path(self): - if self.is_bare(): - raise AssertionError("Repository at %s is bare and does not have a working tree directory" % self.git_path()) + @property + def working_tree_dir(self): + if self.is_bare: + raise AssertionError("Repository at %s is bare and does not have a working tree directory" % self.git_dir) #END assertion - return dirname(self.git_path()) - - def objects_path(self): - return join(self.git_path(), self.objs_dir) - + return dirname(self.git_dir) + + @property + def objects_dir(self): + return join(self.git_dir, self.objs_dir) + + @property def working_dir(self): - if self.is_bare(): - return self.git_path() + if self.is_bare: + return self.git_dir else: - return self.working_tree_dir() + return self.working_tree_dir #END handle bare state + def _mk_description(): + def _get_description(self): + filename = join(self.git_dir, 'description') + return file(filename).read().rstrip() + + def _set_description(self, descr): + filename = join(self.git_dir, 'description') + file(filename, 'w').write(descr+'\n') + + return property(_get_description, _set_description, "Descriptive text for the content of the repository") + + description = _mk_description() + del(_mk_description) + #} END interface @@ -313,7 +349,7 @@ class PureConfigurationMixin(ConfigurationMixin): def __init__(self, *args, **kwargs): """Verify prereqs""" - assert hasattr(self, 'git_path') + assert hasattr(self, 'git_dir') def _path_at_level(self, level ): # we do not support an absolute path of the gitconfig on windows , @@ -327,7 +363,7 @@ class PureConfigurationMixin(ConfigurationMixin): elif level == "global": return normpath(expanduser("~/.%s" % self.system_config_file_name)) elif level == "repository": - return join(self.git_path(), self.repo_config_file_name) + return join(self.git_dir, self.repo_config_file_name) #END handle level raise ValueError("Invalid configuration level: %r" % level) @@ -346,5 +382,6 @@ class PureConfigurationMixin(ConfigurationMixin): def config_writer(self, config_level="repository"): return GitConfigParser(self._path_at_level(config_level), read_only=False) + #} END interface -- cgit v1.2.3 From 0996049122842a343e0ea7fbbecafddb2b4ba9d3 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 29 May 2011 21:59:12 +0200 Subject: Intermediate commit with quite some progress in order to put all extra methods on the default Repo implementation into interfaces or something that can be abstracted. It shows that it would indeed be good to keep the differentiation between Repositories which contain an object database as it is clearly easier to setup any combination of repositories that use git and those that do not, with just the addition of one more level of indirection. Lets see how it will end up --- git/db/py/base.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index f45711d5..cc326c27 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -35,7 +35,7 @@ import os __all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB', - 'PureConfigurationMixin', 'PureRepositoryPathsMixin') + 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin') class PureObjectDBR(ObjectDBR): @@ -385,3 +385,75 @@ class PureConfigurationMixin(ConfigurationMixin): #} END interface + +class PureAlternatesFileMixin(object): + """Utility able to read and write an alternates file through the alternates property + It needs to be part of a type with the git_dir or db_path property. + + The file by default is assumed to be located at the default location as imposed + by the standard git repository layout""" + + #{ Configuration + alternates_filepath = os.path.join('info', 'alternates') # relative path to alternates file + + #} END configuration + + def __init__(self, *args, **kwargs): + super(PureAlternatesFileMixin, self).__init__(*args, **kwargs) + self._alternates_path() # throws on incompatible type + + #{ Interface + + def _alternates_path(self): + if hasattr(self, 'git_dir'): + return join(self.git_dir, 'objects', self.alternates_filepath) + elif hasattr(self, 'db_path'): + return self.db_path(self.alternates_filepath) + else: + raise AssertionError("This mixin requires a parent type with either the git_dir property or db_path method") + #END handle path + + def _get_alternates(self): + """The list of alternates for this repo from which objects can be retrieved + + :return: list of strings being pathnames of alternates""" + alternates_path = self._alternates_path() + + if os.path.exists(alternates_path): + try: + f = open(alternates_path) + alts = f.read() + finally: + f.close() + return alts.strip().splitlines() + else: + return list() + # END handle path exists + + def _set_alternates(self, alts): + """Sets the alternates + + :parm alts: + is the array of string paths representing the alternates at which + git should look for objects, i.e. /home/user/repo/.git/objects + + :raise NoSuchPathError: + :note: + The method does not check for the existance of the paths in alts + as the caller is responsible.""" + alternates_path = self._alternates_path() + if not alts: + if isfile(alternates_path): + os.remove(alternates_path) + else: + try: + f = open(alternates_path, 'w') + f.write("\n".join(alts)) + finally: + f.close() + # END file handling + # END alts handling + + alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") + + #} END interface -- cgit v1.2.3 From 112bb1672d6b28f203e7839e320b985486636800 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 30 May 2011 01:23:28 +0200 Subject: Finished moving all repository methods to the respective interfaces and implementations. It seems theoretically work together now, although it clearly is much more complex than ever before. The repo package was slimmed down to being a module once again, which is only there for compatability actually --- git/db/py/base.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index cc326c27..74b8beb9 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -20,6 +20,7 @@ from git.util import ( is_git_dir ) +from git.index import IndexFile from git.config import GitConfigParser from git.exc import ( BadObject, @@ -35,7 +36,8 @@ import os __all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB', - 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin') + 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin', + 'PureIndexDB') class PureObjectDBR(ObjectDBR): @@ -386,6 +388,16 @@ class PureConfigurationMixin(ConfigurationMixin): #} END interface +class PureIndexDB(IndexDB): + #{ Configuration + IndexCls = IndexFile + #} END configuration + + @property + def index(self): + return self.IndexCls(self) + + class PureAlternatesFileMixin(object): """Utility able to read and write an alternates file through the alternates property It needs to be part of a type with the git_dir or db_path property. -- cgit v1.2.3 From 1f71ed94578799ee1667ba54b66a369e307f415b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 30 May 2011 16:32:56 +0200 Subject: git cmd implementation of repository appears to work, at least this is what the test suggests. Pure python implementation still has some trouble, but this should be very fixable --- git/db/py/base.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index 74b8beb9..4d9b6e14 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -8,6 +8,7 @@ from git.db.interface import * from git.util import ( pool, join, + isfile, normpath, abspath, dirname, @@ -25,7 +26,8 @@ from git.config import GitConfigParser from git.exc import ( BadObject, AmbiguousObjectName, - InvalidDBRoot + InvalidGitRepositoryError, + NoSuchPathError ) from async import ChannelThreadTask @@ -240,7 +242,7 @@ class PureRepositoryPathsMixin(RepositoryPathsMixin): epath = abspath(expandvars(expanduser(path or os.getcwd()))) if not exists(epath): - raise InvalidDBRoot(epath) + raise NoSuchPathError(epath) #END check file self._working_tree_dir = None @@ -264,7 +266,7 @@ class PureRepositoryPathsMixin(RepositoryPathsMixin): # END while curpath if self._git_path is None: - raise InvalidDBRoot(epath) + raise InvalidGitRepositoryError(epath) # END path not found self._bare = self._git_path.endswith(self.repo_dir) @@ -351,6 +353,7 @@ class PureConfigurationMixin(ConfigurationMixin): def __init__(self, *args, **kwargs): """Verify prereqs""" + super(PureConfigurationMixin, self).__init__(*args, **kwargs) assert hasattr(self, 'git_dir') def _path_at_level(self, level ): -- cgit v1.2.3 From 4ea529dd7f545dddc8cfdfdb4b6209eef0494ec5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 30 May 2011 17:16:18 +0200 Subject: Fixed pure python implementation to run the default repository tests --- git/db/py/base.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index 4d9b6e14..a2c9a4ef 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -96,8 +96,9 @@ class PureObjectDBW(ObjectDBW): class PureRootPathDB(RootPathDB): def __init__(self, root_path): - super(PureRootPathDB, self).__init__(root_path) self._root_path = root_path + super(PureRootPathDB, self).__init__(root_path) + #{ Interface @@ -127,8 +128,8 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB): def _set_cache_(self, attr): if attr == '_dbs': self._dbs = list() - elif attr == '_db_cache': - self._db_cache = dict() + elif attr == '_obj_cache': + self._obj_cache = dict() else: super(PureCompoundDB, self)._set_cache_(attr) @@ -138,14 +139,14 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB): # most databases use binary representations, prevent converting # it everytime a database is being queried try: - return self._db_cache[sha] + return self._obj_cache[sha] except KeyError: pass # END first level cache for db in self._dbs: if db.has_object(sha): - self._db_cache[sha] = db + self._obj_cache[sha] = db return db # END for each database raise BadObject(sha) @@ -181,7 +182,7 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB): def update_cache(self, force=False): # something might have changed, clear everything - self._db_cache.clear() + self._obj_cache.clear() stat = False for db in self._dbs: if isinstance(db, CachingDB): @@ -191,8 +192,6 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB): return stat def partial_to_complete_sha_hex(self, partial_hexsha): - databases = self.databases() - len_partial_hexsha = len(partial_hexsha) if len_partial_hexsha % 2 != 0: partial_binsha = hex_to_bin(partial_hexsha + "0") -- cgit v1.2.3 From 9bf3fdec93fe427bb5f0bd39c986a4e977969f41 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 7 Jun 2011 13:38:48 +0200 Subject: First run in order to fix the remote handling. Cleaned up interfaces and figured out that the implementation really should be specific to the git command. This leaves the interface open for other implemntations which use a different way to provide feedback (as we do not make assumptions about the format of a feedback line) --- git/db/py/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'git/db/py/base.py') diff --git a/git/db/py/base.py b/git/db/py/base.py index a2c9a4ef..2fdbd202 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -18,7 +18,7 @@ from git.util import ( expandvars, expanduser, exists, - is_git_dir + is_git_dir, ) from git.index import IndexFile @@ -40,7 +40,7 @@ import os __all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB', 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin', 'PureIndexDB') - + class PureObjectDBR(ObjectDBR): @@ -471,3 +471,4 @@ class PureAlternatesFileMixin(object): alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") #} END interface + -- cgit v1.2.3