diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lib/__init__.py | 7 | ||||
-rw-r--r-- | test/lib/helper.py | 146 | ||||
-rw-r--r-- | test/performance/lib.py | 43 | ||||
-rw-r--r-- | test/performance/test_commit.py | 52 | ||||
-rw-r--r-- | test/performance/test_odb.py | 39 | ||||
-rw-r--r-- | test/performance/test_streams.py | 87 | ||||
-rw-r--r-- | test/test_actor.py | 1 | ||||
-rw-r--r-- | test/test_base.py | 55 | ||||
-rw-r--r-- | test/test_blob.py | 9 | ||||
-rw-r--r-- | test/test_clone.py | 17 | ||||
-rw-r--r-- | test/test_commit.py | 252 | ||||
-rw-r--r-- | test/test_config.py | 289 | ||||
-rw-r--r-- | test/test_db.py | 3 | ||||
-rw-r--r-- | test/test_diff.py | 236 | ||||
-rw-r--r-- | test/test_docs.py | 433 | ||||
-rw-r--r-- | test/test_exc.py | 83 | ||||
-rw-r--r-- | test/test_fun.py | 103 | ||||
-rw-r--r-- | test/test_git.py | 173 | ||||
-rw-r--r-- | test/test_index.py | 311 | ||||
-rw-r--r-- | test/test_installation.py | 61 | ||||
-rw-r--r-- | test/test_reflog.py | 37 | ||||
-rw-r--r-- | test/test_refs.py | 137 | ||||
-rw-r--r-- | test/test_remote.py | 218 | ||||
-rw-r--r-- | test/test_repo.py | 477 | ||||
-rw-r--r-- | test/test_stats.py | 24 | ||||
-rw-r--r-- | test/test_submodule.py | 567 | ||||
-rw-r--r-- | test/test_tree.py | 38 | ||||
-rw-r--r-- | test/test_util.py | 172 | ||||
-rw-r--r-- | test/tstrunner.py | 3 |
29 files changed, 2470 insertions, 1603 deletions
diff --git a/test/lib/__init__.py b/test/lib/__init__.py index 1551ce45..ae4c2b67 100644 --- a/test/lib/__init__.py +++ b/test/lib/__init__.py @@ -8,5 +8,8 @@ import inspect from .helper import * -__all__ = [name for name, obj in locals().items() - if not (name.startswith('_') or inspect.ismodule(obj))] +__all__ = [ + name + for name, obj in locals().items() + if not (name.startswith("_") or inspect.ismodule(obj)) +] diff --git a/test/lib/helper.py b/test/lib/helper.py index 632d6af9..8f4046da 100644 --- a/test/lib/helper.py +++ b/test/lib/helper.py @@ -31,29 +31,37 @@ GIT_REPO = os.environ.get("GIT_PYTHON_TEST_GIT_REPO_BASE", ospd(ospd(ospd(__file GIT_DAEMON_PORT = os.environ.get("GIT_PYTHON_TEST_GIT_DAEMON_PORT", "19418") __all__ = ( - 'fixture_path', 'fixture', 'StringProcessAdapter', - 'with_rw_directory', 'with_rw_repo', 'with_rw_and_rw_remote_repo', - 'TestBase', 'TestCase', - 'SkipTest', 'skipIf', - 'GIT_REPO', 'GIT_DAEMON_PORT' + "fixture_path", + "fixture", + "StringProcessAdapter", + "with_rw_directory", + "with_rw_repo", + "with_rw_and_rw_remote_repo", + "TestBase", + "TestCase", + "SkipTest", + "skipIf", + "GIT_REPO", + "GIT_DAEMON_PORT", ) log = logging.getLogger(__name__) -#{ Routines +# { Routines def fixture_path(name): - return osp.join(ospd(ospd(__file__)), 'fixtures', name) + return osp.join(ospd(ospd(__file__)), "fixtures", name) def fixture(name): - with open(fixture_path(name), 'rb') as fd: + with open(fixture_path(name), "rb") as fd: return fd.read() -#} END routines -#{ Adapters +# } END routines + +# { Adapters class StringProcessAdapter(object): @@ -70,9 +78,10 @@ class StringProcessAdapter(object): poll = wait -#} END adapters -#{ Decorators +# } END adapters + +# { Decorators def with_rw_directory(func): @@ -88,8 +97,12 @@ def with_rw_directory(func): try: return func(self, path) except Exception: - log.info("Test %s.%s failed, output is at %r\n", - type(self).__name__, func.__name__, path) + log.info( + "Test %s.%s failed, output is at %r\n", + type(self).__name__, + func.__name__, + path, + ) keep = True raise finally: @@ -114,14 +127,16 @@ def with_rw_repo(working_tree_ref, bare=False): To make working with relative paths easier, the cwd will be set to the working dir of the repository. """ - assert isinstance(working_tree_ref, str), "Decorator requires ref name for working tree checkout" + assert isinstance( + working_tree_ref, str + ), "Decorator requires ref name for working tree checkout" def argument_passer(func): @wraps(func) def repo_creator(self): - prefix = 'non_' + prefix = "non_" if bare: - prefix = '' + prefix = "" # END handle prefix repo_dir = tempfile.mktemp(prefix="%sbare_%s" % (prefix, func.__name__)) rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=bare, n=True) @@ -151,8 +166,10 @@ def with_rw_repo(working_tree_ref, bare=False): rmtree(repo_dir) # END rm test repo if possible # END cleanup + # END rw repo creator return repo_creator + # END argument passer return argument_passer @@ -170,24 +187,29 @@ def git_daemon_launched(base_path, ip, port): # So, invoke it as a single command. ## Cygwin-git has no daemon. But it can use MINGW's. # - daemon_cmd = ['git-daemon', - '--enable=receive-pack', - '--listen=%s' % ip, - '--port=%s' % port, - '--base-path=%s' % base_path, - base_path] + daemon_cmd = [ + "git-daemon", + "--enable=receive-pack", + "--listen=%s" % ip, + "--port=%s" % port, + "--base-path=%s" % base_path, + base_path, + ] gd = Git().execute(daemon_cmd, as_process=True) else: - gd = Git().daemon(base_path, - enable='receive-pack', - listen=ip, - port=port, - base_path=base_path, - as_process=True) + gd = Git().daemon( + base_path, + enable="receive-pack", + listen=ip, + port=port, + base_path=base_path, + as_process=True, + ) # yes, I know ... fortunately, this is always going to work if sleep time is just large enough time.sleep(0.5 * (1 + is_win)) except Exception as ex: - msg = textwrap.dedent(""" + msg = textwrap.dedent( + """ Launching git-daemon failed due to: %s Probably test will fail subsequently. @@ -195,14 +217,17 @@ def git_daemon_launched(base_path, ip, port): git daemon --enable=receive-pack --listen=%s --port=%s --base-path=%s %s You may also run the daemon on a different port by passing --port=<port>" and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port> - """) + """ + ) if is_win: - msg += textwrap.dedent(r""" + msg += textwrap.dedent( + r""" On Windows, the `git-daemon.exe` must be in PATH. For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear. - CYGWIN has no daemon, but if one exists, it gets along fine (but has also paths problems).""") + CYGWIN has no daemon, but if one exists, it gets along fine (but has also paths problems).""" + ) log.warning(msg, ex, ip, port, base_path, base_path, exc_info=1) yield # OK, assume daemon started manually. @@ -245,16 +270,23 @@ def with_rw_and_rw_remote_repo(working_tree_ref): """ from git import Git, Remote # To avoid circular deps. - assert isinstance(working_tree_ref, str), "Decorator requires ref name for working tree checkout" + assert isinstance( + working_tree_ref, str + ), "Decorator requires ref name for working tree checkout" def argument_passer(func): - @wraps(func) def remote_repo_creator(self): - rw_daemon_repo_dir = tempfile.mktemp(prefix="daemon_repo-%s-" % func.__name__) - rw_repo_dir = tempfile.mktemp(prefix="daemon_cloned_repo-%s-" % func.__name__) - - rw_daemon_repo = self.rorepo.clone(rw_daemon_repo_dir, shared=True, bare=True) + rw_daemon_repo_dir = tempfile.mktemp( + prefix="daemon_repo-%s-" % func.__name__ + ) + rw_repo_dir = tempfile.mktemp( + prefix="daemon_cloned_repo-%s-" % func.__name__ + ) + + rw_daemon_repo = self.rorepo.clone( + rw_daemon_repo_dir, shared=True, bare=True + ) # recursive alternates info ? rw_repo = rw_daemon_repo.clone(rw_repo_dir, shared=True, bare=False, n=True) try: @@ -280,13 +312,19 @@ def with_rw_and_rw_remote_repo(working_tree_ref): base_daemon_path, rel_repo_dir = osp.split(rw_daemon_repo_dir) - remote_repo_url = Git.polish_url("git://localhost:%s/%s" % (GIT_DAEMON_PORT, rel_repo_dir)) + remote_repo_url = Git.polish_url( + "git://localhost:%s/%s" % (GIT_DAEMON_PORT, rel_repo_dir) + ) with d_remote.config_writer as cw: - cw.set('url', remote_repo_url) - - with git_daemon_launched(Git.polish_url(base_daemon_path, is_cygwin=False), # No daemon in Cygwin. - '127.0.0.1', - GIT_DAEMON_PORT): + cw.set("url", remote_repo_url) + + with git_daemon_launched( + Git.polish_url( + base_daemon_path, is_cygwin=False + ), # No daemon in Cygwin. + "127.0.0.1", + GIT_DAEMON_PORT, + ): # Try listing remotes, to diagnose whether the daemon is up. rw_repo.git.ls_remote(d_remote) @@ -294,8 +332,11 @@ def with_rw_and_rw_remote_repo(working_tree_ref): try: return func(self, rw_repo, rw_daemon_repo) except: # noqa E722 - log.info("Keeping repos after failure: \n rw_repo_dir: %s \n rw_daemon_repo_dir: %s", - rw_repo_dir, rw_daemon_repo_dir) + log.info( + "Keeping repos after failure: \n rw_repo_dir: %s \n rw_daemon_repo_dir: %s", + rw_repo_dir, + rw_daemon_repo_dir, + ) rw_repo_dir = rw_daemon_repo_dir = None raise @@ -312,14 +353,17 @@ def with_rw_and_rw_remote_repo(working_tree_ref): if rw_daemon_repo_dir: rmtree(rw_daemon_repo_dir) # END cleanup + # END bare repo creator return remote_repo_creator # END remote repo creator + # END argument parser return argument_passer -#} END decorators + +# } END decorators class TestBase(TestCase): @@ -344,7 +388,10 @@ class TestBase(TestCase): def _small_repo_url(self): """:return" a path to a small, clonable repository""" from git.cmd import Git - return Git.polish_url(osp.join(self.rorepo.working_tree_dir, 'git/ext/gitdb/gitdb/ext/smmap')) + + return Git.polish_url( + osp.join(self.rorepo.working_tree_dir, "git/ext/gitdb/gitdb/ext/smmap") + ) @classmethod def setUpClass(cls): @@ -353,6 +400,7 @@ class TestBase(TestCase): each test type has its own repository """ from git import Repo + gc.collect() cls.rorepo = Repo(GIT_REPO) diff --git a/test/performance/lib.py b/test/performance/lib.py index 86f87757..101e2cd4 100644 --- a/test/performance/lib.py +++ b/test/performance/lib.py @@ -3,27 +3,21 @@ import logging import os import tempfile -from git import ( - Repo -) -from git.db import ( - GitCmdObjectDB, - GitDB -) -from test.lib import ( - TestBase -) +from git import Repo +from git.db import GitCmdObjectDB, GitDB +from test.lib import TestBase from git.util import rmtree import os.path as osp -#{ Invariants +# { Invariants k_env_git_repo = "GIT_PYTHON_TEST_GIT_REPO_BASE" -#} END invariants +# } END invariants -#{ Base Classes +# { Base Classes + class TestBigRepoR(TestBase): @@ -39,8 +33,8 @@ class TestBigRepoR(TestBase): * As gitrepo, but uses pure python implementation """ - #{ Invariants - #} END invariants + # { Invariants + # } END invariants def setUp(self): try: @@ -51,11 +45,17 @@ class TestBigRepoR(TestBase): repo_path = os.environ.get(k_env_git_repo) if repo_path is None: logging.info( - ("You can set the %s environment variable to a .git repository of" % k_env_git_repo) + - "your choice - defaulting to the gitpython repository") + ( + "You can set the %s environment variable to a .git repository of" + % k_env_git_repo + ) + + "your choice - defaulting to the gitpython repository" + ) repo_path = osp.dirname(__file__) # end set some repo path - self.gitrorepo = Repo(repo_path, odbt=GitCmdObjectDB, search_parent_directories=True) + self.gitrorepo = Repo( + repo_path, odbt=GitCmdObjectDB, search_parent_directories=True + ) self.puregitrorepo = Repo(repo_path, odbt=GitDB, search_parent_directories=True) def tearDown(self): @@ -79,7 +79,9 @@ class TestBigRepoRW(TestBigRepoR): pass dirname = tempfile.mktemp() os.mkdir(dirname) - self.gitrwrepo = self.gitrorepo.clone(dirname, shared=True, bare=True, odbt=GitCmdObjectDB) + self.gitrwrepo = self.gitrorepo.clone( + dirname, shared=True, bare=True, odbt=GitCmdObjectDB + ) self.puregitrwrepo = Repo(dirname, odbt=GitDB) def tearDown(self): @@ -91,4 +93,5 @@ class TestBigRepoRW(TestBigRepoR): self.puregitrwrepo.git.clear_cache() self.puregitrwrepo = None -#} END base classes + +# } END base classes diff --git a/test/performance/test_commit.py b/test/performance/test_commit.py index 8158a1e6..25cc34b8 100644 --- a/test/performance/test_commit.py +++ b/test/performance/test_commit.py @@ -14,13 +14,13 @@ from test.test_commit import TestCommitSerialization class TestPerformance(TestBigRepoRW, TestCommitSerialization): - def tearDown(self): import gc + gc.collect() # ref with about 100 commits in its history - ref_100 = '0.1.6' + ref_100 = "0.1.6" def _query_commit_info(self, c): c.author @@ -50,8 +50,11 @@ class TestPerformance(TestBigRepoRW, TestCommitSerialization): # END for each object # END for each commit elapsed_time = time() - st - print("Traversed %i Trees and a total of %i uncached objects in %s [s] ( %f objs/s )" - % (nc, no, elapsed_time, no / elapsed_time), file=sys.stderr) + print( + "Traversed %i Trees and a total of %i uncached objects in %s [s] ( %f objs/s )" + % (nc, no, elapsed_time, no / elapsed_time), + file=sys.stderr, + ) def test_commit_traversal(self): # bound to cat-file parsing performance @@ -62,8 +65,11 @@ class TestPerformance(TestBigRepoRW, TestCommitSerialization): self._query_commit_info(c) # END for each traversed commit elapsed_time = time() - st - print("Traversed %i Commits in %s [s] ( %f commits/s )" - % (nc, elapsed_time, nc / elapsed_time), file=sys.stderr) + print( + "Traversed %i Commits in %s [s] ( %f commits/s )" + % (nc, elapsed_time, nc / elapsed_time), + file=sys.stderr, + ) def test_commit_iteration(self): # bound to stream parsing performance @@ -74,11 +80,14 @@ class TestPerformance(TestBigRepoRW, TestCommitSerialization): self._query_commit_info(c) # END for each traversed commit elapsed_time = time() - st - print("Iterated %i Commits in %s [s] ( %f commits/s )" - % (nc, elapsed_time, nc / elapsed_time), file=sys.stderr) + print( + "Iterated %i Commits in %s [s] ( %f commits/s )" + % (nc, elapsed_time, nc / elapsed_time), + file=sys.stderr, + ) def test_commit_serialization(self): - self.assert_commit_serialization(self.gitrwrepo, '58c78e6', True) + self.assert_commit_serialization(self.gitrwrepo, "58c78e6", True) rwrepo = self.gitrwrepo make_object = rwrepo.odb.store @@ -89,10 +98,20 @@ class TestPerformance(TestBigRepoRW, TestCommitSerialization): nc = 5000 st = time() for i in range(nc): - cm = Commit(rwrepo, Commit.NULL_BIN_SHA, hc.tree, - hc.author, hc.authored_date, hc.author_tz_offset, - hc.committer, hc.committed_date, hc.committer_tz_offset, - str(i), parents=hc.parents, encoding=hc.encoding) + cm = Commit( + rwrepo, + Commit.NULL_BIN_SHA, + hc.tree, + hc.author, + hc.authored_date, + hc.author_tz_offset, + hc.committer, + hc.committed_date, + hc.committer_tz_offset, + str(i), + parents=hc.parents, + encoding=hc.encoding, + ) stream = BytesIO() cm._serialize(stream) @@ -103,5 +122,8 @@ class TestPerformance(TestBigRepoRW, TestCommitSerialization): # END commit creation elapsed = time() - st - print("Serialized %i commits to loose objects in %f s ( %f commits / s )" - % (nc, elapsed, nc / elapsed), file=sys.stderr) + print( + "Serialized %i commits to loose objects in %f s ( %f commits / s )" + % (nc, elapsed, nc / elapsed), + file=sys.stderr, + ) diff --git a/test/performance/test_odb.py b/test/performance/test_odb.py index c9521c56..680464c9 100644 --- a/test/performance/test_odb.py +++ b/test/performance/test_odb.py @@ -2,13 +2,10 @@ import sys from time import time -from .lib import ( - TestBigRepoR -) +from .lib import TestBigRepoR class TestObjDBPerformance(TestBigRepoR): - def test_random_access(self): results = [["Iterate Commits"], ["Iterate Blobs"], ["Retrieve Blob Data"]] for repo in (self.gitrorepo, self.puregitrorepo): @@ -19,8 +16,11 @@ class TestObjDBPerformance(TestBigRepoR): nc = len(commits) elapsed = time() - st - print("%s: Retrieved %i commits from ObjectStore in %g s ( %f commits / s )" - % (type(repo.odb), nc, elapsed, nc / elapsed), file=sys.stderr) + print( + "%s: Retrieved %i commits from ObjectStore in %g s ( %f commits / s )" + % (type(repo.odb), nc, elapsed, nc / elapsed), + file=sys.stderr, + ) results[0].append(elapsed) # GET TREES @@ -33,7 +33,7 @@ class TestObjDBPerformance(TestBigRepoR): blobs = [] for item in tree.traverse(): nt += 1 - if item.type == 'blob': + if item.type == "blob": blobs.append(item) # direct access for speed # END while trees are there for walking @@ -41,8 +41,11 @@ class TestObjDBPerformance(TestBigRepoR): # END for each commit elapsed = time() - st - print("%s: Retrieved %i objects from %i commits in %g s ( %f objects / s )" - % (type(repo.odb), nt, len(commits), elapsed, nt / elapsed), file=sys.stderr) + print( + "%s: Retrieved %i objects from %i commits in %g s ( %f objects / s )" + % (type(repo.odb), nt, len(commits), elapsed, nt / elapsed), + file=sys.stderr, + ) results[1].append(elapsed) # GET BLOBS @@ -60,13 +63,25 @@ class TestObjDBPerformance(TestBigRepoR): # END for each bloblist elapsed = time() - st - msg = "%s: Retrieved %i blob (%i KiB) and their data in %g s ( %f blobs / s, %f KiB / s )"\ - % (type(repo.odb), nb, data_bytes / 1000, elapsed, nb / elapsed, (data_bytes / 1000) / elapsed) + msg = ( + "%s: Retrieved %i blob (%i KiB) and their data in %g s ( %f blobs / s, %f KiB / s )" + % ( + type(repo.odb), + nb, + data_bytes / 1000, + elapsed, + nb / elapsed, + (data_bytes / 1000) / elapsed, + ) + ) print(msg, file=sys.stderr) results[2].append(elapsed) # END for each repo type # final results for test_name, a, b in results: - print("%s: %f s vs %f s, pure is %f times slower" % (test_name, a, b, b / a), file=sys.stderr) + print( + "%s: %f s vs %f s, pure is %f times slower" % (test_name, a, b, b / a), + file=sys.stderr, + ) # END for each result diff --git a/test/performance/test_streams.py b/test/performance/test_streams.py index 28e6b13e..2ae94e29 100644 --- a/test/performance/test_streams.py +++ b/test/performance/test_streams.py @@ -4,36 +4,29 @@ import subprocess import sys from time import time -from test.lib import ( - with_rw_repo -) +from test.lib import with_rw_repo from git.util import bin_to_hex -from gitdb import ( - LooseObjectDB, - IStream -) +from gitdb import LooseObjectDB, IStream from gitdb.test.lib import make_memory_file import os.path as osp -from .lib import ( - TestBigRepoR -) +from .lib import TestBigRepoR class TestObjDBPerformance(TestBigRepoR): - large_data_size_bytes = 1000 * 1000 * 10 # some MiB should do it - moderate_data_size_bytes = 1000 * 1000 * 1 # just 1 MiB + large_data_size_bytes = 1000 * 1000 * 10 # some MiB should do it + moderate_data_size_bytes = 1000 * 1000 * 1 # just 1 MiB - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_large_data_streaming(self, rwrepo): # TODO: This part overlaps with the same file in gitdb.test.performance.test_stream # It should be shared if possible - ldb = LooseObjectDB(osp.join(rwrepo.git_dir, 'objects')) + ldb = LooseObjectDB(osp.join(rwrepo.git_dir, "objects")) for randomize in range(2): - desc = (randomize and 'random ') or '' + desc = (randomize and "random ") or "" print("Creating %s data ..." % desc, file=sys.stderr) st = time() size, stream = make_memory_file(self.large_data_size_bytes, randomize) @@ -42,7 +35,7 @@ class TestObjDBPerformance(TestBigRepoR): # writing - due to the compression it will seem faster than it is st = time() - binsha = ldb.store(IStream('blob', size, stream)).binsha + binsha = ldb.store(IStream("blob", size, stream)).binsha elapsed_add = time() - st assert ldb.has_object(binsha) db_file = ldb.readable_db_object_path(bin_to_hex(binsha)) @@ -79,33 +72,45 @@ class TestObjDBPerformance(TestBigRepoR): elapsed_readchunks = time() - st stream.seek(0) - assert b''.join(chunks) == stream.getvalue() + assert b"".join(chunks) == stream.getvalue() cs_kib = cs / 1000 - print("Read %i KiB of %s data in %i KiB chunks from loose odb in %f s ( %f Read KiB / s)" - % (size_kib, desc, cs_kib, elapsed_readchunks, size_kib / elapsed_readchunks), file=sys.stderr) + print( + "Read %i KiB of %s data in %i KiB chunks from loose odb in %f s ( %f Read KiB / s)" + % ( + size_kib, + desc, + cs_kib, + elapsed_readchunks, + size_kib / elapsed_readchunks, + ), + file=sys.stderr, + ) # del db file so git has something to do ostream = None import gc + gc.collect() os.remove(db_file) # VS. CGIT ########## # CGIT ! Can using the cgit programs be faster ? - proc = rwrepo.git.hash_object('-w', '--stdin', as_process=True, istream=subprocess.PIPE) + proc = rwrepo.git.hash_object( + "-w", "--stdin", as_process=True, istream=subprocess.PIPE + ) # write file - pump everything in at once to be a fast as possible - data = stream.getvalue() # cache it + data = stream.getvalue() # cache it st = time() proc.stdin.write(data) proc.stdin.close() gitsha = proc.stdout.read().strip() proc.wait() gelapsed_add = time() - st - del(data) - assert gitsha == bin_to_hex(binsha) # we do it the same way, right ? + del data + assert gitsha == bin_to_hex(binsha) # we do it the same way, right ? # as its the same sha, we reuse our path fsize_kib = osp.getsize(db_file) / 1000 @@ -114,19 +119,28 @@ class TestObjDBPerformance(TestBigRepoR): print(msg, file=sys.stderr) # compare ... - print("Git-Python is %f %% faster than git when adding big %s files" - % (100.0 - (elapsed_add / gelapsed_add) * 100, desc), file=sys.stderr) + print( + "Git-Python is %f %% faster than git when adding big %s files" + % (100.0 - (elapsed_add / gelapsed_add) * 100, desc), + file=sys.stderr, + ) # read all st = time() _hexsha, _typename, size, data = rwrepo.git.get_object_data(gitsha) gelapsed_readall = time() - st - print("Read %i KiB of %s data at once using git-cat-file in %f s ( %f Read KiB / s)" - % (size_kib, desc, gelapsed_readall, size_kib / gelapsed_readall), file=sys.stderr) + print( + "Read %i KiB of %s data at once using git-cat-file in %f s ( %f Read KiB / s)" + % (size_kib, desc, gelapsed_readall, size_kib / gelapsed_readall), + file=sys.stderr, + ) # compare - print("Git-Python is %f %% faster than git when reading big %sfiles" - % (100.0 - (elapsed_readall / gelapsed_readall) * 100, desc), file=sys.stderr) + print( + "Git-Python is %f %% faster than git when reading big %sfiles" + % (100.0 - (elapsed_readall / gelapsed_readall) * 100, desc), + file=sys.stderr, + ) # read chunks st = time() @@ -138,10 +152,19 @@ class TestObjDBPerformance(TestBigRepoR): # END read stream gelapsed_readchunks = time() - st msg = "Read %i KiB of %s data in %i KiB chunks from git-cat-file in %f s ( %f Read KiB / s)" - msg %= (size_kib, desc, cs_kib, gelapsed_readchunks, size_kib / gelapsed_readchunks) + msg %= ( + size_kib, + desc, + cs_kib, + gelapsed_readchunks, + size_kib / gelapsed_readchunks, + ) print(msg, file=sys.stderr) # compare - print("Git-Python is %f %% faster than git when reading big %s files in chunks" - % (100.0 - (elapsed_readchunks / gelapsed_readchunks) * 100, desc), file=sys.stderr) + print( + "Git-Python is %f %% faster than git when reading big %s files in chunks" + % (100.0 - (elapsed_readchunks / gelapsed_readchunks) * 100, desc), + file=sys.stderr, + ) # END for each randomization factor diff --git a/test/test_actor.py b/test/test_actor.py index 32d16ea7..ce0c74fc 100644 --- a/test/test_actor.py +++ b/test/test_actor.py @@ -9,7 +9,6 @@ from git import Actor class TestActor(TestBase): - def test_from_string_should_separate_name_and_email(self): a = Actor._from_string("Michael Trier <mtrier@example.com>") self.assertEqual("Michael Trier", a.name) diff --git a/test/test_base.py b/test/test_base.py index 68ce6816..a7c034e2 100644 --- a/test/test_base.py +++ b/test/test_base.py @@ -9,19 +9,10 @@ import sys import tempfile from unittest import SkipTest, skipIf -from git.objects import ( - Blob, - Tree, - Commit, - TagObject -) +from git.objects import Blob, Tree, Commit, TagObject from git.compat import is_win from git.objects.util import get_object_type_by_name -from test.lib import ( - TestBase as _TestBase, - with_rw_repo, - with_rw_and_rw_remote_repo -) +from test.lib import TestBase as _TestBase, with_rw_repo, with_rw_and_rw_remote_repo from git.util import hex_to_bin, HIDE_WINDOWS_FREEZE_ERRORS import git.objects.base as base @@ -29,15 +20,17 @@ import os.path as osp class TestBase(_TestBase): - def tearDown(self): import gc + gc.collect() - type_tuples = (("blob", "8741fc1d09d61f02ffd8cded15ff603eff1ec070", "blob.py"), - ("tree", "3a6a5e3eeed3723c09f1ef0399f81ed6b8d82e79", "directory"), - ("commit", "4251bd59fb8e11e40c40548cba38180a9536118c", None), - ("tag", "e56a60e8e9cd333cfba0140a77cd12b0d9398f10", None)) + type_tuples = ( + ("blob", "8741fc1d09d61f02ffd8cded15ff603eff1ec070", "blob.py"), + ("tree", "3a6a5e3eeed3723c09f1ef0399f81ed6b8d82e79", "directory"), + ("commit", "4251bd59fb8e11e40c40548cba38180a9536118c", None), + ("tag", "e56a60e8e9cd333cfba0140a77cd12b0d9398f10", None), + ) def test_base_object(self): # test interface of base object classes @@ -67,8 +60,8 @@ class TestBase(_TestBase): if isinstance(item, base.IndexObject): num_index_objs += 1 - if hasattr(item, 'path'): # never runs here - assert not item.path.startswith("/") # must be relative + if hasattr(item, "path"): # never runs here + assert not item.path.startswith("/") # must be relative assert isinstance(item.mode, int) # END index object check @@ -77,8 +70,8 @@ class TestBase(_TestBase): data = data_stream.read() assert data - tmpfilename = tempfile.mktemp(suffix='test-stream') - with open(tmpfilename, 'wb+') as tmpfile: + tmpfilename = tempfile.mktemp(suffix="test-stream") + with open(tmpfilename, "wb+") as tmpfile: self.assertEqual(item, item.stream_data(tmpfile)) tmpfile.seek(0) self.assertEqual(tmpfile.read(), data) @@ -99,26 +92,28 @@ class TestBase(_TestBase): def test_object_resolution(self): # objects must be resolved to shas so they compare equal - self.assertEqual(self.rorepo.head.reference.object, self.rorepo.active_branch.object) + self.assertEqual( + self.rorepo.head.reference.object, self.rorepo.active_branch.object + ) - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_with_bare_rw_repo(self, bare_rw_repo): assert bare_rw_repo.config_reader("repository").getboolean("core", "bare") - assert osp.isfile(osp.join(bare_rw_repo.git_dir, 'HEAD')) + assert osp.isfile(osp.join(bare_rw_repo.git_dir, "HEAD")) - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_with_rw_repo(self, rw_repo): assert not rw_repo.config_reader("repository").getboolean("core", "bare") - assert osp.isdir(osp.join(rw_repo.working_tree_dir, 'lib')) + assert osp.isdir(osp.join(rw_repo.working_tree_dir, "lib")) @skipIf(HIDE_WINDOWS_FREEZE_ERRORS, "FIXME: Freezes! sometimes...") - @with_rw_and_rw_remote_repo('0.1.6') + @with_rw_and_rw_remote_repo("0.1.6") def test_with_rw_remote_and_rw_repo(self, rw_repo, rw_remote_repo): assert not rw_repo.config_reader("repository").getboolean("core", "bare") assert rw_remote_repo.config_reader("repository").getboolean("core", "bare") - assert osp.isdir(osp.join(rw_repo.working_tree_dir, 'lib')) + assert osp.isdir(osp.join(rw_repo.working_tree_dir, "lib")) - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_add_unicode(self, rw_repo): filename = "שלום.txt" @@ -131,7 +126,7 @@ class TestBase(_TestBase): raise SkipTest("Environment doesn't support unicode filenames") from e with open(file_path, "wb") as fp: - fp.write(b'something') + fp.write(b"something") if is_win: # on windows, there is no way this works, see images on @@ -144,4 +139,4 @@ class TestBase(_TestBase): # on posix, we can just add unicode files without problems rw_repo.git.add(rw_repo.working_dir) # end - rw_repo.index.commit('message') + rw_repo.index.commit("message") diff --git a/test/test_blob.py b/test/test_blob.py index c9c8c48a..ad5b46c1 100644 --- a/test/test_blob.py +++ b/test/test_blob.py @@ -9,14 +9,15 @@ from git import Blob class TestBlob(TestBase): - def test_mime_type_should_return_mime_type_for_known_types(self): - blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA, 'path': 'foo.png'}) + blob = Blob(self.rorepo, **{"binsha": Blob.NULL_BIN_SHA, "path": "foo.png"}) self.assertEqual("image/png", blob.mime_type) def test_mime_type_should_return_text_plain_for_unknown_types(self): - blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA, 'path': 'something'}) + blob = Blob(self.rorepo, **{"binsha": Blob.NULL_BIN_SHA, "path": "something"}) self.assertEqual("text/plain", blob.mime_type) def test_nodict(self): - self.assertRaises(AttributeError, setattr, self.rorepo.tree()['AUTHORS'], 'someattr', 2) + self.assertRaises( + AttributeError, setattr, self.rorepo.tree()["AUTHORS"], "someattr", 2 + ) diff --git a/test/test_clone.py b/test/test_clone.py index e9f6714d..6bd944f9 100644 --- a/test/test_clone.py +++ b/test/test_clone.py @@ -17,16 +17,23 @@ class TestClone(TestBase): @with_rw_directory def test_checkout_in_non_empty_dir(self, rw_dir): non_empty_dir = Path(rw_dir) - garbage_file = non_empty_dir / 'not-empty' - garbage_file.write_text('Garbage!') + garbage_file = non_empty_dir / "not-empty" + garbage_file.write_text("Garbage!") # Verify that cloning into the non-empty dir fails while complaining about # the target directory not being empty/non-existent try: self.rorepo.clone(non_empty_dir) except git.GitCommandError as exc: - self.assertTrue(exc.stderr, "GitCommandError's 'stderr' is unexpectedly empty") - expr = re.compile(r'(?is).*\bfatal:\s+destination\s+path\b.*\bexists\b.*\bnot\b.*\bempty\s+directory\b') - self.assertTrue(expr.search(exc.stderr), '"%s" does not match "%s"' % (expr.pattern, exc.stderr)) + self.assertTrue( + exc.stderr, "GitCommandError's 'stderr' is unexpectedly empty" + ) + expr = re.compile( + r"(?is).*\bfatal:\s+destination\s+path\b.*\bexists\b.*\bnot\b.*\bempty\s+directory\b" + ) + self.assertTrue( + expr.search(exc.stderr), + '"%s" does not match "%s"' % (expr.pattern, exc.stderr), + ) else: self.fail("GitCommandError not raised") diff --git a/test/test_commit.py b/test/test_commit.py index 40cf7dd2..17a4fe4f 100644 --- a/test/test_commit.py +++ b/test/test_commit.py @@ -19,12 +19,7 @@ from git import ( from git import Repo from git.objects.util import tzoffset, utc from git.repo.fun import touch -from test.lib import ( - TestBase, - with_rw_repo, - fixture_path, - StringProcessAdapter -) +from test.lib import TestBase, with_rw_repo, fixture_path, StringProcessAdapter from test.lib import with_rw_directory from gitdb import IStream @@ -32,13 +27,14 @@ import os.path as osp class TestCommitSerialization(TestBase): - - def assert_commit_serialization(self, rwrepo, commit_id, print_performance_info=False): + def assert_commit_serialization( + self, rwrepo, commit_id, print_performance_info=False + ): """traverse all commits in the history of commit identified by commit_id and check if the serialization works. :param print_performance_info: if True, we will show how fast we are""" - ns = 0 # num serializations - nds = 0 # num deserializations + ns = 0 # num serializations + nds = 0 # num deserializations st = time.time() for cm in rwrepo.commit(commit_id).traverse(): @@ -53,12 +49,22 @@ class TestCommitSerialization(TestBase): stream.seek(0) istream = rwrepo.odb.store(IStream(Commit.type, streamlen, stream)) - self.assertEqual(istream.hexsha, cm.hexsha.encode('ascii')) - - nc = Commit(rwrepo, Commit.NULL_BIN_SHA, cm.tree, - cm.author, cm.authored_date, cm.author_tz_offset, - cm.committer, cm.committed_date, cm.committer_tz_offset, - cm.message, cm.parents, cm.encoding) + self.assertEqual(istream.hexsha, cm.hexsha.encode("ascii")) + + nc = Commit( + rwrepo, + Commit.NULL_BIN_SHA, + cm.tree, + cm.author, + cm.authored_date, + cm.author_tz_offset, + cm.committer, + cm.committed_date, + cm.committer_tz_offset, + cm.message, + cm.parents, + cm.encoding, + ) self.assertEqual(nc.parents, cm.parents) stream = BytesIO() @@ -79,55 +85,65 @@ class TestCommitSerialization(TestBase): elapsed = time.time() - st if print_performance_info: - print("Serialized %i and deserialized %i commits in %f s ( (%f, %f) commits / s" - % (ns, nds, elapsed, ns / elapsed, nds / elapsed), file=sys.stderr) + print( + "Serialized %i and deserialized %i commits in %f s ( (%f, %f) commits / s" + % (ns, nds, elapsed, ns / elapsed, nds / elapsed), + file=sys.stderr, + ) # END handle performance info class TestCommit(TestCommitSerialization): - def test_bake(self): - commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae') + commit = self.rorepo.commit("2454ae89983a4496a445ce347d7a41c0bb0ea7ae") # commits have no dict - self.assertRaises(AttributeError, setattr, commit, 'someattr', 1) + self.assertRaises(AttributeError, setattr, commit, "someattr", 1) commit.author # bake self.assertEqual("Sebastian Thiel", commit.author.name) self.assertEqual("byronimo@gmail.com", commit.author.email) self.assertEqual(commit.author, commit.committer) - assert isinstance(commit.authored_date, int) and isinstance(commit.committed_date, int) - assert isinstance(commit.author_tz_offset, int) and isinstance(commit.committer_tz_offset, int) - self.assertEqual(commit.message, "Added missing information to docstrings of commit and stats module\n") + assert isinstance(commit.authored_date, int) and isinstance( + commit.committed_date, int + ) + assert isinstance(commit.author_tz_offset, int) and isinstance( + commit.committer_tz_offset, int + ) + self.assertEqual( + commit.message, + "Added missing information to docstrings of commit and stats module\n", + ) def test_replace_no_changes(self): - old_commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae') + old_commit = self.rorepo.commit("2454ae89983a4496a445ce347d7a41c0bb0ea7ae") new_commit = old_commit.replace() for attr in old_commit.__slots__: assert getattr(new_commit, attr) == getattr(old_commit, attr) def test_replace_new_sha(self): - commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae') - new_commit = commit.replace(message='Added replace method') + commit = self.rorepo.commit("2454ae89983a4496a445ce347d7a41c0bb0ea7ae") + new_commit = commit.replace(message="Added replace method") - assert new_commit.hexsha == 'fc84cbecac1bd4ba4deaac07c1044889edd536e6' - assert new_commit.message == 'Added replace method' + assert new_commit.hexsha == "fc84cbecac1bd4ba4deaac07c1044889edd536e6" + assert new_commit.message == "Added replace method" def test_replace_invalid_attribute(self): - commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae') + commit = self.rorepo.commit("2454ae89983a4496a445ce347d7a41c0bb0ea7ae") with self.assertRaises(ValueError): - commit.replace(badattr='This will never work') + commit.replace(badattr="This will never work") def test_stats(self): - commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781') + commit = self.rorepo.commit("33ebe7acec14b25c5f84f35a664803fcab2f7781") stats = commit.stats def check_entries(d): assert isinstance(d, dict) for key in ("insertions", "deletions", "lines"): assert key in d + # END assertion helper assert stats.files assert stats.total @@ -179,19 +195,24 @@ class TestCommit(TestCommitSerialization): # at some point, both iterations should stop self.assertEqual(list(bfirst)[-1], first) - stoptraverse = self.rorepo.commit("254d04aa3180eb8b8daf7b7ff25f010cd69b4e7d").traverse(ignore_self=0, - as_edge=True) + stoptraverse = self.rorepo.commit( + "254d04aa3180eb8b8daf7b7ff25f010cd69b4e7d" + ).traverse(ignore_self=0, as_edge=True) stoptraverse_list = list(stoptraverse) for itemtup in stoptraverse_list: - self.assertIsInstance(itemtup, (tuple)) and self.assertEqual(len(itemtup), 2) # as_edge=True -> tuple + self.assertIsInstance(itemtup, (tuple)) and self.assertEqual( + len(itemtup), 2 + ) # as_edge=True -> tuple src, item = itemtup self.assertIsInstance(item, Commit) if src: self.assertIsInstance(src, Commit) else: - self.assertIsNone(src) # ignore_self=0 -> first is (None, Commit) + self.assertIsNone(src) # ignore_self=0 -> first is (None, Commit) - stoptraverse = self.rorepo.commit("254d04aa3180eb8b8daf7b7ff25f010cd69b4e7d").traverse(as_edge=True) + stoptraverse = self.rorepo.commit( + "254d04aa3180eb8b8daf7b7ff25f010cd69b4e7d" + ).traverse(as_edge=True) self.assertEqual(len(next(stoptraverse)), 2) # ignore self @@ -201,10 +222,14 @@ class TestCommit(TestCommitSerialization): self.assertEqual(len(list(start.traverse(ignore_self=False, depth=0))), 1) # prune - self.assertEqual(next(start.traverse(branch_first=1, prune=lambda i, d: i == p0)), p1) + self.assertEqual( + next(start.traverse(branch_first=1, prune=lambda i, d: i == p0)), p1 + ) # predicate - self.assertEqual(next(start.traverse(branch_first=1, predicate=lambda i, d: i == p1)), p1) + self.assertEqual( + next(start.traverse(branch_first=1, predicate=lambda i, d: i == p1)), p1 + ) # traversal should stop when the beginning is reached self.assertRaises(StopIteration, next, first.traverse()) @@ -220,64 +245,78 @@ class TestCommit(TestCommitSerialization): self.assertEqual(all_commits, list(self.rorepo.iter_commits())) # this includes merge commits - mcomit = self.rorepo.commit('d884adc80c80300b4cc05321494713904ef1df2d') + mcomit = self.rorepo.commit("d884adc80c80300b4cc05321494713904ef1df2d") assert mcomit in all_commits # we can limit the result to paths - ltd_commits = list(self.rorepo.iter_commits(paths='CHANGES')) + ltd_commits = list(self.rorepo.iter_commits(paths="CHANGES")) assert ltd_commits and len(ltd_commits) < len(all_commits) # show commits of multiple paths, resulting in a union of commits - less_ltd_commits = list(Commit.iter_items(self.rorepo, 'master', paths=('CHANGES', 'AUTHORS'))) + less_ltd_commits = list( + Commit.iter_items(self.rorepo, "master", paths=("CHANGES", "AUTHORS")) + ) assert len(ltd_commits) < len(less_ltd_commits) class Child(Commit): def __init__(self, *args, **kwargs): super(Child, self).__init__(*args, **kwargs) - child_commits = list(Child.iter_items(self.rorepo, 'master', paths=('CHANGES', 'AUTHORS'))) + child_commits = list( + Child.iter_items(self.rorepo, "master", paths=("CHANGES", "AUTHORS")) + ) assert type(child_commits[0]) == Child def test_iter_items(self): # pretty not allowed - self.assertRaises(ValueError, Commit.iter_items, self.rorepo, 'master', pretty="raw") + self.assertRaises( + ValueError, Commit.iter_items, self.rorepo, "master", pretty="raw" + ) def test_rev_list_bisect_all(self): """ 'git rev-list --bisect-all' returns additional information in the commit header. This test ensures that we properly parse it. """ - revs = self.rorepo.git.rev_list('933d23bf95a5bd1624fbcdf328d904e1fa173474', - first_parent=True, - bisect_all=True) + revs = self.rorepo.git.rev_list( + "933d23bf95a5bd1624fbcdf328d904e1fa173474", + first_parent=True, + bisect_all=True, + ) - commits = Commit._iter_from_process_or_stream(self.rorepo, StringProcessAdapter(revs.encode('ascii'))) + commits = Commit._iter_from_process_or_stream( + self.rorepo, StringProcessAdapter(revs.encode("ascii")) + ) expected_ids = ( - '7156cece3c49544abb6bf7a0c218eb36646fad6d', - '1f66cfbbce58b4b552b041707a12d437cc5f400a', - '33ebe7acec14b25c5f84f35a664803fcab2f7781', - '933d23bf95a5bd1624fbcdf328d904e1fa173474' + "7156cece3c49544abb6bf7a0c218eb36646fad6d", + "1f66cfbbce58b4b552b041707a12d437cc5f400a", + "33ebe7acec14b25c5f84f35a664803fcab2f7781", + "933d23bf95a5bd1624fbcdf328d904e1fa173474", ) for sha1, commit in zip(expected_ids, commits): self.assertEqual(sha1, commit.hexsha) @with_rw_directory def test_ambiguous_arg_iteration(self, rw_dir): - rw_repo = Repo.init(osp.join(rw_dir, 'test_ambiguous_arg')) - path = osp.join(str(rw_repo.working_tree_dir), 'master') + rw_repo = Repo.init(osp.join(rw_dir, "test_ambiguous_arg")) + path = osp.join(str(rw_repo.working_tree_dir), "master") touch(path) rw_repo.index.add([path]) - rw_repo.index.commit('initial commit') + rw_repo.index.commit("initial commit") list(rw_repo.iter_commits(rw_repo.head.ref)) # should fail unless bug is fixed def test_count(self): - self.assertEqual(self.rorepo.tag('refs/tags/0.1.5').commit.count(), 143) + self.assertEqual(self.rorepo.tag("refs/tags/0.1.5").commit.count(), 143) def test_list(self): # This doesn't work anymore, as we will either attempt getattr with bytes, or compare 20 byte string # with actual 20 byte bytes. This usage makes no sense anyway - assert isinstance(Commit.list_items(self.rorepo, '0.1.5', max_count=5)[ - '5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) + assert isinstance( + Commit.list_items(self.rorepo, "0.1.5", max_count=5)[ + "5117c9c8a4d3af19a9958677e45cda9269de1541" + ], + Commit, + ) def test_str(self): commit = Commit(self.rorepo, Commit.NULL_BIN_SHA) @@ -296,7 +335,7 @@ class TestCommit(TestCommitSerialization): def test_iter_parents(self): # should return all but ourselves, even if skip is defined - c = self.rorepo.commit('0.1.5') + c = self.rorepo.commit("0.1.5") for skip in (0, 1): piter = c.iter_parents(skip=skip) first_parent = next(piter) @@ -308,18 +347,18 @@ class TestCommit(TestCommitSerialization): name_rev = self.rorepo.head.commit.name_rev assert isinstance(name_rev, str) - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_serialization(self, rwrepo): # create all commits of our repo - self.assert_commit_serialization(rwrepo, '0.1.6') + self.assert_commit_serialization(rwrepo, "0.1.6") def test_serialization_unicode_support(self): - self.assertEqual(Commit.default_encoding.lower(), 'utf-8') + self.assertEqual(Commit.default_encoding.lower(), "utf-8") # create a commit with unicode in the message, and the author's name # Verify its serialization and deserialization - cmt = self.rorepo.commit('0.1.6') - assert isinstance(cmt.message, str) # it automatically decodes it as such + cmt = self.rorepo.commit("0.1.6") + assert isinstance(cmt.message, str) # it automatically decodes it as such assert isinstance(cmt.author.name, str) # same here cmt.message = "üäêèß" @@ -344,15 +383,15 @@ class TestCommit(TestCommitSerialization): def test_invalid_commit(self): cmt = self.rorepo.commit() - with open(fixture_path('commit_invalid_data'), 'rb') as fd: + with open(fixture_path("commit_invalid_data"), "rb") as fd: cmt._deserialize(fd) - self.assertEqual(cmt.author.name, 'E.Azer Ko�o�o�oculu', cmt.author.name) - self.assertEqual(cmt.author.email, 'azer@kodfabrik.com', cmt.author.email) + self.assertEqual(cmt.author.name, "E.Azer Ko�o�o�oculu", cmt.author.name) + self.assertEqual(cmt.author.email, "azer@kodfabrik.com", cmt.author.email) def test_gpgsig(self): cmt = self.rorepo.commit() - with open(fixture_path('commit_with_gpgsig'), 'rb') as fd: + with open(fixture_path("commit_with_gpgsig"), "rb") as fd: cmt._deserialize(fd) fixture_sig = """-----BEGIN PGP SIGNATURE----- @@ -379,7 +418,11 @@ JzJMZDRLQLFvnzqZuCjE cstream = BytesIO() cmt._serialize(cstream) - assert re.search(r"^gpgsig <test\n dummy\n sig>$", cstream.getvalue().decode('ascii'), re.MULTILINE) + assert re.search( + r"^gpgsig <test\n dummy\n sig>$", + cstream.getvalue().decode("ascii"), + re.MULTILINE, + ) self.assert_gpgsig_deserialization(cstream) @@ -391,10 +434,12 @@ JzJMZDRLQLFvnzqZuCjE cmt.gpgsig = None cstream = BytesIO() cmt._serialize(cstream) - assert not re.search(r"^gpgsig ", cstream.getvalue().decode('ascii'), re.MULTILINE) + assert not re.search( + r"^gpgsig ", cstream.getvalue().decode("ascii"), re.MULTILINE + ) def assert_gpgsig_deserialization(self, cstream): - assert 'gpgsig' in 'precondition: need gpgsig' + assert "gpgsig" in "precondition: need gpgsig" class RepoMock: def __init__(self, bytestr): @@ -407,29 +452,40 @@ JzJMZDRLQLFvnzqZuCjE self.bytestr = bytestr def stream(self, *args): - stream = Mock(spec_set=['read'], return_value=self.bytestr) + stream = Mock(spec_set=["read"], return_value=self.bytestr) stream.read.return_value = self.bytestr - return ('binsha', 'typename', 'size', stream) + return ("binsha", "typename", "size", stream) return ODBMock(self.bytestr) repo_mock = RepoMock(cstream.getvalue()) for field in Commit.__slots__: - c = Commit(repo_mock, b'x' * 20) + c = Commit(repo_mock, b"x" * 20) assert getattr(c, field) is not None def test_datetimes(self): - commit = self.rorepo.commit('4251bd5') + commit = self.rorepo.commit("4251bd5") self.assertEqual(commit.authored_date, 1255018625) self.assertEqual(commit.committed_date, 1255026171) - self.assertEqual(commit.authored_datetime, - datetime(2009, 10, 8, 18, 17, 5, tzinfo=tzoffset(-7200)), commit.authored_datetime) # noqa - self.assertEqual(commit.authored_datetime, - datetime(2009, 10, 8, 16, 17, 5, tzinfo=utc), commit.authored_datetime) - self.assertEqual(commit.committed_datetime, - datetime(2009, 10, 8, 20, 22, 51, tzinfo=tzoffset(-7200))) - self.assertEqual(commit.committed_datetime, - datetime(2009, 10, 8, 18, 22, 51, tzinfo=utc), commit.committed_datetime) + self.assertEqual( + commit.authored_datetime, + datetime(2009, 10, 8, 18, 17, 5, tzinfo=tzoffset(-7200)), + commit.authored_datetime, + ) # noqa + self.assertEqual( + commit.authored_datetime, + datetime(2009, 10, 8, 16, 17, 5, tzinfo=utc), + commit.authored_datetime, + ) + self.assertEqual( + commit.committed_datetime, + datetime(2009, 10, 8, 20, 22, 51, tzinfo=tzoffset(-7200)), + ) + self.assertEqual( + commit.committed_datetime, + datetime(2009, 10, 8, 18, 22, 51, tzinfo=utc), + commit.committed_datetime, + ) def test_trailers(self): KEY_1 = "Hello" @@ -440,12 +496,18 @@ JzJMZDRLQLFvnzqZuCjE # Check if KEY 1 & 2 with Value 1 & 2 is extracted from multiple msg variations msgs = [] msgs.append(f"Subject\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") - msgs.append(f"Subject\n \nSome body of a function\n \n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") - msgs.append(f"Subject\n \nSome body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") - msgs.append(f"Subject\n \nSome multiline\n body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2} : {VALUE_2}\n") + msgs.append( + f"Subject\n \nSome body of a function\n \n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n" + ) + msgs.append( + f"Subject\n \nSome body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n" + ) + msgs.append( + f"Subject\n \nSome multiline\n body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2} : {VALUE_2}\n" + ) for msg in msgs: - commit = self.rorepo.commit('master') + commit = self.rorepo.commit("master") commit = copy.copy(commit) commit.message = msg assert KEY_1 in commit.trailers.keys() @@ -457,21 +519,27 @@ JzJMZDRLQLFvnzqZuCjE msgs = [] msgs.append(f"Subject\n") msgs.append(f"Subject\n\nBody with some\nText\n") - msgs.append(f"Subject\n\nBody with\nText\n\nContinuation but\n doesn't contain colon\n") - msgs.append(f"Subject\n\nBody with\nText\n\nContinuation but\n only contains one :\n") + msgs.append( + f"Subject\n\nBody with\nText\n\nContinuation but\n doesn't contain colon\n" + ) + msgs.append( + f"Subject\n\nBody with\nText\n\nContinuation but\n only contains one :\n" + ) msgs.append(f"Subject\n\nBody with\nText\n\nKey: Value\nLine without colon\n") msgs.append(f"Subject\n\nBody with\nText\n\nLine without colon\nKey: Value\n") for msg in msgs: - commit = self.rorepo.commit('master') + commit = self.rorepo.commit("master") commit = copy.copy(commit) commit.message = msg assert len(commit.trailers.keys()) == 0 # check that only the last key value paragraph is evaluated - commit = self.rorepo.commit('master') + commit = self.rorepo.commit("master") commit = copy.copy(commit) - commit.message = f"Subject\n\nMultiline\nBody\n\n{KEY_1}: {VALUE_1}\n\n{KEY_2}: {VALUE_2}\n" + commit.message = ( + f"Subject\n\nMultiline\nBody\n\n{KEY_1}: {VALUE_1}\n\n{KEY_2}: {VALUE_2}\n" + ) assert KEY_1 not in commit.trailers.keys() assert KEY_2 in commit.trailers.keys() assert commit.trailers[KEY_2] == VALUE_2 diff --git a/test/test_config.py b/test/test_config.py index 50d9b010..45677b0d 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -9,9 +9,7 @@ import io import os from unittest import mock -from git import ( - GitConfigParser -) +from git import GitConfigParser from git.config import _OMD, cp from test.lib import ( TestCase, @@ -24,7 +22,7 @@ import os.path as osp from git.util import rmfile -_tc_lock_fpaths = osp.join(osp.dirname(__file__), 'fixtures/*.lock') +_tc_lock_fpaths = osp.join(osp.dirname(__file__), "fixtures/*.lock") def _rm_lock_files(): @@ -39,7 +37,9 @@ class TestBase(TestCase): def tearDown(self): for lfp in glob.glob(_tc_lock_fpaths): if osp.isfile(lfp): - raise AssertionError('Previous TC left hanging git-lock file: {}'.format(lfp)) + raise AssertionError( + "Previous TC left hanging git-lock file: {}".format(lfp) + ) def _to_memcache(self, file_path): with open(file_path, "rb") as fp: @@ -52,13 +52,16 @@ class TestBase(TestCase): for filename in ("git_config", "git_config_global"): file_obj = self._to_memcache(fixture_path(filename)) with GitConfigParser(file_obj, read_only=False) as w_config: - w_config.read() # enforce reading + w_config.read() # enforce reading assert w_config._sections - w_config.write() # enforce writing + w_config.write() # enforce writing # we stripped lines when reading, so the results differ assert file_obj.getvalue() - self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path(filename)).getvalue()) + self.assertEqual( + file_obj.getvalue(), + self._to_memcache(fixture_path(filename)).getvalue(), + ) # creating an additional config writer must fail due to exclusive access with self.assertRaises(IOError): @@ -91,29 +94,31 @@ class TestBase(TestCase): # END for each filename def test_includes_order(self): - with GitConfigParser(list(map(fixture_path, ("git_config", "git_config_global")))) as r_config: - r_config.read() # enforce reading + with GitConfigParser( + list(map(fixture_path, ("git_config", "git_config_global"))) + ) as r_config: + r_config.read() # enforce reading # Simple inclusions, again checking them taking precedence - assert r_config.get_value('sec', 'var0') == "value0_included" + assert r_config.get_value("sec", "var0") == "value0_included" # This one should take the git_config_global value since included # values must be considered as soon as they get them - assert r_config.get_value('diff', 'tool') == "meld" + assert r_config.get_value("diff", "tool") == "meld" try: - assert r_config.get_value('sec', 'var1') == "value1_main" + assert r_config.get_value("sec", "var1") == "value1_main" except AssertionError as e: raise SkipTest( - 'Known failure -- included values are not in effect right away' + "Known failure -- included values are not in effect right away" ) from e @with_rw_directory def test_lock_reentry(self, rw_dir): - fpl = osp.join(rw_dir, 'l') + fpl = osp.join(rw_dir, "l") gcp = GitConfigParser(fpl, read_only=False) with gcp as cw: - cw.set_value('include', 'some_value', 'a') + cw.set_value("include", "some_value", "a") # entering again locks the file again... with gcp as cw: - cw.set_value('include', 'some_other_value', 'b') + cw.set_value("include", "some_other_value", "b") # ...so creating an additional config writer must fail due to exclusive access with self.assertRaises(IOError): GitConfigParser(fpl, read_only=False) @@ -136,10 +141,12 @@ class TestBase(TestCase): ev += " end\n" ev += " File.open(%(%A), %(w)) {|f| f.write(b)}\n" ev += " exit 1 if b.include?(%(<)*%L)'" - self.assertEqual(config.get('merge "railsschema"', 'driver'), ev) - self.assertEqual(config.get('alias', 'lg'), - "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'" - " --abbrev-commit --date=relative") + self.assertEqual(config.get('merge "railsschema"', "driver"), ev) + self.assertEqual( + config.get("alias", "lg"), + "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'" + " --abbrev-commit --date=relative", + ) self.assertEqual(len(config.sections()), 23) def test_base(self): @@ -186,47 +193,51 @@ class TestBase(TestCase): @with_rw_directory def test_config_include(self, rw_dir): def write_test_value(cw, value): - cw.set_value(value, 'value', value) + cw.set_value(value, "value", value) + # end def check_test_value(cr, value): - assert cr.get_value(value, 'value') == value + assert cr.get_value(value, "value") == value + # end # PREPARE CONFIG FILE A - fpa = osp.join(rw_dir, 'a') + fpa = osp.join(rw_dir, "a") with GitConfigParser(fpa, read_only=False) as cw: - write_test_value(cw, 'a') - - fpb = osp.join(rw_dir, 'b') - fpc = osp.join(rw_dir, 'c') - cw.set_value('include', 'relative_path_b', 'b') - cw.set_value('include', 'doesntexist', 'foobar') - cw.set_value('include', 'relative_cycle_a_a', 'a') - cw.set_value('include', 'absolute_cycle_a_a', fpa) + write_test_value(cw, "a") + + fpb = osp.join(rw_dir, "b") + fpc = osp.join(rw_dir, "c") + cw.set_value("include", "relative_path_b", "b") + cw.set_value("include", "doesntexist", "foobar") + cw.set_value("include", "relative_cycle_a_a", "a") + cw.set_value("include", "absolute_cycle_a_a", fpa) assert osp.exists(fpa) # PREPARE CONFIG FILE B with GitConfigParser(fpb, read_only=False) as cw: - write_test_value(cw, 'b') - cw.set_value('include', 'relative_cycle_b_a', 'a') - cw.set_value('include', 'absolute_cycle_b_a', fpa) - cw.set_value('include', 'relative_path_c', 'c') - cw.set_value('include', 'absolute_path_c', fpc) + write_test_value(cw, "b") + cw.set_value("include", "relative_cycle_b_a", "a") + cw.set_value("include", "absolute_cycle_b_a", fpa) + cw.set_value("include", "relative_path_c", "c") + cw.set_value("include", "absolute_path_c", fpc) # PREPARE CONFIG FILE C with GitConfigParser(fpc, read_only=False) as cw: - write_test_value(cw, 'c') + write_test_value(cw, "c") with GitConfigParser(fpa, read_only=True) as cr: - for tv in ('a', 'b', 'c'): + for tv in ("a", "b", "c"): check_test_value(cr, tv) # end for each test to verify - assert len(cr.items('include')) == 8, "Expected all include sections to be merged" + assert ( + len(cr.items("include")) == 8 + ), "Expected all include sections to be merged" # test writable config writers - assure write-back doesn't involve includes with GitConfigParser(fpa, read_only=False, merge_includes=True) as cw: - tv = 'x' + tv = "x" write_test_value(cw, tv) with GitConfigParser(fpa, read_only=True) as cr: @@ -252,7 +263,7 @@ class TestBase(TestCase): # Initiate config files. path1 = osp.join(rw_dir, "config1") path2 = osp.join(rw_dir, "config2") - template = "[includeIf \"{}:{}\"]\n path={}\n" + template = '[includeIf "{}:{}"]\n path={}\n' with open(path1, "w") as stream: stream.write(template.format("gitdir", git_dir, path2)) @@ -319,7 +330,7 @@ class TestBase(TestCase): # Initiate config files. path1 = osp.join(rw_dir, "config1") path2 = osp.join(rw_dir, "config2") - template = "[includeIf \"onbranch:{}\"]\n path={}\n" + template = '[includeIf "onbranch:{}"]\n path={}\n' # Ensure that config is included is branch is correct. with open(path1, "w") as stream: @@ -356,14 +367,14 @@ class TestBase(TestCase): # Ensure that config is ignored when active branch cannot be found. with open(path1, "w") as stream: - stream.write("[includeIf \"onbranch:foo\"]\n path=/path\n") + stream.write('[includeIf "onbranch:foo"]\n path=/path\n') with GitConfigParser(path1, repo=repo) as config: assert not config._has_includes() assert config._included_paths() == [] def test_rename(self): - file_obj = self._to_memcache(fixture_path('git_config')) + file_obj = self._to_memcache(fixture_path("git_config")) with GitConfigParser(file_obj, read_only=False, merge_includes=False) as cw: with self.assertRaises(ValueError): cw.rename_section("doesntexist", "foo") @@ -371,127 +382,161 @@ class TestBase(TestCase): cw.rename_section("core", "include") nn = "bee" - assert cw.rename_section('core', nn) is cw - assert not cw.has_section('core') + assert cw.rename_section("core", nn) is cw + assert not cw.has_section("core") assert len(cw.items(nn)) == 4 def test_complex_aliases(self): - file_obj = self._to_memcache(fixture_path('.gitconfig')) + file_obj = self._to_memcache(fixture_path(".gitconfig")) with GitConfigParser(file_obj, read_only=False) as w_config: - self.assertEqual(w_config.get('alias', 'rbi'), '"!g() { git rebase -i origin/${1:-master} ; } ; g"') - self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path('.gitconfig')).getvalue()) + self.assertEqual( + w_config.get("alias", "rbi"), + '"!g() { git rebase -i origin/${1:-master} ; } ; g"', + ) + self.assertEqual( + file_obj.getvalue(), + self._to_memcache(fixture_path(".gitconfig")).getvalue(), + ) def test_empty_config_value(self): - cr = GitConfigParser(fixture_path('git_config_with_empty_value'), read_only=True) + cr = GitConfigParser( + fixture_path("git_config_with_empty_value"), read_only=True + ) - assert cr.get_value('core', 'filemode'), "Should read keys with values" + assert cr.get_value("core", "filemode"), "Should read keys with values" with self.assertRaises(cp.NoOptionError): - cr.get_value('color', 'ui') + cr.get_value("color", "ui") def test_multiple_values(self): - file_obj = self._to_memcache(fixture_path('git_config_multiple')) + file_obj = self._to_memcache(fixture_path("git_config_multiple")) with GitConfigParser(file_obj, read_only=False) as cw: - self.assertEqual(cw.get('section0', 'option0'), 'value0') - self.assertEqual(cw.get_values('section0', 'option0'), ['value0']) - self.assertEqual(cw.items('section0'), [('option0', 'value0')]) + self.assertEqual(cw.get("section0", "option0"), "value0") + self.assertEqual(cw.get_values("section0", "option0"), ["value0"]) + self.assertEqual(cw.items("section0"), [("option0", "value0")]) # Where there are multiple values, "get" returns the last. - self.assertEqual(cw.get('section1', 'option1'), 'value1b') - self.assertEqual(cw.get_values('section1', 'option1'), - ['value1a', 'value1b']) - self.assertEqual(cw.items('section1'), - [('option1', 'value1b'), - ('other_option1', 'other_value1')]) - self.assertEqual(cw.items_all('section1'), - [('option1', ['value1a', 'value1b']), - ('other_option1', ['other_value1'])]) + self.assertEqual(cw.get("section1", "option1"), "value1b") + self.assertEqual( + cw.get_values("section1", "option1"), ["value1a", "value1b"] + ) + self.assertEqual( + cw.items("section1"), + [("option1", "value1b"), ("other_option1", "other_value1")], + ) + self.assertEqual( + cw.items_all("section1"), + [ + ("option1", ["value1a", "value1b"]), + ("other_option1", ["other_value1"]), + ], + ) with self.assertRaises(KeyError): - cw.get_values('section1', 'missing') + cw.get_values("section1", "missing") - self.assertEqual(cw.get_values('section1', 'missing', 1), [1]) - self.assertEqual(cw.get_values('section1', 'missing', 's'), ['s']) + self.assertEqual(cw.get_values("section1", "missing", 1), [1]) + self.assertEqual(cw.get_values("section1", "missing", "s"), ["s"]) def test_multiple_values_rename(self): - file_obj = self._to_memcache(fixture_path('git_config_multiple')) + file_obj = self._to_memcache(fixture_path("git_config_multiple")) with GitConfigParser(file_obj, read_only=False) as cw: - cw.rename_section('section1', 'section2') + cw.rename_section("section1", "section2") cw.write() file_obj.seek(0) cr = GitConfigParser(file_obj, read_only=True) - self.assertEqual(cr.get_value('section2', 'option1'), 'value1b') - self.assertEqual(cr.get_values('section2', 'option1'), - ['value1a', 'value1b']) - self.assertEqual(cr.items('section2'), - [('option1', 'value1b'), - ('other_option1', 'other_value1')]) - self.assertEqual(cr.items_all('section2'), - [('option1', ['value1a', 'value1b']), - ('other_option1', ['other_value1'])]) + self.assertEqual(cr.get_value("section2", "option1"), "value1b") + self.assertEqual( + cr.get_values("section2", "option1"), ["value1a", "value1b"] + ) + self.assertEqual( + cr.items("section2"), + [("option1", "value1b"), ("other_option1", "other_value1")], + ) + self.assertEqual( + cr.items_all("section2"), + [ + ("option1", ["value1a", "value1b"]), + ("other_option1", ["other_value1"]), + ], + ) def test_multiple_to_single(self): - file_obj = self._to_memcache(fixture_path('git_config_multiple')) + file_obj = self._to_memcache(fixture_path("git_config_multiple")) with GitConfigParser(file_obj, read_only=False) as cw: - cw.set_value('section1', 'option1', 'value1c') + cw.set_value("section1", "option1", "value1c") cw.write() file_obj.seek(0) cr = GitConfigParser(file_obj, read_only=True) - self.assertEqual(cr.get_value('section1', 'option1'), 'value1c') - self.assertEqual(cr.get_values('section1', 'option1'), ['value1c']) - self.assertEqual(cr.items('section1'), - [('option1', 'value1c'), - ('other_option1', 'other_value1')]) - self.assertEqual(cr.items_all('section1'), - [('option1', ['value1c']), - ('other_option1', ['other_value1'])]) + self.assertEqual(cr.get_value("section1", "option1"), "value1c") + self.assertEqual(cr.get_values("section1", "option1"), ["value1c"]) + self.assertEqual( + cr.items("section1"), + [("option1", "value1c"), ("other_option1", "other_value1")], + ) + self.assertEqual( + cr.items_all("section1"), + [("option1", ["value1c"]), ("other_option1", ["other_value1"])], + ) def test_single_to_multiple(self): - file_obj = self._to_memcache(fixture_path('git_config_multiple')) + file_obj = self._to_memcache(fixture_path("git_config_multiple")) with GitConfigParser(file_obj, read_only=False) as cw: - cw.add_value('section1', 'other_option1', 'other_value1a') + cw.add_value("section1", "other_option1", "other_value1a") cw.write() file_obj.seek(0) cr = GitConfigParser(file_obj, read_only=True) - self.assertEqual(cr.get_value('section1', 'option1'), 'value1b') - self.assertEqual(cr.get_values('section1', 'option1'), - ['value1a', 'value1b']) - self.assertEqual(cr.get_value('section1', 'other_option1'), - 'other_value1a') - self.assertEqual(cr.get_values('section1', 'other_option1'), - ['other_value1', 'other_value1a']) - self.assertEqual(cr.items('section1'), - [('option1', 'value1b'), - ('other_option1', 'other_value1a')]) + self.assertEqual(cr.get_value("section1", "option1"), "value1b") + self.assertEqual( + cr.get_values("section1", "option1"), ["value1a", "value1b"] + ) + self.assertEqual(cr.get_value("section1", "other_option1"), "other_value1a") + self.assertEqual( + cr.get_values("section1", "other_option1"), + ["other_value1", "other_value1a"], + ) self.assertEqual( - cr.items_all('section1'), - [('option1', ['value1a', 'value1b']), - ('other_option1', ['other_value1', 'other_value1a'])]) + cr.items("section1"), + [("option1", "value1b"), ("other_option1", "other_value1a")], + ) + self.assertEqual( + cr.items_all("section1"), + [ + ("option1", ["value1a", "value1b"]), + ("other_option1", ["other_value1", "other_value1a"]), + ], + ) def test_add_to_multiple(self): - file_obj = self._to_memcache(fixture_path('git_config_multiple')) + file_obj = self._to_memcache(fixture_path("git_config_multiple")) with GitConfigParser(file_obj, read_only=False) as cw: - cw.add_value('section1', 'option1', 'value1c') + cw.add_value("section1", "option1", "value1c") cw.write() file_obj.seek(0) cr = GitConfigParser(file_obj, read_only=True) - self.assertEqual(cr.get_value('section1', 'option1'), 'value1c') - self.assertEqual(cr.get_values('section1', 'option1'), - ['value1a', 'value1b', 'value1c']) - self.assertEqual(cr.items('section1'), - [('option1', 'value1c'), - ('other_option1', 'other_value1')]) - self.assertEqual(cr.items_all('section1'), - [('option1', ['value1a', 'value1b', 'value1c']), - ('other_option1', ['other_value1'])]) + self.assertEqual(cr.get_value("section1", "option1"), "value1c") + self.assertEqual( + cr.get_values("section1", "option1"), ["value1a", "value1b", "value1c"] + ) + self.assertEqual( + cr.items("section1"), + [("option1", "value1c"), ("other_option1", "other_value1")], + ) + self.assertEqual( + cr.items_all("section1"), + [ + ("option1", ["value1a", "value1b", "value1c"]), + ("other_option1", ["other_value1"]), + ], + ) def test_setlast(self): # Test directly, not covered by higher-level tests. omd = _OMD() - omd.setlast('key', 'value1') - self.assertEqual(omd['key'], 'value1') - self.assertEqual(omd.getall('key'), ['value1']) - omd.setlast('key', 'value2') - self.assertEqual(omd['key'], 'value2') - self.assertEqual(omd.getall('key'), ['value2']) + omd.setlast("key", "value1") + self.assertEqual(omd["key"], "value1") + self.assertEqual(omd.getall("key"), ["value1"]) + omd.setlast("key", "value2") + self.assertEqual(omd["key"], "value2") + self.assertEqual(omd.getall("key"), ["value2"]) diff --git a/test/test_db.py b/test/test_db.py index f9090fdd..228c70e7 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -12,9 +12,8 @@ import os.path as osp class TestDB(TestBase): - def test_base(self): - gdb = GitCmdObjectDB(osp.join(self.rorepo.git_dir, 'objects'), self.rorepo.git) + gdb = GitCmdObjectDB(osp.join(self.rorepo.git_dir, "objects"), self.rorepo.git) # partial to complete - works with everything hexsha = bin_to_hex(gdb.partial_to_complete_sha_hex("0.1.6")) diff --git a/test/test_diff.py b/test/test_diff.py index 92e27f5d..10f5d6db 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -28,18 +28,18 @@ import os.path as osp def to_raw(input): - return input.replace(b'\t', b'\x00') + return input.replace(b"\t", b"\x00") @ddt.ddt class TestDiff(TestBase): - def setUp(self): self.repo_dir = tempfile.mkdtemp() self.submodule_dir = tempfile.mkdtemp() def tearDown(self): import gc + gc.collect() shutil.rmtree(self.repo_dir) shutil.rmtree(self.submodule_dir) @@ -53,9 +53,9 @@ class TestDiff(TestBase): assert isinstance(diff.b_mode, int) if diff.a_blob: - assert not diff.a_blob.path.endswith('\n') + assert not diff.a_blob.path.endswith("\n") if diff.b_blob: - assert not diff.b_blob.path.endswith('\n') + assert not diff.b_blob.path.endswith("\n") # END for each diff return diffs @@ -63,38 +63,47 @@ class TestDiff(TestBase): def test_diff_with_staged_file(self, rw_dir): # SETUP INDEX WITH MULTIPLE STAGES r = Repo.init(rw_dir) - fp = osp.join(rw_dir, 'hello.txt') - with open(fp, 'w') as fs: + fp = osp.join(rw_dir, "hello.txt") + with open(fp, "w") as fs: fs.write("hello world") r.git.add(Git.polish_url(fp)) r.git.commit(message="init") - with open(fp, 'w') as fs: + with open(fp, "w") as fs: fs.write("Hola Mundo") r.git.add(Git.polish_url(fp)) - self.assertEqual(len(r.index.diff("HEAD", create_patch=True)), 1, - "create_patch should generate patch of diff to HEAD") + self.assertEqual( + len(r.index.diff("HEAD", create_patch=True)), + 1, + "create_patch should generate patch of diff to HEAD", + ) r.git.commit(message="change on master") - self.assertEqual(len(r.index.diff("HEAD", create_patch=True)), 0, - "create_patch should generate no patch, already on HEAD") - - r.git.checkout('HEAD~1', b='topic') - with open(fp, 'w') as fs: + self.assertEqual( + len(r.index.diff("HEAD", create_patch=True)), + 0, + "create_patch should generate no patch, already on HEAD", + ) + + r.git.checkout("HEAD~1", b="topic") + with open(fp, "w") as fs: fs.write("Hallo Welt") r.git.commit(all=True, message="change on topic branch") # there must be a merge-conflict with self.assertRaises(GitCommandError): - r.git.cherry_pick('master') + r.git.cherry_pick("master") # Now do the actual testing - this should just work self.assertEqual(len(r.index.diff(None)), 2) - self.assertEqual(len(r.index.diff(None, create_patch=True)), 0, - "This should work, but doesn't right now ... it's OK") + self.assertEqual( + len(r.index.diff(None, create_patch=True)), + 0, + "This should work, but doesn't right now ... it's OK", + ) def test_list_from_string_new_mode(self): - output = StringProcessAdapter(fixture('diff_new_mode')) + output = StringProcessAdapter(fixture("diff_new_mode")) diffs = Diff._index_from_patch_format(self.rorepo, output) self._assert_diff_format(diffs) @@ -102,7 +111,7 @@ class TestDiff(TestBase): self.assertEqual(8, len(diffs[0].diff.splitlines())) def test_diff_with_rename(self): - output = StringProcessAdapter(fixture('diff_rename')) + output = StringProcessAdapter(fixture("diff_rename")) diffs = Diff._index_from_patch_format(self.rorepo, output) self._assert_diff_format(diffs) @@ -111,26 +120,26 @@ class TestDiff(TestBase): diff = diffs[0] self.assertTrue(diff.renamed_file) self.assertTrue(diff.renamed) - self.assertEqual(diff.rename_from, 'Jérôme') - self.assertEqual(diff.rename_to, 'müller') - self.assertEqual(diff.raw_rename_from, b'J\xc3\xa9r\xc3\xb4me') - self.assertEqual(diff.raw_rename_to, b'm\xc3\xbcller') + self.assertEqual(diff.rename_from, "Jérôme") + self.assertEqual(diff.rename_to, "müller") + self.assertEqual(diff.raw_rename_from, b"J\xc3\xa9r\xc3\xb4me") + self.assertEqual(diff.raw_rename_to, b"m\xc3\xbcller") assert isinstance(str(diff), str) - output = StringProcessAdapter(to_raw(fixture('diff_rename_raw'))) + output = StringProcessAdapter(to_raw(fixture("diff_rename_raw"))) diffs = Diff._index_from_raw_format(self.rorepo, output) self.assertEqual(len(diffs), 1) diff = diffs[0] self.assertIsNotNone(diff.renamed_file) self.assertIsNotNone(diff.renamed) - self.assertEqual(diff.rename_from, 'this') - self.assertEqual(diff.rename_to, 'that') - self.assertEqual(diff.change_type, 'R') + self.assertEqual(diff.rename_from, "this") + self.assertEqual(diff.rename_to, "that") + self.assertEqual(diff.change_type, "R") self.assertEqual(diff.score, 100) - self.assertEqual(len(list(diffs.iter_change_type('R'))), 1) + self.assertEqual(len(list(diffs.iter_change_type("R"))), 1) def test_diff_with_copied_file(self): - output = StringProcessAdapter(fixture('diff_copied_mode')) + output = StringProcessAdapter(fixture("diff_copied_mode")) diffs = Diff._index_from_patch_format(self.rorepo, output) self._assert_diff_format(diffs) @@ -138,146 +147,170 @@ class TestDiff(TestBase): diff = diffs[0] self.assertTrue(diff.copied_file) - self.assertTrue(diff.a_path, 'test1.txt') - self.assertTrue(diff.b_path, 'test2.txt') + self.assertTrue(diff.a_path, "test1.txt") + self.assertTrue(diff.b_path, "test2.txt") assert isinstance(str(diff), str) - output = StringProcessAdapter(to_raw(fixture('diff_copied_mode_raw'))) + output = StringProcessAdapter(to_raw(fixture("diff_copied_mode_raw"))) diffs = Diff._index_from_raw_format(self.rorepo, output) self.assertEqual(len(diffs), 1) diff = diffs[0] - self.assertEqual(diff.change_type, 'C') + self.assertEqual(diff.change_type, "C") self.assertEqual(diff.score, 100) - self.assertEqual(diff.a_path, 'test1.txt') - self.assertEqual(diff.b_path, 'test2.txt') - self.assertEqual(len(list(diffs.iter_change_type('C'))), 1) + self.assertEqual(diff.a_path, "test1.txt") + self.assertEqual(diff.b_path, "test2.txt") + self.assertEqual(len(list(diffs.iter_change_type("C"))), 1) def test_diff_with_change_in_type(self): - output = StringProcessAdapter(fixture('diff_change_in_type')) + output = StringProcessAdapter(fixture("diff_change_in_type")) diffs = Diff._index_from_patch_format(self.rorepo, output) self._assert_diff_format(diffs) self.assertEqual(2, len(diffs)) diff = diffs[0] self.assertIsNotNone(diff.deleted_file) - self.assertEqual(diff.a_path, 'this') - self.assertEqual(diff.b_path, 'this') + self.assertEqual(diff.a_path, "this") + self.assertEqual(diff.b_path, "this") assert isinstance(str(diff), str) diff = diffs[1] self.assertEqual(diff.a_path, None) - self.assertEqual(diff.b_path, 'this') + self.assertEqual(diff.b_path, "this") self.assertIsNotNone(diff.new_file) assert isinstance(str(diff), str) - output = StringProcessAdapter(to_raw(fixture('diff_change_in_type_raw'))) + output = StringProcessAdapter(to_raw(fixture("diff_change_in_type_raw"))) diffs = Diff._index_from_raw_format(self.rorepo, output) self.assertEqual(len(diffs), 1) diff = diffs[0] self.assertEqual(diff.rename_from, None) self.assertEqual(diff.rename_to, None) - self.assertEqual(diff.change_type, 'T') - self.assertEqual(len(list(diffs.iter_change_type('T'))), 1) + self.assertEqual(diff.change_type, "T") + self.assertEqual(len(list(diffs.iter_change_type("T"))), 1) def test_diff_of_modified_files_not_added_to_the_index(self): - output = StringProcessAdapter(to_raw(fixture('diff_abbrev-40_full-index_M_raw_no-color'))) + output = StringProcessAdapter( + to_raw(fixture("diff_abbrev-40_full-index_M_raw_no-color")) + ) diffs = Diff._index_from_raw_format(self.rorepo, output) - self.assertEqual(len(diffs), 1, 'one modification') - self.assertEqual(len(list(diffs.iter_change_type('M'))), 1, 'one modification') - self.assertEqual(diffs[0].change_type, 'M') - self.assertIsNone(diffs[0].b_blob,) + self.assertEqual(len(diffs), 1, "one modification") + self.assertEqual(len(list(diffs.iter_change_type("M"))), 1, "one modification") + self.assertEqual(diffs[0].change_type, "M") + self.assertIsNone( + diffs[0].b_blob, + ) @ddt.data( - (Diff._index_from_patch_format, 'diff_patch_binary'), - (Diff._index_from_raw_format, 'diff_raw_binary') + (Diff._index_from_patch_format, "diff_patch_binary"), + (Diff._index_from_raw_format, "diff_raw_binary"), ) def test_binary_diff(self, case): method, file_name = case res = method(None, StringProcessAdapter(fixture(file_name))) self.assertEqual(len(res), 1) - self.assertEqual(len(list(res.iter_change_type('M'))), 1) + self.assertEqual(len(list(res.iter_change_type("M"))), 1) if res[0].diff: - self.assertEqual(res[0].diff, - b"Binary files a/rps and b/rps differ\n", - "in patch mode, we get a diff text") + self.assertEqual( + res[0].diff, + b"Binary files a/rps and b/rps differ\n", + "in patch mode, we get a diff text", + ) self.assertIsNotNone(str(res[0]), "This call should just work") def test_diff_index(self): - output = StringProcessAdapter(fixture('diff_index_patch')) + output = StringProcessAdapter(fixture("diff_index_patch")) res = Diff._index_from_patch_format(None, output) self.assertEqual(len(res), 6) for dr in res: - self.assertTrue(dr.diff.startswith(b'@@'), dr) - self.assertIsNotNone(str(dr), "Diff to string conversion should be possible") + self.assertTrue(dr.diff.startswith(b"@@"), dr) + self.assertIsNotNone( + str(dr), "Diff to string conversion should be possible" + ) # end for each diff dr = res[3] assert dr.diff.endswith(b"+Binary files a/rps and b/rps differ\n") def test_diff_index_raw_format(self): - output = StringProcessAdapter(fixture('diff_index_raw')) + output = StringProcessAdapter(fixture("diff_index_raw")) res = Diff._index_from_raw_format(None, output) self.assertIsNotNone(res[0].deleted_file) - self.assertIsNone(res[0].b_path,) + self.assertIsNone( + res[0].b_path, + ) - @unittest.skip("This currently fails and would need someone to improve diff parsing") + @unittest.skip( + "This currently fails and would need someone to improve diff parsing" + ) def test_diff_file_with_colon(self): - output = fixture('diff_file_with_colon') + output = fixture("diff_file_with_colon") res = [] Diff._handle_diff_line(output, None, res) def test_diff_initial_commit(self): - initial_commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781') + initial_commit = self.rorepo.commit("33ebe7acec14b25c5f84f35a664803fcab2f7781") # Without creating a patch... diff_index = initial_commit.diff(NULL_TREE) - self.assertEqual(diff_index[0].b_path, 'CHANGES') + self.assertEqual(diff_index[0].b_path, "CHANGES") self.assertIsNotNone(diff_index[0].new_file) - self.assertEqual(diff_index[0].diff, '') + self.assertEqual(diff_index[0].diff, "") # ...and with creating a patch diff_index = initial_commit.diff(NULL_TREE, create_patch=True) self.assertIsNone(diff_index[0].a_path, repr(diff_index[0].a_path)) - self.assertEqual(diff_index[0].b_path, 'CHANGES', repr(diff_index[0].b_path)) + self.assertEqual(diff_index[0].b_path, "CHANGES", repr(diff_index[0].b_path)) self.assertIsNotNone(diff_index[0].new_file) - self.assertEqual(diff_index[0].diff, fixture('diff_initial')) + self.assertEqual(diff_index[0].diff, fixture("diff_initial")) def test_diff_unsafe_paths(self): - output = StringProcessAdapter(fixture('diff_patch_unsafe_paths')) + output = StringProcessAdapter(fixture("diff_patch_unsafe_paths")) res = Diff._index_from_patch_format(None, output) # The "Additions" - self.assertEqual(res[0].b_path, 'path/ starting with a space') + self.assertEqual(res[0].b_path, "path/ starting with a space") self.assertEqual(res[1].b_path, 'path/"with-quotes"') self.assertEqual(res[2].b_path, "path/'with-single-quotes'") - self.assertEqual(res[3].b_path, 'path/ending in a space ') - self.assertEqual(res[4].b_path, 'path/with\ttab') - self.assertEqual(res[5].b_path, 'path/with\nnewline') - self.assertEqual(res[6].b_path, 'path/with spaces') - self.assertEqual(res[7].b_path, 'path/with-question-mark?') - self.assertEqual(res[8].b_path, 'path/¯\\_(ツ)_|¯') - self.assertEqual(res[9].b_path, 'path/💩.txt') - self.assertEqual(res[9].b_rawpath, b'path/\xf0\x9f\x92\xa9.txt') - self.assertEqual(res[10].b_path, 'path/�-invalid-unicode-path.txt') - self.assertEqual(res[10].b_rawpath, b'path/\x80-invalid-unicode-path.txt') + self.assertEqual(res[3].b_path, "path/ending in a space ") + self.assertEqual(res[4].b_path, "path/with\ttab") + self.assertEqual(res[5].b_path, "path/with\nnewline") + self.assertEqual(res[6].b_path, "path/with spaces") + self.assertEqual(res[7].b_path, "path/with-question-mark?") + self.assertEqual(res[8].b_path, "path/¯\\_(ツ)_|¯") + self.assertEqual(res[9].b_path, "path/💩.txt") + self.assertEqual(res[9].b_rawpath, b"path/\xf0\x9f\x92\xa9.txt") + self.assertEqual(res[10].b_path, "path/�-invalid-unicode-path.txt") + self.assertEqual(res[10].b_rawpath, b"path/\x80-invalid-unicode-path.txt") # The "Moves" # NOTE: The path prefixes a/ and b/ here are legit! We're actually # verifying that it's not "a/a/" that shows up, see the fixture data. - self.assertEqual(res[11].a_path, 'a/with spaces') # NOTE: path a/ here legit! - self.assertEqual(res[11].b_path, 'b/with some spaces') # NOTE: path b/ here legit! - self.assertEqual(res[12].a_path, 'a/ending in a space ') - self.assertEqual(res[12].b_path, 'b/ending with space ') + self.assertEqual(res[11].a_path, "a/with spaces") # NOTE: path a/ here legit! + self.assertEqual( + res[11].b_path, "b/with some spaces" + ) # NOTE: path b/ here legit! + self.assertEqual(res[12].a_path, "a/ending in a space ") + self.assertEqual(res[12].b_path, "b/ending with space ") self.assertEqual(res[13].a_path, 'a/"with-quotes"') self.assertEqual(res[13].b_path, 'b/"with even more quotes"') def test_diff_patch_format(self): # test all of the 'old' format diffs for completeness - it should at least # be able to deal with it - fixtures = ("diff_2", "diff_2f", "diff_f", "diff_i", "diff_mode_only", - "diff_new_mode", "diff_numstat", "diff_p", "diff_rename", - "diff_tree_numstat_root", "diff_patch_unsafe_paths") + fixtures = ( + "diff_2", + "diff_2f", + "diff_f", + "diff_i", + "diff_mode_only", + "diff_new_mode", + "diff_numstat", + "diff_p", + "diff_rename", + "diff_tree_numstat_root", + "diff_patch_unsafe_paths", + ) for fixture_name in fixtures: diff_proc = StringProcessAdapter(fixture(fixture_name)) @@ -285,10 +318,12 @@ class TestDiff(TestBase): # END for each fixture def test_diff_with_spaces(self): - data = StringProcessAdapter(fixture('diff_file_with_spaces')) + data = StringProcessAdapter(fixture("diff_file_with_spaces")) diff_index = Diff._index_from_patch_format(self.rorepo, data) self.assertIsNone(diff_index[0].a_path, repr(diff_index[0].a_path)) - self.assertEqual(diff_index[0].b_path, 'file with spaces', repr(diff_index[0].b_path)) + self.assertEqual( + diff_index[0].b_path, "file with spaces", repr(diff_index[0].b_path) + ) def test_diff_submodule(self): """Test that diff is able to correctly diff commits that cover submodule changes""" @@ -303,13 +338,13 @@ class TestDiff(TestBase): repo = Repo.init(self.repo_dir) with open(self.repo_dir + "/test", "w") as foo_test: foo_test.write("") - repo.index.add(['test']) + repo.index.add(["test"]) Submodule.add(repo, "subtest", "sub", url="file://" + self.submodule_dir) repo.index.commit("first commit") - repo.create_tag('1') + repo.create_tag("1") # Add a commit to the submodule - submodule = repo.submodule('subtest') + submodule = repo.submodule("subtest") with open(self.repo_dir + "/sub/subfile", "w") as foo_sub_subfile: foo_sub_subfile.write("blub") submodule.module().index.add(["subfile"]) @@ -319,9 +354,9 @@ class TestDiff(TestBase): # Commit submodule updates in parent repo repo.index.add([submodule]) repo.index.commit("submodule changed") - repo.create_tag('2') + repo.create_tag("2") - diff = repo.commit('1').diff(repo.commit('2'))[0] + diff = repo.commit("1").diff(repo.commit("2"))[0] # If diff is unable to find the commit hashes (looks in wrong repo) the *_blob.size # property will be a string containing exception text, an int indicates success self.assertIsInstance(diff.a_blob.size, int) @@ -330,7 +365,7 @@ class TestDiff(TestBase): def test_diff_interface(self): # test a few variations of the main diff routine assertion_map = {} - for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=2)): + for i, commit in enumerate(self.rorepo.iter_commits("0.1.6", max_count=2)): diff_item = commit if i % 2 == 0: diff_item = commit.tree @@ -339,15 +374,19 @@ class TestDiff(TestBase): for other in (None, NULL_TREE, commit.Index, commit.parents[0]): for paths in (None, "CHANGES", ("CHANGES", "lib")): for create_patch in range(2): - diff_index = diff_item.diff(other=other, paths=paths, create_patch=create_patch) + diff_index = diff_item.diff( + other=other, paths=paths, create_patch=create_patch + ) assert isinstance(diff_index, DiffIndex) if diff_index: self._assert_diff_format(diff_index) for ct in DiffIndex.change_type: - key = 'ct_%s' % ct + key = "ct_%s" % ct assertion_map.setdefault(key, 0) - assertion_map[key] = assertion_map[key] + len(list(diff_index.iter_change_type(ct))) + assertion_map[key] = assertion_map[key] + len( + list(diff_index.iter_change_type(ct)) + ) # END for each changetype # check entries @@ -359,7 +398,10 @@ class TestDiff(TestBase): self.assertFalse(diff_index[0] != diff_index[0]) for dr in diff_index: - self.assertIsNotNone(str(dr), "Diff to string conversion should be possible") + self.assertIsNotNone( + str(dr), + "Diff to string conversion should be possible", + ) # END diff index checking # END for each patch option # END for each path option diff --git a/test/test_docs.py b/test/test_docs.py index 08fc8439..b6a0ed31 100644 --- a/test/test_docs.py +++ b/test/test_docs.py @@ -13,9 +13,9 @@ import os.path class Tutorials(TestBase): - def tearDown(self): import gc + gc.collect() # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, ## ACTUALLY skipped by `git.submodule.base#L869`. @@ -34,71 +34,102 @@ class Tutorials(TestBase): # ![1-test_init_repo_object] # [2-test_init_repo_object] - bare_repo = Repo.init(os.path.join(rw_dir, 'bare-repo'), bare=True) + bare_repo = Repo.init(os.path.join(rw_dir, "bare-repo"), bare=True) assert bare_repo.bare # ![2-test_init_repo_object] # [3-test_init_repo_object] - repo.config_reader() # get a config reader for read-only access - with repo.config_writer(): # get a config writer to change configuration - pass # call release() to be sure changes are written and locks are released + repo.config_reader() # get a config reader for read-only access + with repo.config_writer(): # get a config writer to change configuration + pass # call release() to be sure changes are written and locks are released # ![3-test_init_repo_object] # [4-test_init_repo_object] assert not bare_repo.is_dirty() # check the dirty state - repo.untracked_files # retrieve a list of untracked files + repo.untracked_files # retrieve a list of untracked files # ['my_untracked_file'] # ![4-test_init_repo_object] # [5-test_init_repo_object] - cloned_repo = repo.clone(os.path.join(rw_dir, 'to/this/path')) - assert cloned_repo.__class__ is Repo # clone an existing repository - assert Repo.init(os.path.join(rw_dir, 'path/for/new/repo')).__class__ is Repo + cloned_repo = repo.clone(os.path.join(rw_dir, "to/this/path")) + assert cloned_repo.__class__ is Repo # clone an existing repository + assert Repo.init(os.path.join(rw_dir, "path/for/new/repo")).__class__ is Repo # ![5-test_init_repo_object] # [6-test_init_repo_object] - with open(os.path.join(rw_dir, 'repo.tar'), 'wb') as fp: + with open(os.path.join(rw_dir, "repo.tar"), "wb") as fp: repo.archive(fp) # ![6-test_init_repo_object] # repository paths # [7-test_init_repo_object] - assert os.path.isdir(cloned_repo.working_tree_dir) # directory with your work files - assert cloned_repo.git_dir.startswith(cloned_repo.working_tree_dir) # directory containing the git repository - assert bare_repo.working_tree_dir is None # bare repositories have no working tree + assert os.path.isdir( + cloned_repo.working_tree_dir + ) # directory with your work files + assert cloned_repo.git_dir.startswith( + cloned_repo.working_tree_dir + ) # directory containing the git repository + assert ( + bare_repo.working_tree_dir is None + ) # bare repositories have no working tree # ![7-test_init_repo_object] # heads, tags and references # heads are branches in git-speak # [8-test_init_repo_object] - self.assertEqual(repo.head.ref, repo.heads.master, # head is a sym-ref pointing to master - "It's ok if TC not running from `master`.") - self.assertEqual(repo.tags['0.3.5'], repo.tag('refs/tags/0.3.5')) # you can access tags in various ways too - self.assertEqual(repo.refs.master, repo.heads['master']) # .refs provides all refs, ie heads ... - - if 'TRAVIS' not in os.environ: - self.assertEqual(repo.refs['origin/master'], repo.remotes.origin.refs.master) # ... remotes ... - self.assertEqual(repo.refs['0.3.5'], repo.tags['0.3.5']) # ... and tags + self.assertEqual( + repo.head.ref, + repo.heads.master, # head is a sym-ref pointing to master + "It's ok if TC not running from `master`.", + ) + self.assertEqual( + repo.tags["0.3.5"], repo.tag("refs/tags/0.3.5") + ) # you can access tags in various ways too + self.assertEqual( + repo.refs.master, repo.heads["master"] + ) # .refs provides all refs, ie heads ... + + if "TRAVIS" not in os.environ: + self.assertEqual( + repo.refs["origin/master"], repo.remotes.origin.refs.master + ) # ... remotes ... + self.assertEqual(repo.refs["0.3.5"], repo.tags["0.3.5"]) # ... and tags # ![8-test_init_repo_object] # create a new head/branch # [9-test_init_repo_object] - new_branch = cloned_repo.create_head('feature') # create a new branch ... - assert cloned_repo.active_branch != new_branch # which wasn't checked out yet ... - self.assertEqual(new_branch.commit, cloned_repo.active_branch.commit) # pointing to the checked-out commit + new_branch = cloned_repo.create_head("feature") # create a new branch ... + assert ( + cloned_repo.active_branch != new_branch + ) # which wasn't checked out yet ... + self.assertEqual( + new_branch.commit, cloned_repo.active_branch.commit + ) # pointing to the checked-out commit # It's easy to let a branch point to the previous commit, without affecting anything else # Each reference provides access to the git object it points to, usually commits - assert new_branch.set_commit('HEAD~1').commit == cloned_repo.active_branch.commit.parents[0] + assert ( + new_branch.set_commit("HEAD~1").commit + == cloned_repo.active_branch.commit.parents[0] + ) # ![9-test_init_repo_object] # create a new tag reference # [10-test_init_repo_object] - past = cloned_repo.create_tag('past', ref=new_branch, - message="This is a tag-object pointing to %s" % new_branch.name) - self.assertEqual(past.commit, new_branch.commit) # the tag points to the specified commit - assert past.tag.message.startswith("This is") # and its object carries the message provided - - now = cloned_repo.create_tag('now') # This is a tag-reference. It may not carry meta-data + past = cloned_repo.create_tag( + "past", + ref=new_branch, + message="This is a tag-object pointing to %s" % new_branch.name, + ) + self.assertEqual( + past.commit, new_branch.commit + ) # the tag points to the specified commit + assert past.tag.message.startswith( + "This is" + ) # and its object carries the message provided + + now = cloned_repo.create_tag( + "now" + ) # This is a tag-reference. It may not carry meta-data assert now.tag is None # ![10-test_init_repo_object] @@ -106,17 +137,26 @@ class Tutorials(TestBase): # [11-test_init_repo_object] assert now.commit.message != past.commit.message # You can read objects directly through binary streams, no working tree required - assert (now.commit.tree / 'VERSION').data_stream.read().decode('ascii').startswith('3') + assert ( + (now.commit.tree / "VERSION") + .data_stream.read() + .decode("ascii") + .startswith("3") + ) # You can traverse trees as well to handle all contained files of a particular commit file_count = 0 tree_count = 0 tree = past.commit.tree for item in tree.traverse(): - file_count += item.type == 'blob' - tree_count += item.type == 'tree' - assert file_count and tree_count # we have accumulated all directories and files - self.assertEqual(len(tree.blobs) + len(tree.trees), len(tree)) # a tree is iterable on its children + file_count += item.type == "blob" + tree_count += item.type == "tree" + assert ( + file_count and tree_count + ) # we have accumulated all directories and files + self.assertEqual( + len(tree.blobs) + len(tree.trees), len(tree) + ) # a tree is iterable on its children # ![11-test_init_repo_object] # remotes allow handling push, pull and fetch operations @@ -124,19 +164,28 @@ class Tutorials(TestBase): from git import RemoteProgress class MyProgressPrinter(RemoteProgress): - def update(self, op_code, cur_count, max_count=None, message=''): - print(op_code, cur_count, max_count, cur_count / (max_count or 100.0), message or "NO MESSAGE") + def update(self, op_code, cur_count, max_count=None, message=""): + print( + op_code, + cur_count, + max_count, + cur_count / (max_count or 100.0), + message or "NO MESSAGE", + ) + # end - self.assertEqual(len(cloned_repo.remotes), 1) # we have been cloned, so should be one remote - self.assertEqual(len(bare_repo.remotes), 0) # this one was just initialized - origin = bare_repo.create_remote('origin', url=cloned_repo.working_tree_dir) + self.assertEqual( + len(cloned_repo.remotes), 1 + ) # we have been cloned, so should be one remote + self.assertEqual(len(bare_repo.remotes), 0) # this one was just initialized + origin = bare_repo.create_remote("origin", url=cloned_repo.working_tree_dir) assert origin.exists() for fetch_info in origin.fetch(progress=MyProgressPrinter()): print("Updated %s to %s" % (fetch_info.ref, fetch_info.commit)) # create a local branch at the latest fetched master. We specify the name statically, but you have all # information to do it programmatically as well. - bare_master = bare_repo.create_head('master', origin.refs.master) + bare_master = bare_repo.create_head("master", origin.refs.master) bare_repo.head.set_reference(bare_master) assert not bare_repo.delete_remote(origin).exists() # push and pull behave very similarly @@ -144,28 +193,42 @@ class Tutorials(TestBase): # index # [13-test_init_repo_object] - self.assertEqual(new_branch.checkout(), cloned_repo.active_branch) # checking out branch adjusts the wtree - self.assertEqual(new_branch.commit, past.commit) # Now the past is checked out - - new_file_path = os.path.join(cloned_repo.working_tree_dir, 'my-new-file') - open(new_file_path, 'wb').close() # create new file in working tree - cloned_repo.index.add([new_file_path]) # add it to the index + self.assertEqual( + new_branch.checkout(), cloned_repo.active_branch + ) # checking out branch adjusts the wtree + self.assertEqual(new_branch.commit, past.commit) # Now the past is checked out + + new_file_path = os.path.join(cloned_repo.working_tree_dir, "my-new-file") + open(new_file_path, "wb").close() # create new file in working tree + cloned_repo.index.add([new_file_path]) # add it to the index # Commit the changes to deviate masters history cloned_repo.index.commit("Added a new file in the past - for later merege") # prepare a merge - master = cloned_repo.heads.master # right-hand side is ahead of us, in the future - merge_base = cloned_repo.merge_base(new_branch, master) # allows for a three-way merge - cloned_repo.index.merge_tree(master, base=merge_base) # write the merge result into index - cloned_repo.index.commit("Merged past and now into future ;)", - parent_commits=(new_branch.commit, master.commit)) + master = ( + cloned_repo.heads.master + ) # right-hand side is ahead of us, in the future + merge_base = cloned_repo.merge_base( + new_branch, master + ) # allows for a three-way merge + cloned_repo.index.merge_tree( + master, base=merge_base + ) # write the merge result into index + cloned_repo.index.commit( + "Merged past and now into future ;)", + parent_commits=(new_branch.commit, master.commit), + ) # now new_branch is ahead of master, which probably should be checked out and reset softly. # note that all these operations didn't touch the working tree, as we managed it ourselves. # This definitely requires you to know what you are doing :) ! - assert os.path.basename(new_file_path) in new_branch.commit.tree # new file is now in tree - master.commit = new_branch.commit # let master point to most recent commit - cloned_repo.head.reference = master # we adjusted just the reference, not the working tree or index + assert ( + os.path.basename(new_file_path) in new_branch.commit.tree + ) # new file is now in tree + master.commit = new_branch.commit # let master point to most recent commit + cloned_repo.head.reference = ( + master # we adjusted just the reference, not the working tree or index + ) # ![13-test_init_repo_object] # submodules @@ -175,110 +238,135 @@ class Tutorials(TestBase): # As our GitPython repository has submodules already that point to GitHub, make sure we don't # interact with them for sm in cloned_repo.submodules: - assert not sm.remove().exists() # after removal, the sm doesn't exist anymore - sm = cloned_repo.create_submodule('mysubrepo', 'path/to/subrepo', url=bare_repo.git_dir, branch='master') + assert ( + not sm.remove().exists() + ) # after removal, the sm doesn't exist anymore + sm = cloned_repo.create_submodule( + "mysubrepo", "path/to/subrepo", url=bare_repo.git_dir, branch="master" + ) # .gitmodules was written and added to the index, which is now being committed cloned_repo.index.commit("Added submodule") - assert sm.exists() and sm.module_exists() # this submodule is defintely available - sm.remove(module=True, configuration=False) # remove the working tree - assert sm.exists() and not sm.module_exists() # the submodule itself is still available + assert ( + sm.exists() and sm.module_exists() + ) # this submodule is defintely available + sm.remove(module=True, configuration=False) # remove the working tree + assert ( + sm.exists() and not sm.module_exists() + ) # the submodule itself is still available # update all submodules, non-recursively to save time, this method is very powerful, go have a look cloned_repo.submodule_update(recursive=False) - assert sm.module_exists() # The submodules working tree was checked out by update + assert ( + sm.module_exists() + ) # The submodules working tree was checked out by update # ![14-test_init_repo_object] @with_rw_directory def test_references_and_objects(self, rw_dir): # [1-test_references_and_objects] import git - repo = git.Repo.clone_from(self._small_repo_url(), os.path.join(rw_dir, 'repo'), branch='master') + + repo = git.Repo.clone_from( + self._small_repo_url(), os.path.join(rw_dir, "repo"), branch="master" + ) heads = repo.heads - master = heads.master # lists can be accessed by name for convenience - master.commit # the commit pointed to by head called master - master.rename('new_name') # rename heads - master.rename('master') + master = heads.master # lists can be accessed by name for convenience + master.commit # the commit pointed to by head called master + master.rename("new_name") # rename heads + master.rename("master") # ![1-test_references_and_objects] # [2-test_references_and_objects] tags = repo.tags tagref = tags[0] - tagref.tag # tags may have tag objects carrying additional information - tagref.commit # but they always point to commits - repo.delete_tag(tagref) # delete or - repo.create_tag("my_tag") # create tags using the repo for convenience + tagref.tag # tags may have tag objects carrying additional information + tagref.commit # but they always point to commits + repo.delete_tag(tagref) # delete or + repo.create_tag("my_tag") # create tags using the repo for convenience # ![2-test_references_and_objects] # [3-test_references_and_objects] - head = repo.head # the head points to the active branch/ref - master = head.reference # retrieve the reference the head points to - master.commit # from here you use it as any other reference + head = repo.head # the head points to the active branch/ref + master = head.reference # retrieve the reference the head points to + master.commit # from here you use it as any other reference # ![3-test_references_and_objects] -# + # # [4-test_references_and_objects] log = master.log() - log[0] # first (i.e. oldest) reflog entry - log[-1] # last (i.e. most recent) reflog entry + log[0] # first (i.e. oldest) reflog entry + log[-1] # last (i.e. most recent) reflog entry # ![4-test_references_and_objects] # [5-test_references_and_objects] - new_branch = repo.create_head('new') # create a new one - new_branch.commit = 'HEAD~10' # set branch to another commit without changing index or working trees - repo.delete_head(new_branch) # delete an existing head - only works if it is not checked out + new_branch = repo.create_head("new") # create a new one + new_branch.commit = "HEAD~10" # set branch to another commit without changing index or working trees + repo.delete_head( + new_branch + ) # delete an existing head - only works if it is not checked out # ![5-test_references_and_objects] # [6-test_references_and_objects] - new_tag = repo.create_tag('my_new_tag', message='my message') + new_tag = repo.create_tag("my_new_tag", message="my message") # You cannot change the commit a tag points to. Tags need to be re-created - self.assertRaises(AttributeError, setattr, new_tag, 'commit', repo.commit('HEAD~1')) + self.assertRaises( + AttributeError, setattr, new_tag, "commit", repo.commit("HEAD~1") + ) repo.delete_tag(new_tag) # ![6-test_references_and_objects] # [7-test_references_and_objects] - new_branch = repo.create_head('another-branch') + new_branch = repo.create_head("another-branch") repo.head.reference = new_branch # ![7-test_references_and_objects] # [8-test_references_and_objects] hc = repo.head.commit hct = hc.tree - hc != hct # @NoEffect - hc != repo.tags[0] # @NoEffect - hc == repo.head.reference.commit # @NoEffect + hc != hct # @NoEffect + hc != repo.tags[0] # @NoEffect + hc == repo.head.reference.commit # @NoEffect # ![8-test_references_and_objects] # [9-test_references_and_objects] - self.assertEqual(hct.type, 'tree') # preset string type, being a class attribute - assert hct.size > 0 # size in bytes + self.assertEqual( + hct.type, "tree" + ) # preset string type, being a class attribute + assert hct.size > 0 # size in bytes assert len(hct.hexsha) == 40 assert len(hct.binsha) == 20 # ![9-test_references_and_objects] # [10-test_references_and_objects] - self.assertEqual(hct.path, '') # root tree has no path - assert hct.trees[0].path != '' # the first contained item has one though - self.assertEqual(hct.mode, 0o40000) # trees have the mode of a linux directory - self.assertEqual(hct.blobs[0].mode, 0o100644) # blobs have specific mode, comparable to a standard linux fs + self.assertEqual(hct.path, "") # root tree has no path + assert hct.trees[0].path != "" # the first contained item has one though + self.assertEqual(hct.mode, 0o40000) # trees have the mode of a linux directory + self.assertEqual( + hct.blobs[0].mode, 0o100644 + ) # blobs have specific mode, comparable to a standard linux fs # ![10-test_references_and_objects] # [11-test_references_and_objects] - hct.blobs[0].data_stream.read() # stream object to read data from - hct.blobs[0].stream_data(open(os.path.join(rw_dir, 'blob_data'), 'wb')) # write data to given stream + hct.blobs[0].data_stream.read() # stream object to read data from + hct.blobs[0].stream_data( + open(os.path.join(rw_dir, "blob_data"), "wb") + ) # write data to given stream # ![11-test_references_and_objects] # [12-test_references_and_objects] - repo.commit('master') - repo.commit('v0.8.1') - repo.commit('HEAD~10') + repo.commit("master") + repo.commit("v0.8.1") + repo.commit("HEAD~10") # ![12-test_references_and_objects] # [13-test_references_and_objects] - fifty_first_commits = list(repo.iter_commits('master', max_count=50)) + fifty_first_commits = list(repo.iter_commits("master", max_count=50)) assert len(fifty_first_commits) == 50 # this will return commits 21-30 from the commit list as traversed backwards master - ten_commits_past_twenty = list(repo.iter_commits('master', max_count=10, skip=20)) + ten_commits_past_twenty = list( + repo.iter_commits("master", max_count=10, skip=20) + ) assert len(ten_commits_past_twenty) == 10 assert fifty_first_commits[20:30] == ten_commits_past_twenty # ![13-test_references_and_objects] @@ -287,22 +375,23 @@ class Tutorials(TestBase): headcommit = repo.head.commit assert len(headcommit.hexsha) == 40 assert len(headcommit.parents) > 0 - assert headcommit.tree.type == 'tree' + assert headcommit.tree.type == "tree" assert len(headcommit.author.name) != 0 assert isinstance(headcommit.authored_date, int) assert len(headcommit.committer.name) != 0 assert isinstance(headcommit.committed_date, int) - assert headcommit.message != '' + assert headcommit.message != "" # ![14-test_references_and_objects] # [15-test_references_and_objects] import time + time.asctime(time.gmtime(headcommit.committed_date)) time.strftime("%a, %d %b %Y %H:%M", time.gmtime(headcommit.committed_date)) # ![15-test_references_and_objects] # [16-test_references_and_objects] - assert headcommit.parents[0].parents[0].parents[0] == repo.commit('master^^^') + assert headcommit.parents[0].parents[0].parents[0] == repo.commit("master^^^") # ![16-test_references_and_objects] # [17-test_references_and_objects] @@ -311,33 +400,41 @@ class Tutorials(TestBase): # ![17-test_references_and_objects] # [18-test_references_and_objects] - assert len(tree.trees) > 0 # trees are subdirectories - assert len(tree.blobs) > 0 # blobs are files + assert len(tree.trees) > 0 # trees are subdirectories + assert len(tree.blobs) > 0 # blobs are files assert len(tree.blobs) + len(tree.trees) == len(tree) # ![18-test_references_and_objects] # [19-test_references_and_objects] - self.assertEqual(tree['smmap'], tree / 'smmap') # access by index and by sub-path - for entry in tree: # intuitive iteration of tree members + self.assertEqual( + tree["smmap"], tree / "smmap" + ) # access by index and by sub-path + for entry in tree: # intuitive iteration of tree members print(entry) - blob = tree.trees[1].blobs[0] # let's get a blob in a sub-tree + blob = tree.trees[1].blobs[0] # let's get a blob in a sub-tree assert blob.name assert len(blob.path) < len(blob.abspath) - self.assertEqual(tree.trees[1].name + '/' + blob.name, blob.path) # this is how relative blob path generated - self.assertEqual(tree[blob.path], blob) # you can use paths like 'dir/file' in tree + self.assertEqual( + tree.trees[1].name + "/" + blob.name, blob.path + ) # this is how relative blob path generated + self.assertEqual( + tree[blob.path], blob + ) # you can use paths like 'dir/file' in tree # ![19-test_references_and_objects] # [20-test_references_and_objects] - assert tree / 'smmap' == tree['smmap'] + assert tree / "smmap" == tree["smmap"] assert tree / blob.path == tree[blob.path] # ![20-test_references_and_objects] # [21-test_references_and_objects] # This example shows the various types of allowed ref-specs assert repo.tree() == repo.head.commit.tree - past = repo.commit('HEAD~5') + past = repo.commit("HEAD~5") assert repo.tree(past) == repo.tree(past.hexsha) - self.assertEqual(repo.tree('v0.8.1').type, 'tree') # yes, you can provide any refspec - works everywhere + self.assertEqual( + repo.tree("v0.8.1").type, "tree" + ) # yes, you can provide any refspec - works everywhere # ![21-test_references_and_objects] # [22-test_references_and_objects] @@ -347,20 +444,27 @@ class Tutorials(TestBase): # [23-test_references_and_objects] index = repo.index # The index contains all blobs in a flat list - assert len(list(index.iter_blobs())) == len([o for o in repo.head.commit.tree.traverse() if o.type == 'blob']) + assert len(list(index.iter_blobs())) == len( + [o for o in repo.head.commit.tree.traverse() if o.type == "blob"] + ) # Access blob objects for (_path, _stage), entry in index.entries.items(): pass - new_file_path = os.path.join(repo.working_tree_dir, 'new-file-name') - open(new_file_path, 'w').close() - index.add([new_file_path]) # add a new file to the index - index.remove(['LICENSE']) # remove an existing one - assert os.path.isfile(os.path.join(repo.working_tree_dir, 'LICENSE')) # working tree is untouched - - self.assertEqual(index.commit("my commit message").type, 'commit') # commit changed index - repo.active_branch.commit = repo.commit('HEAD~1') # forget last commit + new_file_path = os.path.join(repo.working_tree_dir, "new-file-name") + open(new_file_path, "w").close() + index.add([new_file_path]) # add a new file to the index + index.remove(["LICENSE"]) # remove an existing one + assert os.path.isfile( + os.path.join(repo.working_tree_dir, "LICENSE") + ) # working tree is untouched + + self.assertEqual( + index.commit("my commit message").type, "commit" + ) # commit changed index + repo.active_branch.commit = repo.commit("HEAD~1") # forget last commit from git import Actor + author = Actor("An author", "author@example.com") committer = Actor("A committer", "committer@example.com") # commit by commit message and author and committer @@ -369,28 +473,37 @@ class Tutorials(TestBase): # [24-test_references_and_objects] from git import IndexFile + # loads a tree into a temporary index, which exists just in memory - IndexFile.from_tree(repo, 'HEAD~1') + IndexFile.from_tree(repo, "HEAD~1") # merge two trees three-way into memory - merge_index = IndexFile.from_tree(repo, 'HEAD~10', 'HEAD', repo.merge_base('HEAD~10', 'HEAD')) + merge_index = IndexFile.from_tree( + repo, "HEAD~10", "HEAD", repo.merge_base("HEAD~10", "HEAD") + ) # and persist it - merge_index.write(os.path.join(rw_dir, 'merged_index')) + merge_index.write(os.path.join(rw_dir, "merged_index")) # ![24-test_references_and_objects] # [25-test_references_and_objects] - empty_repo = git.Repo.init(os.path.join(rw_dir, 'empty')) - origin = empty_repo.create_remote('origin', repo.remotes.origin.url) + empty_repo = git.Repo.init(os.path.join(rw_dir, "empty")) + origin = empty_repo.create_remote("origin", repo.remotes.origin.url) assert origin.exists() - assert origin == empty_repo.remotes.origin == empty_repo.remotes['origin'] - origin.fetch() # assure we actually have data. fetch() returns useful information + assert origin == empty_repo.remotes.origin == empty_repo.remotes["origin"] + origin.fetch() # assure we actually have data. fetch() returns useful information # Setup a local tracking branch of a remote branch - empty_repo.create_head('master', origin.refs.master) # create local branch "master" from remote "master" - empty_repo.heads.master.set_tracking_branch(origin.refs.master) # set local "master" to track remote "master + empty_repo.create_head( + "master", origin.refs.master + ) # create local branch "master" from remote "master" + empty_repo.heads.master.set_tracking_branch( + origin.refs.master + ) # set local "master" to track remote "master empty_repo.heads.master.checkout() # checkout local "master" to working tree # Three above commands in one: - empty_repo.create_head('master', origin.refs.master).set_tracking_branch(origin.refs.master).checkout() + empty_repo.create_head("master", origin.refs.master).set_tracking_branch( + origin.refs.master + ).checkout() # rename remotes - origin.rename('new_origin') + origin.rename("new_origin") # push and pull behaves similarly to `git push|pull` origin.pull() origin.push() # attempt push, ignore errors @@ -409,32 +522,32 @@ class Tutorials(TestBase): # [27-test_references_and_objects] hcommit = repo.head.commit - hcommit.diff() # diff tree against index - hcommit.diff('HEAD~1') # diff tree against previous tree - hcommit.diff(None) # diff tree against working tree + hcommit.diff() # diff tree against index + hcommit.diff("HEAD~1") # diff tree against previous tree + hcommit.diff(None) # diff tree against working tree index = repo.index - index.diff() # diff index against itself yielding empty diff - index.diff(None) # diff index against working copy - index.diff('HEAD') # diff index against current HEAD tree + index.diff() # diff index against itself yielding empty diff + index.diff(None) # diff index against working copy + index.diff("HEAD") # diff index against current HEAD tree # ![27-test_references_and_objects] # [28-test_references_and_objects] # Traverse added Diff objects only - for diff_added in hcommit.diff('HEAD~1').iter_change_type('A'): + for diff_added in hcommit.diff("HEAD~1").iter_change_type("A"): print(diff_added) # ![28-test_references_and_objects] # [29-test_references_and_objects] # Reset our working tree 10 commits into the past - past_branch = repo.create_head('past_branch', 'HEAD~10') + past_branch = repo.create_head("past_branch", "HEAD~10") repo.head.reference = past_branch assert not repo.head.is_detached # reset the index and working tree to match the pointed-to commit repo.head.reset(index=True, working_tree=True) # To detach your head, you have to point to a commit directly - repo.head.reference = repo.commit('HEAD~5') + repo.head.reference = repo.commit("HEAD~5") assert repo.head.is_detached # now our head points 15 commits into the past, whereas the working tree # and index are 10 commits in the past @@ -448,10 +561,12 @@ class Tutorials(TestBase): # [31-test_references_and_objects] git = repo.git - git.checkout('HEAD', b="my_new_branch") # create a new branch - git.branch('another-new-one') - git.branch('-D', 'another-new-one') # pass strings for full control over argument order - git.for_each_ref() # '-' becomes '_' when calling it + git.checkout("HEAD", b="my_new_branch") # create a new branch + git.branch("another-new-one") + git.branch( + "-D", "another-new-one" + ) # pass strings for full control over argument order + git.for_each_ref() # '-' becomes '_' when calling it # ![31-test_references_and_objects] repo.git.clear_cache() @@ -463,31 +578,37 @@ class Tutorials(TestBase): assert len(sms) == 1 sm = sms[0] - self.assertEqual(sm.name, 'gitdb') # git-python has gitdb as single submodule ... - self.assertEqual(sm.children()[0].name, 'smmap') # ... which has smmap as single submodule + self.assertEqual( + sm.name, "gitdb" + ) # git-python has gitdb as single submodule ... + self.assertEqual( + sm.children()[0].name, "smmap" + ) # ... which has smmap as single submodule # The module is the repository referenced by the submodule - assert sm.module_exists() # the module is available, which doesn't have to be the case. - assert sm.module().working_tree_dir.endswith('gitdb') + assert ( + sm.module_exists() + ) # the module is available, which doesn't have to be the case. + assert sm.module().working_tree_dir.endswith("gitdb") # the submodule's absolute path is the module's path assert sm.abspath == sm.module().working_tree_dir - self.assertEqual(len(sm.hexsha), 40) # Its sha defines the commit to checkout - assert sm.exists() # yes, this submodule is valid and exists + self.assertEqual(len(sm.hexsha), 40) # Its sha defines the commit to checkout + assert sm.exists() # yes, this submodule is valid and exists # read its configuration conveniently - assert sm.config_reader().get_value('path') == sm.path - self.assertEqual(len(sm.children()), 1) # query the submodule hierarchy + assert sm.config_reader().get_value("path") == sm.path + self.assertEqual(len(sm.children()), 1) # query the submodule hierarchy # ![1-test_submodules] @with_rw_directory def test_add_file_and_commit(self, rw_dir): import git - repo_dir = os.path.join(rw_dir, 'my-new-repo') - file_name = os.path.join(repo_dir, 'new-file') + repo_dir = os.path.join(rw_dir, "my-new-repo") + file_name = os.path.join(repo_dir, "new-file") r = git.Repo.init(repo_dir) # This function just creates an empty file ... - open(file_name, 'wb').close() + open(file_name, "wb").close() r.index.add([file_name]) r.index.commit("initial commit") diff --git a/test/test_exc.py b/test/test_exc.py index c77be782..6c3353fc 100644 --- a/test/test_exc.py +++ b/test/test_exc.py @@ -29,34 +29,43 @@ import itertools as itt _cmd_argvs = ( - ('cmd', ), - ('θνιψοδε', ), - ('θνιψοδε', 'normal', 'argvs'), - ('cmd', 'ελληνικα', 'args'), - ('θνιψοδε', 'κι', 'αλλα', 'strange', 'args'), - ('θνιψοδε', 'κι', 'αλλα', 'non-unicode', 'args'), - ('git', 'clone', '-v', 'https://fakeuser:fakepassword1234@fakerepo.example.com/testrepo'), + ("cmd",), + ("θνιψοδε",), + ("θνιψοδε", "normal", "argvs"), + ("cmd", "ελληνικα", "args"), + ("θνιψοδε", "κι", "αλλα", "strange", "args"), + ("θνιψοδε", "κι", "αλλα", "non-unicode", "args"), + ( + "git", + "clone", + "-v", + "https://fakeuser:fakepassword1234@fakerepo.example.com/testrepo", + ), ) _causes_n_substrings = ( - (None, None), # noqa: E241 @IgnorePep8 - (7, "exit code(7)"), # noqa: E241 @IgnorePep8 - ('Some string', "'Some string'"), # noqa: E241 @IgnorePep8 - ('παλιο string', "'παλιο string'"), # noqa: E241 @IgnorePep8 - (Exception("An exc."), "Exception('An exc.')"), # noqa: E241 @IgnorePep8 - (Exception("Κακια exc."), "Exception('Κακια exc.')"), # noqa: E241 @IgnorePep8 - (object(), "<object object at "), # noqa: E241 @IgnorePep8 + (None, None), # noqa: E241 @IgnorePep8 + (7, "exit code(7)"), # noqa: E241 @IgnorePep8 + ("Some string", "'Some string'"), # noqa: E241 @IgnorePep8 + ("παλιο string", "'παλιο string'"), # noqa: E241 @IgnorePep8 + (Exception("An exc."), "Exception('An exc.')"), # noqa: E241 @IgnorePep8 + (Exception("Κακια exc."), "Exception('Κακια exc.')"), # noqa: E241 @IgnorePep8 + (object(), "<object object at "), # noqa: E241 @IgnorePep8 ) -_streams_n_substrings = (None, 'steram', 'ομορφο stream', ) +_streams_n_substrings = ( + None, + "steram", + "ομορφο stream", +) @ddt.ddt class TExc(TestBase): - def test_ExceptionsHaveBaseClass(self): from git.exc import GitError + self.assertIsInstance(GitError(), Exception) - + exception_classes = [ InvalidGitRepositoryError, WorkTreeRepositoryUnsupported, @@ -73,7 +82,9 @@ class TExc(TestBase): for ex_class in exception_classes: self.assertTrue(issubclass(ex_class, GitError)) - @ddt.data(*list(itt.product(_cmd_argvs, _causes_n_substrings, _streams_n_substrings))) + @ddt.data( + *list(itt.product(_cmd_argvs, _causes_n_substrings, _streams_n_substrings)) + ) def test_CommandError_unicode(self, case): argv, (cause, subs), stream = case cls = CommandError @@ -81,7 +92,7 @@ class TExc(TestBase): s = str(c) self.assertIsNotNone(c._msg) - self.assertIn(' cmdline: ', s) + self.assertIn(" cmdline: ", s) for a in remove_password_if_present(argv): self.assertIn(a, s) @@ -112,17 +123,17 @@ class TExc(TestBase): self.assertIn(" stdout:", s) self.assertIn(stream, s) - c = cls(argv, cause, stream, stream + 'no2') + c = cls(argv, cause, stream, stream + "no2") s = str(c) self.assertIn(" stderr:", s) self.assertIn(stream, s) self.assertIn(" stdout:", s) - self.assertIn(stream + 'no2', s) + self.assertIn(stream + "no2", s) @ddt.data( - (['cmd1'], None), - (['cmd1'], "some cause"), - (['cmd1'], Exception()), + (["cmd1"], None), + (["cmd1"], "some cause"), + (["cmd1"], Exception()), ) def test_GitCommandNotFound(self, init_args): argv, cause = init_args @@ -131,15 +142,15 @@ class TExc(TestBase): self.assertIn(argv[0], s) if cause: - self.assertIn(' not found due to: ', s) + self.assertIn(" not found due to: ", s) self.assertIn(str(cause), s) else: - self.assertIn(' not found!', s) + self.assertIn(" not found!", s) @ddt.data( - (['cmd1'], None), - (['cmd1'], "some cause"), - (['cmd1', 'https://fakeuser@fakerepo.example.com/testrepo'], Exception()), + (["cmd1"], None), + (["cmd1"], "some cause"), + (["cmd1", "https://fakeuser@fakerepo.example.com/testrepo"], Exception()), ) def test_GitCommandError(self, init_args): argv, cause = init_args @@ -149,15 +160,15 @@ class TExc(TestBase): for arg in remove_password_if_present(argv): self.assertIn(arg, s) if cause: - self.assertIn(' failed due to: ', s) + self.assertIn(" failed due to: ", s) self.assertIn(str(cause), s) else: - self.assertIn(' failed!', s) + self.assertIn(" failed!", s) @ddt.data( - (['cmd1'], None), - (['cmd1'], "some cause"), - (['cmd1'], Exception()), + (["cmd1"], None), + (["cmd1"], "some cause"), + (["cmd1"], Exception()), ) def test_HookExecutionError(self, init_args): argv, cause = init_args @@ -166,7 +177,7 @@ class TExc(TestBase): self.assertIn(argv[0], s) if cause: - self.assertTrue(s.startswith('Hook('), s) + self.assertTrue(s.startswith("Hook("), s) self.assertIn(str(cause), s) else: - self.assertIn(' failed!', s) + self.assertIn(" failed!", s) diff --git a/test/test_fun.py b/test/test_fun.py index e3d07194..7c99a4a1 100644 --- a/test/test_fun.py +++ b/test/test_fun.py @@ -16,23 +16,19 @@ from git.objects.fun import ( tree_to_stream, tree_entries_from_data, ) -from git.repo.fun import ( - find_worktree_git_dir -) -from test.lib import ( - TestBase, - with_rw_repo, - with_rw_directory -) +from git.repo.fun import find_worktree_git_dir +from test.lib import TestBase, with_rw_repo, with_rw_directory from git.util import bin_to_hex, cygpath, join_path_native from gitdb.base import IStream from gitdb.typ import str_tree_type class TestFun(TestBase): - def _assert_index_entries(self, entries, trees): - index = IndexFile.from_tree(self.rorepo, *[self.rorepo.tree(bin_to_hex(t).decode('ascii')) for t in trees]) + index = IndexFile.from_tree( + self.rorepo, + *[self.rorepo.tree(bin_to_hex(t).decode("ascii")) for t in trees] + ) assert entries assert len(index.entries) == len(entries) for entry in entries: @@ -80,7 +76,7 @@ class TestFun(TestBase): istream = odb.store(IStream(str_tree_type, len(sio.getvalue()), sio)) return istream.binsha - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_three_way_merge(self, rwrepo): def mkfile(name, sha, executable=0): return (sha, S_IFREG | 0o644 | executable * 0o111, name) @@ -91,6 +87,7 @@ class TestFun(TestBase): def assert_entries(entries, num_entries, has_conflict=False): assert len(entries) == num_entries assert has_conflict == (len([e for e in entries if e.stage != 0]) > 0) + mktree = self.mktree shaa = b"\1" * 20 @@ -100,14 +97,14 @@ class TestFun(TestBase): odb = rwrepo.odb # base tree - bfn = 'basefile' + bfn = "basefile" fbase = mkfile(bfn, shaa) tb = mktree(odb, [fbase]) # non-conflicting new files, same data - fa = mkfile('1', shab) + fa = mkfile("1", shab) th = mktree(odb, [fbase, fa]) - fb = mkfile('2', shac) + fb = mkfile("2", shac) tm = mktree(odb, [fbase, fb]) # two new files, same base file @@ -115,9 +112,9 @@ class TestFun(TestBase): assert_entries(aggressive_tree_merge(odb, trees), 3) # both delete same file, add own one - fa = mkfile('1', shab) + fa = mkfile("1", shab) th = mktree(odb, [fa]) - fb = mkfile('2', shac) + fb = mkfile("2", shac) tm = mktree(odb, [fb]) # two new files @@ -125,9 +122,9 @@ class TestFun(TestBase): assert_entries(aggressive_tree_merge(odb, trees), 2) # same file added in both, differently - fa = mkfile('1', shab) + fa = mkfile("1", shab) th = mktree(odb, [fa]) - fb = mkfile('1', shac) + fb = mkfile("1", shac) tm = mktree(odb, [fb]) # expect conflict @@ -135,9 +132,9 @@ class TestFun(TestBase): assert_entries(aggressive_tree_merge(odb, trees), 2, True) # same file added, different mode - fa = mkfile('1', shab) + fa = mkfile("1", shab) th = mktree(odb, [fa]) - fb = mkcommit('1', shab) + fb = mkcommit("1", shab) tm = mktree(odb, [fb]) # expect conflict @@ -145,9 +142,9 @@ class TestFun(TestBase): assert_entries(aggressive_tree_merge(odb, trees), 2, True) # same file added in both - fa = mkfile('1', shab) + fa = mkfile("1", shab) th = mktree(odb, [fa]) - fb = mkfile('1', shab) + fb = mkfile("1", shab) tm = mktree(odb, [fb]) # expect conflict @@ -194,7 +191,11 @@ class TestFun(TestBase): if is_them: trees = [tb, tb, th] entries = aggressive_tree_merge(odb, trees) - assert len(entries) == 1 and entries[0].binsha == shaa and entries[0].mode == fa[1] + assert ( + len(entries) == 1 + and entries[0].binsha == shaa + and entries[0].mode == fa[1] + ) # one side deletes, the other changes = conflict fa = mkfile(bfn, shab) @@ -209,8 +210,20 @@ class TestFun(TestBase): def test_stat_mode_to_index_mode(self): modes = ( - 0o600, 0o611, 0o640, 0o641, 0o644, 0o650, 0o651, - 0o700, 0o711, 0o740, 0o744, 0o750, 0o751, 0o755, + 0o600, + 0o611, + 0o640, + 0o641, + 0o644, + 0o650, + 0o651, + 0o700, + 0o711, + 0o740, + 0o744, + 0o750, + 0o751, + 0o755, ) for mode in modes: expected_mode = S_IFREG | (mode & S_IXUSR and 0o755 or 0o644) @@ -229,42 +242,46 @@ class TestFun(TestBase): def test_tree_traversal(self): # low level tree tarversal odb = self.rorepo.odb - H = self.rorepo.tree('29eb123beb1c55e5db4aa652d843adccbd09ae18') # head tree - M = self.rorepo.tree('e14e3f143e7260de9581aee27e5a9b2645db72de') # merge tree - B = self.rorepo.tree('f606937a7a21237c866efafcad33675e6539c103') # base tree - B_old = self.rorepo.tree('1f66cfbbce58b4b552b041707a12d437cc5f400a') # old base tree + H = self.rorepo.tree("29eb123beb1c55e5db4aa652d843adccbd09ae18") # head tree + M = self.rorepo.tree("e14e3f143e7260de9581aee27e5a9b2645db72de") # merge tree + B = self.rorepo.tree("f606937a7a21237c866efafcad33675e6539c103") # base tree + B_old = self.rorepo.tree( + "1f66cfbbce58b4b552b041707a12d437cc5f400a" + ) # old base tree # two very different trees - entries = traverse_trees_recursive(odb, [B_old.binsha, H.binsha], '') + entries = traverse_trees_recursive(odb, [B_old.binsha, H.binsha], "") self._assert_tree_entries(entries, 2) - oentries = traverse_trees_recursive(odb, [H.binsha, B_old.binsha], '') + oentries = traverse_trees_recursive(odb, [H.binsha, B_old.binsha], "") assert len(oentries) == len(entries) self._assert_tree_entries(oentries, 2) # single tree - is_no_tree = lambda i, d: i.type != 'tree' - entries = traverse_trees_recursive(odb, [B.binsha], '') + is_no_tree = lambda i, d: i.type != "tree" + entries = traverse_trees_recursive(odb, [B.binsha], "") assert len(entries) == len(list(B.traverse(predicate=is_no_tree))) self._assert_tree_entries(entries, 1) # two trees - entries = traverse_trees_recursive(odb, [B.binsha, H.binsha], '') + entries = traverse_trees_recursive(odb, [B.binsha, H.binsha], "") self._assert_tree_entries(entries, 2) # tree trees - entries = traverse_trees_recursive(odb, [B.binsha, H.binsha, M.binsha], '') + entries = traverse_trees_recursive(odb, [B.binsha, H.binsha, M.binsha], "") self._assert_tree_entries(entries, 3) def test_tree_traversal_single(self): max_count = 50 count = 0 odb = self.rorepo.odb - for commit in self.rorepo.commit("29eb123beb1c55e5db4aa652d843adccbd09ae18").traverse(): + for commit in self.rorepo.commit( + "29eb123beb1c55e5db4aa652d843adccbd09ae18" + ).traverse(): if count >= max_count: break count += 1 - entries = traverse_tree_recursive(odb, commit.tree.binsha, '') + entries = traverse_tree_recursive(odb, commit.tree.binsha, "") assert entries # END for each commit @@ -275,12 +292,12 @@ class TestFun(TestBase): if git.version_info[:3] < (2, 5, 1): raise SkipTest("worktree feature unsupported") - rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo')) - branch = rw_master.create_head('aaaaaaaa') - worktree_path = join_path_native(rw_dir, 'worktree_repo') + rw_master = self.rorepo.clone(join_path_native(rw_dir, "master_repo")) + branch = rw_master.create_head("aaaaaaaa") + worktree_path = join_path_native(rw_dir, "worktree_repo") if Git.is_cygwin(): worktree_path = cygpath(worktree_path) - rw_master.git.worktree('add', worktree_path, branch.name) + rw_master.git.worktree("add", worktree_path, branch.name) dotgit = osp.join(worktree_path, ".git") statbuf = stat(dotgit) @@ -292,5 +309,5 @@ class TestFun(TestBase): self.assertTrue(statbuf.st_mode & S_IFDIR) def test_tree_entries_from_data_with_failing_name_decode_py3(self): - r = tree_entries_from_data(b'100644 \x9f\0aaa') - assert r == [(b'aaa', 33188, '\udc9f')], r + r = tree_entries_from_data(b"100644 \x9f\0aaa") + assert r == [(b"aaa", 33188, "\udc9f")], r diff --git a/test/test_git.py b/test/test_git.py index 10e21487..2a034e41 100644 --- a/test/test_git.py +++ b/test/test_git.py @@ -10,18 +10,8 @@ import sys from tempfile import TemporaryFile from unittest import mock -from git import ( - Git, - refresh, - GitCommandError, - GitCommandNotFound, - Repo, - cmd -) -from test.lib import ( - TestBase, - fixture_path -) +from git import Git, refresh, GitCommandError, GitCommandNotFound, Repo, cmd +from test.lib import TestBase, fixture_path from test.lib import with_rw_directory from git.util import finalize_process @@ -31,7 +21,6 @@ from git.compat import is_win class TestGit(TestBase): - @classmethod def setUpClass(cls): super(TestGit, cls).setUpClass() @@ -39,56 +28,72 @@ class TestGit(TestBase): def tearDown(self): import gc + gc.collect() - @mock.patch.object(Git, 'execute') + @mock.patch.object(Git, "execute") def test_call_process_calls_execute(self, git): - git.return_value = '' + git.return_value = "" self.git.version() self.assertTrue(git.called) - self.assertEqual(git.call_args, ((['git', 'version'],), {})) + self.assertEqual(git.call_args, ((["git", "version"],), {})) def test_call_unpack_args_unicode(self): - args = Git._Git__unpack_args('Unicode€™') - mangled_value = 'Unicode\u20ac\u2122' + args = Git._Git__unpack_args("Unicode€™") + mangled_value = "Unicode\u20ac\u2122" self.assertEqual(args, [mangled_value]) def test_call_unpack_args(self): - args = Git._Git__unpack_args(['git', 'log', '--', 'Unicode€™']) - mangled_value = 'Unicode\u20ac\u2122' - self.assertEqual(args, ['git', 'log', '--', mangled_value]) + args = Git._Git__unpack_args(["git", "log", "--", "Unicode€™"]) + mangled_value = "Unicode\u20ac\u2122" + self.assertEqual(args, ["git", "log", "--", mangled_value]) def test_it_raises_errors(self): self.assertRaises(GitCommandError, self.git.this_does_not_exist) def test_it_transforms_kwargs_into_git_command_arguments(self): - self.assertEqual(["-s"], self.git.transform_kwargs(**{'s': True})) - self.assertEqual(["-s", "5"], self.git.transform_kwargs(**{'s': 5})) - self.assertEqual([], self.git.transform_kwargs(**{'s': None})) + self.assertEqual(["-s"], self.git.transform_kwargs(**{"s": True})) + self.assertEqual(["-s", "5"], self.git.transform_kwargs(**{"s": 5})) + self.assertEqual([], self.git.transform_kwargs(**{"s": None})) - self.assertEqual(["--max-count"], self.git.transform_kwargs(**{'max_count': True})) - self.assertEqual(["--max-count=5"], self.git.transform_kwargs(**{'max_count': 5})) - self.assertEqual(["--max-count=0"], self.git.transform_kwargs(**{'max_count': 0})) - self.assertEqual([], self.git.transform_kwargs(**{'max_count': None})) + self.assertEqual( + ["--max-count"], self.git.transform_kwargs(**{"max_count": True}) + ) + self.assertEqual( + ["--max-count=5"], self.git.transform_kwargs(**{"max_count": 5}) + ) + self.assertEqual( + ["--max-count=0"], self.git.transform_kwargs(**{"max_count": 0}) + ) + self.assertEqual([], self.git.transform_kwargs(**{"max_count": None})) # Multiple args are supported by using lists/tuples - self.assertEqual(["-L", "1-3", "-L", "12-18"], self.git.transform_kwargs(**{'L': ('1-3', '12-18')})) - self.assertEqual(["-C", "-C"], self.git.transform_kwargs(**{'C': [True, True, None, False]})) + self.assertEqual( + ["-L", "1-3", "-L", "12-18"], + self.git.transform_kwargs(**{"L": ("1-3", "12-18")}), + ) + self.assertEqual( + ["-C", "-C"], self.git.transform_kwargs(**{"C": [True, True, None, False]}) + ) # order is undefined - res = self.git.transform_kwargs(**{'s': True, 't': True}) - self.assertEqual({'-s', '-t'}, set(res)) + res = self.git.transform_kwargs(**{"s": True, "t": True}) + self.assertEqual({"-s", "-t"}, set(res)) def test_it_executes_git_to_shell_and_returns_result(self): - self.assertRegex(self.git.execute(["git", "version"]), r'^git version [\d\.]{2}.*$') + self.assertRegex( + self.git.execute(["git", "version"]), r"^git version [\d\.]{2}.*$" + ) def test_it_accepts_stdin(self): filename = fixture_path("cat_file_blob") - with open(filename, 'r') as fh: - self.assertEqual("70c379b63ffa0795fdbfbc128e5a2818397b7ef8", - self.git.hash_object(istream=fh, stdin=True)) + with open(filename, "r") as fh: + self.assertEqual( + "70c379b63ffa0795fdbfbc128e5a2818397b7ef8", + self.git.hash_object(istream=fh, stdin=True), + ) - @mock.patch.object(Git, 'execute') + @mock.patch.object(Git, "execute") def test_it_ignores_false_kwargs(self, git): # this_should_not_be_ignored=False implies it *should* be ignored self.git.version(pass_this_kwarg=False) @@ -96,22 +101,27 @@ class TestGit(TestBase): def test_it_raises_proper_exception_with_output_stream(self): tmp_file = TemporaryFile() - self.assertRaises(GitCommandError, self.git.checkout, 'non-existent-branch', output_stream=tmp_file) + self.assertRaises( + GitCommandError, + self.git.checkout, + "non-existent-branch", + output_stream=tmp_file, + ) def test_it_accepts_environment_variables(self): filename = fixture_path("ls_tree_empty") - with open(filename, 'r') as fh: + with open(filename, "r") as fh: tree = self.git.mktree(istream=fh) env = { - 'GIT_AUTHOR_NAME': 'Author Name', - 'GIT_AUTHOR_EMAIL': 'author@example.com', - 'GIT_AUTHOR_DATE': '1400000000+0000', - 'GIT_COMMITTER_NAME': 'Committer Name', - 'GIT_COMMITTER_EMAIL': 'committer@example.com', - 'GIT_COMMITTER_DATE': '1500000000+0000', + "GIT_AUTHOR_NAME": "Author Name", + "GIT_AUTHOR_EMAIL": "author@example.com", + "GIT_AUTHOR_DATE": "1400000000+0000", + "GIT_COMMITTER_NAME": "Committer Name", + "GIT_COMMITTER_EMAIL": "committer@example.com", + "GIT_COMMITTER_DATE": "1500000000+0000", } - commit = self.git.commit_tree(tree, m='message', env=env) - self.assertEqual(commit, '4cfd6b0314682d5a58f80be39850bad1640e9241') + commit = self.git.commit_tree(tree, m="message", env=env) + self.assertEqual(commit, "4cfd6b0314682d5a58f80be39850bad1640e9241") def test_persistent_cat_file_command(self): # read header only @@ -124,9 +134,7 @@ class TestGit(TestBase): obj_info = g.stdout.readline() # read header + data - g = self.git.cat_file( - batch=True, istream=subprocess.PIPE, as_process=True - ) + g = self.git.cat_file(batch=True, istream=subprocess.PIPE, as_process=True) g.stdin.write(b"b2339455342180c7cc1e9bba3e9f181f7baa5167\n") g.stdin.flush() obj_info_two = g.stdout.readline() @@ -161,7 +169,8 @@ class TestGit(TestBase): try: # set it to something that doesn't exist, assure it raises type(self.git).GIT_PYTHON_GIT_EXECUTABLE = osp.join( - "some", "path", "which", "doesn't", "exist", "gitbinary") + "some", "path", "which", "doesn't", "exist", "gitbinary" + ) self.assertRaises(exc, self.git.version) finally: type(self.git).GIT_PYTHON_GIT_EXECUTABLE = prev_cmd @@ -173,7 +182,7 @@ class TestGit(TestBase): # test a good path refresh which_cmd = "where" if is_win else "which" - path = os.popen("{0} git".format(which_cmd)).read().strip().split('\n')[0] + path = os.popen("{0} git".format(which_cmd)).read().strip().split("\n")[0] refresh(path) def test_options_are_passed_to_git(self): @@ -197,8 +206,10 @@ class TestGit(TestBase): self.assertRaises(GitCommandError, self.git.NoOp) def test_single_char_git_options_are_passed_to_git(self): - input_value = 'TestValue' - output_value = self.git(c='user.name=%s' % input_value).config('--get', 'user.name') + input_value = "TestValue" + output_value = self.git(c="user.name=%s" % input_value).config( + "--get", "user.name" + ) self.assertEqual(input_value, output_value) def test_change_to_transform_kwargs_does_not_break_command_options(self): @@ -206,11 +217,13 @@ class TestGit(TestBase): def test_insert_after_kwarg_raises(self): # This isn't a complete add command, which doesn't matter here - self.assertRaises(ValueError, self.git.remote, 'add', insert_kwargs_after='foo') + self.assertRaises(ValueError, self.git.remote, "add", insert_kwargs_after="foo") def test_env_vars_passed_to_git(self): - editor = 'non_existent_editor' - with mock.patch.dict('os.environ', {'GIT_EDITOR': editor}): # @UndefinedVariable + editor = "non_existent_editor" + with mock.patch.dict( + "os.environ", {"GIT_EDITOR": editor} + ): # @UndefinedVariable self.assertEqual(self.git.var("GIT_EDITOR"), editor) @with_rw_directory @@ -219,35 +232,34 @@ class TestGit(TestBase): self.assertEqual(self.git.environment(), {}) # make sure the context manager works and cleans up after itself - with self.git.custom_environment(PWD='/tmp'): - self.assertEqual(self.git.environment(), {'PWD': '/tmp'}) + with self.git.custom_environment(PWD="/tmp"): + self.assertEqual(self.git.environment(), {"PWD": "/tmp"}) self.assertEqual(self.git.environment(), {}) - old_env = self.git.update_environment(VARKEY='VARVALUE') + old_env = self.git.update_environment(VARKEY="VARVALUE") # The returned dict can be used to revert the change, hence why it has # an entry with value 'None'. - self.assertEqual(old_env, {'VARKEY': None}) - self.assertEqual(self.git.environment(), {'VARKEY': 'VARVALUE'}) + self.assertEqual(old_env, {"VARKEY": None}) + self.assertEqual(self.git.environment(), {"VARKEY": "VARVALUE"}) new_env = self.git.update_environment(**old_env) - self.assertEqual(new_env, {'VARKEY': 'VARVALUE'}) + self.assertEqual(new_env, {"VARKEY": "VARVALUE"}) self.assertEqual(self.git.environment(), {}) - path = osp.join(rw_dir, 'failing-script.sh') - with open(path, 'wt') as stream: - stream.write("#!/usr/bin/env sh\n" - "echo FOO\n") + path = osp.join(rw_dir, "failing-script.sh") + with open(path, "wt") as stream: + stream.write("#!/usr/bin/env sh\n" "echo FOO\n") os.chmod(path, 0o777) - rw_repo = Repo.init(osp.join(rw_dir, 'repo')) - remote = rw_repo.create_remote('ssh-origin', "ssh://git@server/foo") + rw_repo = Repo.init(osp.join(rw_dir, "repo")) + remote = rw_repo.create_remote("ssh-origin", "ssh://git@server/foo") with rw_repo.git.custom_environment(GIT_SSH=path): try: remote.fetch() except GitCommandError as err: - self.assertIn('FOO', str(err)) + self.assertIn("FOO", str(err)) def test_handle_process_output(self): from git.cmd import handle_process_output @@ -261,14 +273,19 @@ class TestGit(TestBase): def counter_stderr(line): count[2] += 1 - cmdline = [sys.executable, fixture_path('cat_file.py'), str(fixture_path('issue-301_stderr'))] - proc = subprocess.Popen(cmdline, - stdin=None, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=False, - creationflags=cmd.PROC_CREATIONFLAGS, - ) + cmdline = [ + sys.executable, + fixture_path("cat_file.py"), + str(fixture_path("issue-301_stderr")), + ] + proc = subprocess.Popen( + cmdline, + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + creationflags=cmd.PROC_CREATIONFLAGS, + ) handle_process_output(proc, counter_stdout, counter_stderr, finalize_process) diff --git a/test/test_index.py b/test/test_index.py index 4a20a8f6..3f88f5c5 100644 --- a/test/test_index.py +++ b/test/test_index.py @@ -7,10 +7,7 @@ from io import BytesIO import os -from stat import ( - S_ISLNK, - ST_MODE -) +from stat import S_ISLNK, ST_MODE import tempfile from unittest import skipIf import shutil @@ -27,22 +24,11 @@ from git import ( CheckoutError, ) from git.compat import is_win -from git.exc import ( - HookExecutionError, - InvalidGitRepositoryError -) +from git.exc import HookExecutionError, InvalidGitRepositoryError from git.index.fun import hook_path -from git.index.typ import ( - BaseIndexEntry, - IndexEntry -) +from git.index.typ import BaseIndexEntry, IndexEntry from git.objects import Blob -from test.lib import ( - TestBase, - fixture_path, - fixture, - with_rw_repo -) +from test.lib import TestBase, fixture_path, fixture, with_rw_repo from test.lib import with_rw_directory from git.util import Actor, rmtree from git.util import HIDE_WINDOWS_KNOWN_ERRORS, hex_to_bin @@ -53,7 +39,7 @@ from git.cmd import Git HOOKS_SHEBANG = "#!/usr/bin/env sh\n" -is_win_without_bash = is_win and not shutil.which('bash.exe') +is_win_without_bash = is_win and not shutil.which("bash.exe") def _make_hook(git_dir, name, content, make_exec=True): @@ -70,7 +56,6 @@ def _make_hook(git_dir, name, content, make_exec=True): class TestIndex(TestBase): - def __init__(self, *args): super(TestIndex, self).__init__(*args) self._reset_progress() @@ -116,8 +101,20 @@ class TestIndex(TestBase): # test entry entry = next(iter(index.entries.values())) - for attr in ("path", "ctime", "mtime", "dev", "inode", "mode", "uid", - "gid", "size", "binsha", "hexsha", "stage"): + for attr in ( + "path", + "ctime", + "mtime", + "dev", + "inode", + "mode", + "uid", + "gid", + "size", + "binsha", + "hexsha", + "stage", + ): getattr(entry, attr) # END for each method @@ -134,7 +131,7 @@ class TestIndex(TestBase): # write the data - it must match the original tmpfile = tempfile.mktemp() index_merge.write(tmpfile) - with open(tmpfile, 'rb') as fp: + with open(tmpfile, "rb") as fp: self.assertEqual(fp.read(), fixture("index_merge")) os.remove(tmpfile) @@ -144,21 +141,25 @@ class TestIndex(TestBase): tree = self.rorepo.commit(tree).tree blist = [] - for blob in tree.traverse(predicate=lambda e, d: e.type == "blob", branch_first=False): + for blob in tree.traverse( + predicate=lambda e, d: e.type == "blob", branch_first=False + ): assert (blob.path, 0) in index.entries blist.append(blob) # END for each blob in tree if len(blist) != len(index.entries): iset = {k[0] for k in index.entries.keys()} bset = {b.path for b in blist} - raise AssertionError("CMP Failed: Missing entries in index: %s, missing in tree: %s" % - (bset - iset, iset - bset)) + raise AssertionError( + "CMP Failed: Missing entries in index: %s, missing in tree: %s" + % (bset - iset, iset - bset) + ) # END assertion message - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_index_lock_handling(self, rw_repo): def add_bad_blob(): - rw_repo.index.add([Blob(rw_repo, b'f' * 20, 'bad-permissions', 'foo')]) + rw_repo.index.add([Blob(rw_repo, b"f" * 20, "bad-permissions", "foo")]) try: ## 1st fail on purpose adding into index. @@ -174,7 +175,7 @@ class TestIndex(TestBase): except Exception as ex: assert "index.lock' could not be obtained" not in str(ex) - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_index_file_from_tree(self, rw_repo): common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" @@ -191,7 +192,9 @@ class TestIndex(TestBase): self._cmp_tree_index(cur_sha, two_way_index) # merge three trees - here we have a merge conflict - three_way_index = IndexFile.from_tree(rw_repo, common_ancestor_sha, cur_sha, other_sha) + three_way_index = IndexFile.from_tree( + rw_repo, common_ancestor_sha, cur_sha, other_sha + ) assert len([e for e in three_way_index.entries.values() if e.stage != 0]) # ITERATE BLOBS @@ -202,7 +205,7 @@ class TestIndex(TestBase): assert isinstance(merge_blobs[0][1], Blob) # test BlobFilter - prefix = 'lib/git' + prefix = "lib/git" for _stage, blob in base_index.iter_blobs(BlobFilter([prefix])): assert blob.path.startswith(prefix) @@ -224,7 +227,7 @@ class TestIndex(TestBase): # END for each blob self.assertEqual(num_blobs, len(three_way_index.entries)) - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_index_merge_tree(self, rw_repo): # A bit out of place, but we need a different repo for this: self.assertNotEqual(self.rorepo, rw_repo) @@ -234,21 +237,25 @@ class TestIndex(TestBase): # current index is at the (virtual) cur_commit next_commit = "4c39f9da792792d4e73fc3a5effde66576ae128c" parent_commit = rw_repo.head.commit.parents[0] - manifest_key = IndexFile.entry_key('MANIFEST.in', 0) + manifest_key = IndexFile.entry_key("MANIFEST.in", 0) manifest_entry = rw_repo.index.entries[manifest_key] rw_repo.index.merge_tree(next_commit) # only one change should be recorded assert manifest_entry.binsha != rw_repo.index.entries[manifest_key].binsha rw_repo.index.reset(rw_repo.head) - self.assertEqual(rw_repo.index.entries[manifest_key].binsha, manifest_entry.binsha) + self.assertEqual( + rw_repo.index.entries[manifest_key].binsha, manifest_entry.binsha + ) # FAKE MERGE ############# # Add a change with a NULL sha that should conflict with next_commit. We # pretend there was a change, but we do not even bother adding a proper # sha for it ( which makes things faster of course ) - manifest_fake_entry = BaseIndexEntry((manifest_entry[0], b"\0" * 20, 0, manifest_entry[3])) + manifest_fake_entry = BaseIndexEntry( + (manifest_entry[0], b"\0" * 20, 0, manifest_entry[3]) + ) # try write flag self._assert_entries(rw_repo.index.add([manifest_fake_entry], write=False)) # add actually resolves the null-hex-sha for us as a feature, but we can @@ -267,7 +274,9 @@ class TestIndex(TestBase): # a three way merge would result in a conflict and fails as the command will # not overwrite any entries in our index and hence leave them unmerged. This is # mainly a protection feature as the current index is not yet in a tree - self.assertRaises(GitCommandError, index.merge_tree, next_commit, base=parent_commit) + self.assertRaises( + GitCommandError, index.merge_tree, next_commit, base=parent_commit + ) # the only way to get the merged entries is to safe the current index away into a tree, # which is like a temporary commit for us. This fails as well as the NULL sha deos not @@ -277,7 +286,9 @@ class TestIndex(TestBase): # if missing objects are okay, this would work though ( they are always okay now ) # As we can't read back the tree with NULL_SHA, we rather set it to something else - index.entries[manifest_key] = IndexEntry(manifest_entry[:1] + (hex_to_bin('f' * 40),) + manifest_entry[2:]) + index.entries[manifest_key] = IndexEntry( + manifest_entry[:1] + (hex_to_bin("f" * 40),) + manifest_entry[2:] + ) tree = index.write_tree() # now make a proper three way merge with unmerged entries @@ -286,7 +297,7 @@ class TestIndex(TestBase): self.assertEqual(len(unmerged_blobs), 1) self.assertEqual(list(unmerged_blobs.keys())[0], manifest_key[0]) - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_index_file_diffing(self, rw_repo): # default Index instance points to our index index = IndexFile(rw_repo) @@ -302,14 +313,14 @@ class TestIndex(TestBase): # resetting the head will leave the index in a different state, and the # diff will yield a few changes cur_head_commit = rw_repo.head.reference.commit - rw_repo.head.reset('HEAD~6', index=True, working_tree=False) + rw_repo.head.reset("HEAD~6", index=True, working_tree=False) # diff against same index is 0 diff = index.diff() self.assertEqual(len(diff), 0) # against HEAD as string, must be the same as it matches index - diff = index.diff('HEAD') + diff = index.diff("HEAD") self.assertEqual(len(diff), 0) # against previous head, there must be a difference @@ -318,9 +329,9 @@ class TestIndex(TestBase): # we reverse the result adiff = index.diff(str(cur_head_commit), R=True) - odiff = index.diff(cur_head_commit, R=False) # now its not reversed anymore + odiff = index.diff(cur_head_commit, R=False) # now its not reversed anymore assert adiff != odiff - self.assertEqual(odiff, diff) # both unreversed diffs against HEAD + self.assertEqual(odiff, diff) # both unreversed diffs against HEAD # against working copy - its still at cur_commit wdiff = index.diff(None) @@ -333,7 +344,7 @@ class TestIndex(TestBase): # adjust the index to match an old revision cur_branch = rw_repo.active_branch cur_commit = cur_branch.commit - rev_head_parent = 'HEAD~1' + rev_head_parent = "HEAD~1" assert index.reset(rev_head_parent) is index self.assertEqual(cur_branch, rw_repo.active_branch) @@ -351,28 +362,28 @@ class TestIndex(TestBase): assert not index.diff(None) self.assertEqual(cur_branch, rw_repo.active_branch) self.assertEqual(cur_commit, rw_repo.head.commit) - with open(file_path, 'rb') as fp: + with open(file_path, "rb") as fp: assert fp.read() != new_data # test full checkout test_file = osp.join(rw_repo.working_tree_dir, "CHANGES") - with open(test_file, 'ab') as fd: + with open(test_file, "ab") as fd: fd.write(b"some data") rval = index.checkout(None, force=True, fprogress=self._fprogress) - assert 'CHANGES' in list(rval) + assert "CHANGES" in list(rval) self._assert_fprogress([None]) assert osp.isfile(test_file) os.remove(test_file) rval = index.checkout(None, force=False, fprogress=self._fprogress) - assert 'CHANGES' in list(rval) + assert "CHANGES" in list(rval) self._assert_fprogress([None]) assert osp.isfile(test_file) # individual file os.remove(test_file) rval = index.checkout(test_file, fprogress=self._fprogress) - self.assertEqual(list(rval)[0], 'CHANGES') + self.assertEqual(list(rval)[0], "CHANGES") self._assert_fprogress([test_file]) assert osp.exists(test_file) @@ -394,7 +405,7 @@ class TestIndex(TestBase): self.assertEqual(len(e.failed_files), len(e.failed_reasons)) self.assertIsInstance(e.failed_reasons[0], str) self.assertEqual(len(e.valid_files), 0) - with open(test_file, 'rb') as fd: + with open(test_file, "rb") as fd: s = fd.read() self.assertTrue(s.endswith(append_data), s) else: @@ -402,11 +413,11 @@ class TestIndex(TestBase): # if we force it it should work index.checkout(test_file, force=True) - assert not open(test_file, 'rb').read().endswith(append_data) + assert not open(test_file, "rb").read().endswith(append_data) # checkout directory rmtree(osp.join(rw_repo.working_tree_dir, "lib")) - rval = index.checkout('lib') + rval = index.checkout("lib") assert len(list(rval)) > 1 def _count_existing(self, repo, files): @@ -419,15 +430,18 @@ class TestIndex(TestBase): existing += osp.isfile(osp.join(basedir, f)) # END for each deleted file return existing + # END num existing helper - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(), - """FIXME: File "C:\\projects\\gitpython\\git\\test\\test_index.py", line 642, in test_index_mutation + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(), + """FIXME: File "C:\\projects\\gitpython\\git\\test\\test_index.py", line 642, in test_index_mutation self.assertEqual(fd.read(), link_target) AssertionError: '!<symlink>\xff\xfe/\x00e\x00t\x00c\x00/\x00t\x00h\x00a\x00t\x00\x00\x00' != '/etc/that' - """) - @with_rw_repo('0.1.6') + """, + ) + @with_rw_repo("0.1.6") def test_index_mutation(self, rw_repo): index = rw_repo.index num_entries = len(index.entries) @@ -446,7 +460,7 @@ class TestIndex(TestBase): count = 0 for entry in index.entries.values(): type_id = count % 4 - if type_id == 0: # path + if type_id == 0: # path yield entry.path elif type_id == 1: # blob yield Blob(rw_repo, entry.binsha, entry.mode, entry.path) @@ -458,10 +472,13 @@ class TestIndex(TestBase): raise AssertionError("Invalid Type") count += 1 # END for each entry + # END mixed iterator deleted_files = index.remove(mixed_iterator(), working_tree=False) assert deleted_files - self.assertEqual(self._count_existing(rw_repo, deleted_files), len(deleted_files)) + self.assertEqual( + self._count_existing(rw_repo, deleted_files), len(deleted_files) + ) self.assertEqual(len(index.entries), 0) # reset the index to undo our changes @@ -475,13 +492,17 @@ class TestIndex(TestBase): # reset everything index.reset(working_tree=True) - self.assertEqual(self._count_existing(rw_repo, deleted_files), len(deleted_files)) + self.assertEqual( + self._count_existing(rw_repo, deleted_files), len(deleted_files) + ) # invalid type self.assertRaises(TypeError, index.remove, [1]) # absolute path - deleted_files = index.remove([osp.join(rw_repo.working_tree_dir, "lib")], r=True) + deleted_files = index.remove( + [osp.join(rw_repo.working_tree_dir, "lib")], r=True + ) assert len(deleted_files) > 1 self.assertRaises(ValueError, index.remove, ["/doesnt/exists"]) @@ -506,7 +527,9 @@ class TestIndex(TestBase): my_author = Actor("Frèderic Çaufl€", "author@example.com") my_committer = Actor("Committing Frèderic Çaufl€", "committer@example.com") - commit_actor = index.commit(commit_message, author=my_author, committer=my_committer) + commit_actor = index.commit( + commit_message, author=my_author, committer=my_committer + ) assert cur_commit != commit_actor self.assertEqual(commit_actor.author.name, "Frèderic Çaufl€") self.assertEqual(commit_actor.author.email, "author@example.com") @@ -522,7 +545,11 @@ class TestIndex(TestBase): cur_commit = cur_head.commit commit_message = "commit with dates by Avinash Sajjanshetty" - new_commit = index.commit(commit_message, author_date="2006-04-07T22:13:13", commit_date="2005-04-07T22:13:13") + new_commit = index.commit( + commit_message, + author_date="2006-04-07T22:13:13", + commit_date="2005-04-07T22:13:13", + ) assert cur_commit != new_commit print(new_commit.authored_date, new_commit.committed_date) self.assertEqual(new_commit.message, commit_message) @@ -538,7 +565,9 @@ class TestIndex(TestBase): # same index, multiple parents commit_message = "Index with multiple parents\n commit with another line" - commit_multi_parent = index.commit(commit_message, parent_commits=(commit_no_parents, new_commit)) + commit_multi_parent = index.commit( + commit_message, parent_commits=(commit_no_parents, new_commit) + ) self.assertEqual(commit_multi_parent.message, commit_message) self.assertEqual(len(commit_multi_parent.parents), 2) self.assertEqual(commit_multi_parent.parents[0], commit_no_parents) @@ -547,26 +576,32 @@ class TestIndex(TestBase): # re-add all files in lib # get the lib folder back on disk, but get an index without it - index.reset(new_commit.parents[0], working_tree=True).reset(new_commit, working_tree=False) + index.reset(new_commit.parents[0], working_tree=True).reset( + new_commit, working_tree=False + ) lib_file_path = osp.join("lib", "git", "__init__.py") assert (lib_file_path, 0) not in index.entries assert osp.isfile(osp.join(rw_repo.working_tree_dir, lib_file_path)) # directory - entries = index.add(['lib'], fprogress=self._fprogress_add) + entries = index.add(["lib"], fprogress=self._fprogress_add) self._assert_entries(entries) self._assert_fprogress(entries) assert len(entries) > 1 # glob - entries = index.reset(new_commit).add([osp.join('lib', 'git', '*.py')], fprogress=self._fprogress_add) + entries = index.reset(new_commit).add( + [osp.join("lib", "git", "*.py")], fprogress=self._fprogress_add + ) self._assert_entries(entries) self._assert_fprogress(entries) self.assertEqual(len(entries), 14) # same file entries = index.reset(new_commit).add( - [osp.join(rw_repo.working_tree_dir, 'lib', 'git', 'head.py')] * 2, fprogress=self._fprogress_add) + [osp.join(rw_repo.working_tree_dir, "lib", "git", "head.py")] * 2, + fprogress=self._fprogress_add, + ) self._assert_entries(entries) self.assertEqual(entries[0].mode & 0o644, 0o644) # would fail, test is too primitive to handle this case @@ -575,7 +610,9 @@ class TestIndex(TestBase): self.assertEqual(len(entries), 2) # missing path - self.assertRaises(OSError, index.reset(new_commit).add, ['doesnt/exist/must/raise']) + self.assertRaises( + OSError, index.reset(new_commit).add, ["doesnt/exist/must/raise"] + ) # blob from older revision overrides current index revision old_blob = new_commit.parents[0].tree.blobs[0] @@ -588,14 +625,19 @@ class TestIndex(TestBase): # mode 0 not allowed null_hex_sha = Diff.NULL_HEX_SHA null_bin_sha = b"\0" * 20 - self.assertRaises(ValueError, index.reset( - new_commit).add, [BaseIndexEntry((0, null_bin_sha, 0, "doesntmatter"))]) + self.assertRaises( + ValueError, + index.reset(new_commit).add, + [BaseIndexEntry((0, null_bin_sha, 0, "doesntmatter"))], + ) # add new file new_file_relapath = "my_new_file" self._make_file(new_file_relapath, "hello world", rw_repo) entries = index.reset(new_commit).add( - [BaseIndexEntry((0o10644, null_bin_sha, 0, new_file_relapath))], fprogress=self._fprogress_add) + [BaseIndexEntry((0o10644, null_bin_sha, 0, new_file_relapath))], + fprogress=self._fprogress_add, + ) self._assert_entries(entries) self._assert_fprogress(entries) self.assertEqual(len(entries), 1) @@ -603,20 +645,27 @@ class TestIndex(TestBase): # add symlink if not is_win: - for target in ('/etc/nonexisting', '/etc/passwd', '/etc'): + for target in ("/etc/nonexisting", "/etc/passwd", "/etc"): basename = "my_real_symlink" link_file = osp.join(rw_repo.working_tree_dir, basename) os.symlink(target, link_file) - entries = index.reset(new_commit).add([link_file], fprogress=self._fprogress_add) + entries = index.reset(new_commit).add( + [link_file], fprogress=self._fprogress_add + ) self._assert_entries(entries) self._assert_fprogress(entries) self.assertEqual(len(entries), 1) self.assertTrue(S_ISLNK(entries[0].mode)) - self.assertTrue(S_ISLNK(index.entries[index.entry_key("my_real_symlink", 0)].mode)) + self.assertTrue( + S_ISLNK(index.entries[index.entry_key("my_real_symlink", 0)].mode) + ) # we expect only the target to be written - self.assertEqual(index.repo.odb.stream(entries[0].binsha).read().decode('ascii'), target) + self.assertEqual( + index.repo.odb.stream(entries[0].binsha).read().decode("ascii"), + target, + ) os.remove(link_file) # end for each target @@ -627,7 +676,9 @@ class TestIndex(TestBase): link_target = "/etc/that" fake_symlink_path = self._make_file(fake_symlink_relapath, link_target, rw_repo) fake_entry = BaseIndexEntry((0o120000, null_bin_sha, 0, fake_symlink_relapath)) - entries = index.reset(new_commit).add([fake_entry], fprogress=self._fprogress_add) + entries = index.reset(new_commit).add( + [fake_entry], fprogress=self._fprogress_add + ) self._assert_entries(entries) self._assert_fprogress(entries) assert entries[0].hexsha != null_hex_sha @@ -635,7 +686,9 @@ class TestIndex(TestBase): self.assertTrue(S_ISLNK(entries[0].mode)) # assure this also works with an alternate method - full_index_entry = IndexEntry.from_base(BaseIndexEntry((0o120000, entries[0].binsha, 0, entries[0].path))) + full_index_entry = IndexEntry.from_base( + BaseIndexEntry((0o120000, entries[0].binsha, 0, entries[0].path)) + ) entry_key = index.entry_key(full_index_entry) index.reset(new_commit) @@ -649,7 +702,7 @@ class TestIndex(TestBase): # a tree created from this should contain the symlink tree = index.write_tree() assert fake_symlink_relapath in tree - index.write() # flush our changes for the checkout + index.write() # flush our changes for the checkout # checkout the fakelink, should be a link then assert not S_ISLNK(os.stat(fake_symlink_path)[ST_MODE]) @@ -660,7 +713,7 @@ class TestIndex(TestBase): if is_win: # simlinks should contain the link as text ( which is what a # symlink actually is ) - with open(fake_symlink_path, 'rt') as fd: + with open(fake_symlink_path, "rt") as fd: self.assertEqual(fd.read(), link_target) else: self.assertTrue(S_ISLNK(os.lstat(fake_symlink_path)[ST_MODE])) @@ -670,18 +723,19 @@ class TestIndex(TestBase): for source, dest in rval: assert not osp.exists(source) and osp.exists(dest) # END for each renamed item + # END move assertion utility - self.assertRaises(ValueError, index.move, ['just_one_path']) + self.assertRaises(ValueError, index.move, ["just_one_path"]) # file onto existing file - files = ['AUTHORS', 'LICENSE'] + files = ["AUTHORS", "LICENSE"] self.assertRaises(GitCommandError, index.move, files) # again, with force assert_mv_rval(index.move(files, f=True)) # files into directory - dry run - paths = ['LICENSE', 'VERSION', 'doc'] + paths = ["LICENSE", "VERSION", "doc"] rval = index.move(paths, dry_run=True) self.assertEqual(len(rval), 2) assert osp.exists(paths[0]) @@ -691,7 +745,7 @@ class TestIndex(TestBase): assert_mv_rval(rval) # dir into dir - rval = index.move(['doc', 'test']) + rval = index.move(["doc", "test"]) assert_mv_rval(rval) # TEST PATH REWRITING @@ -702,21 +756,23 @@ class TestIndex(TestBase): rval = str(count[0]) count[0] += 1 return rval + # END rewriter def make_paths(): # two existing ones, one new one - yield 'CHANGES' - yield 'ez_setup.py' - yield index.entries[index.entry_key('README', 0)] - yield index.entries[index.entry_key('.gitignore', 0)] + yield "CHANGES" + yield "ez_setup.py" + yield index.entries[index.entry_key("README", 0)] + yield index.entries[index.entry_key(".gitignore", 0)] for fid in range(3): - fname = 'newfile%i' % fid - with open(fname, 'wb') as fd: + fname = "newfile%i" % fid + with open(fname, "wb") as fd: fd.write(b"abcd") yield Blob(rw_repo, Blob.NULL_BIN_SHA, 0o100644, fname) # END for each new file + # END path producer paths = list(make_paths()) self._assert_entries(index.add(paths, path_rewriter=rewriter)) @@ -762,7 +818,7 @@ class TestIndex(TestBase): for absfile in absfiles: assert osp.isfile(absfile) - @with_rw_repo('HEAD') + @with_rw_repo("HEAD") def test_compare_write_tree(self, rw_repo): # write all trees and compare them # its important to have a few submodules in there too @@ -776,16 +832,16 @@ class TestIndex(TestBase): orig_tree = commit.tree self.assertEqual(index.write_tree(), orig_tree) # END for each commit - - @with_rw_repo('HEAD', bare=False) + + @with_rw_repo("HEAD", bare=False) def test_index_single_addremove(self, rw_repo): - fp = osp.join(rw_repo.working_dir, 'testfile.txt') - with open(fp, 'w') as fs: - fs.write('content of testfile') + fp = osp.join(rw_repo.working_dir, "testfile.txt") + with open(fp, "w") as fs: + fs.write("content of testfile") self._assert_entries(rw_repo.index.add(fp)) deleted_files = rw_repo.index.remove(fp) assert deleted_files - + def test_index_new(self): B = self.rorepo.tree("6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e") H = self.rorepo.tree("25dca42bac17d511b7e2ebdd9d1d679e7626db5f") @@ -796,7 +852,7 @@ class TestIndex(TestBase): assert isinstance(index, IndexFile) # END for each arg tuple - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_index_bare_add(self, rw_bare_repo): # Something is wrong after cloning to a bare repo, reading the # property rw_bare_repo.working_tree_dir will return '/tmp' @@ -804,12 +860,11 @@ class TestIndex(TestBase): # a quick hack to make this test fail when expected. assert rw_bare_repo.working_tree_dir is None assert rw_bare_repo.bare - contents = b'This is a BytesIO file' + contents = b"This is a BytesIO file" filesize = len(contents) fileobj = BytesIO(contents) - filename = 'my-imaginary-file' - istream = rw_bare_repo.odb.store( - IStream(Blob.type, filesize, fileobj)) + filename = "my-imaginary-file" + istream = rw_bare_repo.odb.store(IStream(Blob.type, filesize, fileobj)) entry = BaseIndexEntry((0o100644, istream.binsha, 0, filename)) try: rw_bare_repo.index.add([entry]) @@ -818,7 +873,7 @@ class TestIndex(TestBase): # Adding using a path should still require a non-bare repository. asserted = False - path = osp.join('git', 'test', 'test_index.py') + path = osp.join("git", "test", "test_index.py") try: rw_bare_repo.index.add([path]) except InvalidGitRepositoryError: @@ -828,24 +883,24 @@ class TestIndex(TestBase): @with_rw_directory def test_add_utf8P_path(self, rw_dir): # NOTE: fp is not a Unicode object in python 2 (which is the source of the problem) - fp = osp.join(rw_dir, 'ø.txt') - with open(fp, 'wb') as fs: - fs.write('content of ø'.encode('utf-8')) + fp = osp.join(rw_dir, "ø.txt") + with open(fp, "wb") as fs: + fs.write("content of ø".encode("utf-8")) r = Repo.init(rw_dir) r.index.add([fp]) - r.index.commit('Added orig and prestable') + r.index.commit("Added orig and prestable") @with_rw_directory def test_add_a_file_with_wildcard_chars(self, rw_dir): # see issue #407 - fp = osp.join(rw_dir, '[.exe') + fp = osp.join(rw_dir, "[.exe") with open(fp, "wb") as f: - f.write(b'something') + f.write(b"something") r = Repo.init(rw_dir) r.index.add([fp]) - r.index.commit('Added [.exe') + r.index.commit("Added [.exe") def test__to_relative_path_at_root(self): root = osp.abspath(os.sep) @@ -856,29 +911,23 @@ class TestIndex(TestBase): working_tree_dir = root repo = Mocked() - path = os.path.join(root, 'file') + path = os.path.join(root, "file") index = IndexFile(repo) rel = index._to_relative_path(path) self.assertEqual(rel, os.path.relpath(path, root)) - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_pre_commit_hook_success(self, rw_repo): index = rw_repo.index - _make_hook( - index.repo.git_dir, - 'pre-commit', - "exit 0" - ) + _make_hook(index.repo.git_dir, "pre-commit", "exit 0") index.commit("This should not fail") - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_pre_commit_hook_fail(self, rw_repo): index = rw_repo.index hp = _make_hook( - index.repo.git_dir, - 'pre-commit', - "echo stdout; echo stderr 1>&2; exit 1" + index.repo.git_dir, "pre-commit", "echo stdout; echo stderr 1>&2; exit 1" ) try: index.commit("This should fail") @@ -886,8 +935,8 @@ class TestIndex(TestBase): if is_win_without_bash: self.assertIsInstance(err.status, OSError) self.assertEqual(err.command, [hp]) - self.assertEqual(err.stdout, '') - self.assertEqual(err.stderr, '') + self.assertEqual(err.stdout, "") + self.assertEqual(err.stderr, "") assert str(err) else: self.assertEqual(err.status, 1) @@ -899,26 +948,26 @@ class TestIndex(TestBase): raise AssertionError("Should have caught a HookExecutionError") @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, "TODO: fix hooks execution on Windows: #703") - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_commit_msg_hook_success(self, rw_repo): commit_message = "commit default head by Frèderic Çaufl€" from_hook_message = "from commit-msg" index = rw_repo.index _make_hook( index.repo.git_dir, - 'commit-msg', - 'printf " {}" >> "$1"'.format(from_hook_message) + "commit-msg", + 'printf " {}" >> "$1"'.format(from_hook_message), ) new_commit = index.commit(commit_message) - self.assertEqual(new_commit.message, "{} {}".format(commit_message, from_hook_message)) + self.assertEqual( + new_commit.message, "{} {}".format(commit_message, from_hook_message) + ) - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_commit_msg_hook_fail(self, rw_repo): index = rw_repo.index hp = _make_hook( - index.repo.git_dir, - 'commit-msg', - "echo stdout; echo stderr 1>&2; exit 1" + index.repo.git_dir, "commit-msg", "echo stdout; echo stderr 1>&2; exit 1" ) try: index.commit("This should fail") @@ -926,8 +975,8 @@ class TestIndex(TestBase): if is_win_without_bash: self.assertIsInstance(err.status, OSError) self.assertEqual(err.command, [hp]) - self.assertEqual(err.stdout, '') - self.assertEqual(err.stderr, '') + self.assertEqual(err.stdout, "") + self.assertEqual(err.stderr, "") assert str(err) else: self.assertEqual(err.status, 1) diff --git a/test/test_installation.py b/test/test_installation.py index 6117be98..2607ff4e 100644 --- a/test/test_installation.py +++ b/test/test_installation.py @@ -11,9 +11,9 @@ from test.lib.helper import with_rw_directory class TestInstallation(TestBase): def setUp_venv(self, rw_dir): self.venv = rw_dir - subprocess.run(['virtualenv', self.venv], stdout=subprocess.PIPE) - self.python = os.path.join(self.venv, 'bin/python3') - self.pip = os.path.join(self.venv, 'bin/pip3') + subprocess.run(["virtualenv", self.venv], stdout=subprocess.PIPE) + self.python = os.path.join(self.venv, "bin/python3") + self.pip = os.path.join(self.venv, "bin/pip3") self.sources = os.path.join(self.venv, "src") self.cwd = os.path.dirname(os.path.dirname(__file__)) os.symlink(self.cwd, self.sources, target_is_directory=True) @@ -21,17 +21,46 @@ class TestInstallation(TestBase): @with_rw_directory def test_installation(self, rw_dir): self.setUp_venv(rw_dir) - result = subprocess.run([self.pip, 'install', '-r', 'requirements.txt'], - stdout=subprocess.PIPE, cwd=self.sources) - self.assertEqual(0, result.returncode, msg=result.stderr or result.stdout or "Can't install requirements") - result = subprocess.run([self.python, 'setup.py', 'install'], stdout=subprocess.PIPE, cwd=self.sources) - self.assertEqual(0, result.returncode, msg=result.stderr or result.stdout or "Can't build - setup.py failed") - result = subprocess.run([self.python, '-c', 'import git'], stdout=subprocess.PIPE, cwd=self.sources) - self.assertEqual(0, result.returncode, msg=result.stderr or result.stdout or "Selftest failed") - result = subprocess.run([self.python, '-c', 'import sys;import git; print(sys.path)'], - stdout=subprocess.PIPE, cwd=self.sources) - syspath = result.stdout.decode('utf-8').splitlines()[0] + result = subprocess.run( + [self.pip, "install", "-r", "requirements.txt"], + stdout=subprocess.PIPE, + cwd=self.sources, + ) + self.assertEqual( + 0, + result.returncode, + msg=result.stderr or result.stdout or "Can't install requirements", + ) + result = subprocess.run( + [self.python, "setup.py", "install"], + stdout=subprocess.PIPE, + cwd=self.sources, + ) + self.assertEqual( + 0, + result.returncode, + msg=result.stderr or result.stdout or "Can't build - setup.py failed", + ) + result = subprocess.run( + [self.python, "-c", "import git"], stdout=subprocess.PIPE, cwd=self.sources + ) + self.assertEqual( + 0, + result.returncode, + msg=result.stderr or result.stdout or "Selftest failed", + ) + result = subprocess.run( + [self.python, "-c", "import sys;import git; print(sys.path)"], + stdout=subprocess.PIPE, + cwd=self.sources, + ) + syspath = result.stdout.decode("utf-8").splitlines()[0] syspath = ast.literal_eval(syspath) - self.assertEqual('', syspath[0], - msg='Failed to follow the conventions for https://docs.python.org/3/library/sys.html#sys.path') - self.assertTrue(syspath[1].endswith('gitdb'), msg='Failed to add gitdb to sys.path') + self.assertEqual( + "", + syspath[0], + msg="Failed to follow the conventions for https://docs.python.org/3/library/sys.html#sys.path", + ) + self.assertTrue( + syspath[1].endswith("gitdb"), msg="Failed to add gitdb to sys.path" + ) diff --git a/test/test_reflog.py b/test/test_reflog.py index a6c15950..c126d3dc 100644 --- a/test/test_reflog.py +++ b/test/test_reflog.py @@ -2,28 +2,23 @@ import os import tempfile from git.objects import IndexObject -from git.refs import ( - RefLogEntry, - RefLog -) -from test.lib import ( - TestBase, - fixture_path -) +from git.refs import RefLogEntry, RefLog +from test.lib import TestBase, fixture_path from git.util import Actor, rmtree, hex_to_bin import os.path as osp class TestRefLog(TestBase): - def test_reflogentry(self): nullhexsha = IndexObject.NULL_HEX_SHA - hexsha = 'F' * 40 - actor = Actor('name', 'email') + hexsha = "F" * 40 + actor = Actor("name", "email") msg = "message" - self.assertRaises(ValueError, RefLogEntry.new, nullhexsha, hexsha, 'noactor', 0, 0, "") + self.assertRaises( + ValueError, RefLogEntry.new, nullhexsha, hexsha, "noactor", 0, 0, "" + ) e = RefLogEntry.new(nullhexsha, hexsha, actor, 0, 1, msg) assert e.oldhexsha == nullhexsha @@ -37,8 +32,8 @@ class TestRefLog(TestBase): assert repr(e).startswith(nullhexsha) def test_base(self): - rlp_head = fixture_path('reflog_HEAD') - rlp_master = fixture_path('reflog_master') + rlp_head = fixture_path("reflog_HEAD") + rlp_master = fixture_path("reflog_master") tdir = tempfile.mktemp(suffix="test_reflogs") os.mkdir(tdir) @@ -52,13 +47,13 @@ class TestRefLog(TestBase): assert len(reflog) # iter_entries works with path and with stream - assert len(list(RefLog.iter_entries(open(rlp_master, 'rb')))) + assert len(list(RefLog.iter_entries(open(rlp_master, "rb")))) assert len(list(RefLog.iter_entries(rlp_master))) # raise on invalid revlog # TODO: Try multiple corrupted ones ! - pp = 'reflog_invalid_' - for suffix in ('oldsha', 'newsha', 'email', 'date', 'sep'): + pp = "reflog_invalid_" + for suffix in ("oldsha", "newsha", "email", "date", "sep"): self.assertRaises(ValueError, RefLog.from_file, fixture_path(pp + suffix)) # END for each invalid file @@ -66,7 +61,7 @@ class TestRefLog(TestBase): self.assertRaises(ValueError, RefLog().write) # test serialize and deserialize - results must match exactly - binsha = hex_to_bin(('f' * 40).encode('ascii')) + binsha = hex_to_bin(("f" * 40).encode("ascii")) msg = "my reflog message" cr = self.rorepo.config_reader() for rlp in (rlp_head, rlp_master): @@ -83,9 +78,11 @@ class TestRefLog(TestBase): assert open(tfile).read() == open(rlp).read() # append an entry - entry = RefLog.append_entry(cr, tfile, IndexObject.NULL_BIN_SHA, binsha, msg) + entry = RefLog.append_entry( + cr, tfile, IndexObject.NULL_BIN_SHA, binsha, msg + ) assert entry.oldhexsha == IndexObject.NULL_HEX_SHA - assert entry.newhexsha == 'f' * 40 + assert entry.newhexsha == "f" * 40 assert entry.message == msg assert RefLog.from_file(tfile)[-1] == entry diff --git a/test/test_refs.py b/test/test_refs.py index ab760a6f..ee4ec86f 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -14,13 +14,10 @@ from git import ( Commit, SymbolicReference, GitCommandError, - RefLog + RefLog, ) from git.objects.tag import TagObject -from test.lib import ( - TestBase, - with_rw_repo -) +from test.lib import TestBase, with_rw_repo from git.util import Actor import git.refs as refs @@ -28,11 +25,10 @@ import os.path as osp class TestRefs(TestBase): - def test_from_path(self): # should be able to create any reference directly for ref_type in (Reference, Head, TagReference, RemoteReference): - for name in ('rela_name', 'path/rela_name'): + for name in ("rela_name", "path/rela_name"): full_path = ref_type.to_full_path(name) instance = ref_type.from_path(self.rorepo, full_path) assert isinstance(instance, ref_type) @@ -54,7 +50,7 @@ class TestRefs(TestBase): tag_object_refs.append(tag) tagobj = tag.tag # have no dict - self.assertRaises(AttributeError, setattr, tagobj, 'someattr', 1) + self.assertRaises(AttributeError, setattr, tagobj, "someattr", 1) assert isinstance(tagobj, TagObject) assert tagobj.tag == tag.name assert isinstance(tagobj.tagger, Actor) @@ -63,18 +59,18 @@ class TestRefs(TestBase): assert tagobj.message assert tag.object == tagobj # can't assign the object - self.assertRaises(AttributeError, setattr, tag, 'object', tagobj) + self.assertRaises(AttributeError, setattr, tag, "object", tagobj) # END if we have a tag object # END for tag in repo-tags assert tag_object_refs - assert isinstance(self.rorepo.tags['0.1.5'], TagReference) + assert isinstance(self.rorepo.tags["0.1.5"], TagReference) def test_tags_author(self): tag = self.rorepo.tags[0] tagobj = tag.tag assert isinstance(tagobj.tagger, Actor) tagger_name = tagobj.tagger.name - assert tagger_name == 'Michael Trier' + assert tagger_name == "Michael Trier" def test_tags(self): # tag refs can point to tag objects or to commits @@ -92,7 +88,7 @@ class TestRefs(TestBase): assert len(s) == ref_count assert len(s | s) == ref_count - @with_rw_repo('HEAD', bare=False) + @with_rw_repo("HEAD", bare=False) def test_heads(self, rwrepo): for head in rwrepo.heads: assert head.name @@ -100,8 +96,8 @@ class TestRefs(TestBase): assert "refs/heads" in head.path prev_object = head.object cur_object = head.object - assert prev_object == cur_object # represent the same git object - assert prev_object is not cur_object # but are different instances + assert prev_object == cur_object # represent the same git object + assert prev_object is not cur_object # but are different instances with head.config_writer() as writer: tv = "testopt" @@ -120,17 +116,23 @@ class TestRefs(TestBase): head.set_tracking_branch(None) assert head.tracking_branch() is None - special_name = 'feature#123' - special_name_remote_ref = SymbolicReference.create(rwrepo, 'refs/remotes/origin/%s' % special_name) - gp_tracking_branch = rwrepo.create_head('gp_tracking#123') - special_name_remote_ref = rwrepo.remotes[0].refs[special_name] # get correct type + special_name = "feature#123" + special_name_remote_ref = SymbolicReference.create( + rwrepo, "refs/remotes/origin/%s" % special_name + ) + gp_tracking_branch = rwrepo.create_head("gp_tracking#123") + special_name_remote_ref = rwrepo.remotes[0].refs[ + special_name + ] # get correct type gp_tracking_branch.set_tracking_branch(special_name_remote_ref) TBranch = gp_tracking_branch.tracking_branch() if TBranch is not None: assert TBranch.path == special_name_remote_ref.path - git_tracking_branch = rwrepo.create_head('git_tracking#123') - rwrepo.git.branch('-u', special_name_remote_ref.name, git_tracking_branch.name) + git_tracking_branch = rwrepo.create_head("git_tracking#123") + rwrepo.git.branch( + "-u", special_name_remote_ref.name, git_tracking_branch.name + ) TBranch = gp_tracking_branch.tracking_branch() if TBranch is not None: assert TBranch.name == special_name_remote_ref.name @@ -143,7 +145,7 @@ class TestRefs(TestBase): pcommit = cur_head.commit.parents[0].parents[0] hlog_len = len(head.log()) blog_len = len(cur_head.log()) - assert head.set_reference(pcommit, 'detached head') is head + assert head.set_reference(pcommit, "detached head") is head # one new log-entry thlog = head.log() assert len(thlog) == hlog_len + 1 @@ -154,23 +156,25 @@ class TestRefs(TestBase): assert len(cur_head.log()) == blog_len # head changes once again, cur_head doesn't change - head.set_reference(cur_head, 'reattach head') + head.set_reference(cur_head, "reattach head") assert len(head.log()) == hlog_len + 2 assert len(cur_head.log()) == blog_len # adjusting the head-ref also adjust the head, so both reflogs are # altered - cur_head.set_commit(pcommit, 'changing commit') + cur_head.set_commit(pcommit, "changing commit") assert len(cur_head.log()) == blog_len + 1 assert len(head.log()) == hlog_len + 3 # with automatic dereferencing - assert head.set_commit(cur_commit, 'change commit once again') is head + assert head.set_commit(cur_commit, "change commit once again") is head assert len(head.log()) == hlog_len + 4 assert len(cur_head.log()) == blog_len + 2 # a new branch has just a single entry - other_head = Head.create(rwrepo, 'mynewhead', pcommit, logmsg='new head created') + other_head = Head.create( + rwrepo, "mynewhead", pcommit, logmsg="new head created" + ) log = other_head.log() assert len(log) == 1 assert log[0].oldhexsha == pcommit.NULL_HEX_SHA @@ -183,21 +187,21 @@ class TestRefs(TestBase): assert len(types_found) >= 3 def test_is_valid(self): - assert not Reference(self.rorepo, 'refs/doesnt/exist').is_valid() + assert not Reference(self.rorepo, "refs/doesnt/exist").is_valid() assert self.rorepo.head.is_valid() assert self.rorepo.head.reference.is_valid() - assert not SymbolicReference(self.rorepo, 'hellothere').is_valid() + assert not SymbolicReference(self.rorepo, "hellothere").is_valid() def test_orig_head(self): assert type(self.rorepo.head.orig_head()) == SymbolicReference - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_head_checkout_detached_head(self, rw_repo): res = rw_repo.remotes.origin.refs.master.checkout() assert isinstance(res, SymbolicReference) - assert res.name == 'HEAD' + assert res.name == "HEAD" - @with_rw_repo('0.1.6') + @with_rw_repo("0.1.6") def test_head_reset(self, rw_repo): cur_head = rw_repo.head old_head_commit = cur_head.commit @@ -205,7 +209,9 @@ class TestRefs(TestBase): cur_head.reset(new_head_commit, index=True) # index only assert cur_head.reference.commit == new_head_commit - self.assertRaises(ValueError, cur_head.reset, new_head_commit, index=False, working_tree=True) + self.assertRaises( + ValueError, cur_head.reset, new_head_commit, index=False, working_tree=True + ) new_head_commit = new_head_commit.parents[0] cur_head.reset(new_head_commit, index=True, working_tree=True) # index + wt assert cur_head.reference.commit == new_head_commit @@ -215,7 +221,13 @@ class TestRefs(TestBase): cur_head.reset(cur_head, paths="test") cur_head.reset(new_head_commit, paths="lib") # hard resets with paths don't work, its all or nothing - self.assertRaises(GitCommandError, cur_head.reset, new_head_commit, working_tree=True, paths="lib") + self.assertRaises( + GitCommandError, + cur_head.reset, + new_head_commit, + working_tree=True, + paths="lib", + ) # we can do a mixed reset, and then checkout from the index though cur_head.reset(new_head_commit) @@ -255,7 +267,7 @@ class TestRefs(TestBase): self.assertRaises(ValueError, setattr, cur_head, "reference", "that") # head handling - commit = 'HEAD' + commit = "HEAD" prev_head_commit = cur_head.commit for count, new_name in enumerate(("my_new_head", "feature/feature1")): actual_commit = commit + "^" * count @@ -267,7 +279,9 @@ class TestRefs(TestBase): Head.create(rw_repo, new_name, new_head.commit) # its not fine with a different value - self.assertRaises(OSError, Head.create, rw_repo, new_name, new_head.commit.parents[0]) + self.assertRaises( + OSError, Head.create, rw_repo, new_name, new_head.commit.parents[0] + ) # force it new_head = Head.create(rw_repo, new_name, actual_commit, force=True) @@ -276,7 +290,9 @@ class TestRefs(TestBase): assert new_head.rename("hello").name == "hello" assert new_head.rename("hello/world").name == "hello/world" - assert new_head.rename(old_name).name == old_name and new_head.path == old_path + assert ( + new_head.rename(old_name).name == old_name and new_head.path == old_path + ) # rename with force tmp_head = Head.create(rw_repo, "tmphead") @@ -330,7 +346,7 @@ class TestRefs(TestBase): remote_head_name = "HEAD" if remote_head_name in refs: RemoteReference.delete(rw_repo, refs[remote_head_name]) - del(refs[remote_head_name]) + del refs[remote_head_name] # END handle HEAD deletion RemoteReference.delete(rw_repo, *refs) @@ -358,13 +374,13 @@ class TestRefs(TestBase): # setting a non-commit as commit fails, but succeeds as object head_tree = head.commit.tree - self.assertRaises(ValueError, setattr, head, 'commit', head_tree) - assert head.commit == old_commit # and the ref did not change + self.assertRaises(ValueError, setattr, head, "commit", head_tree) + assert head.commit == old_commit # and the ref did not change # we allow heds to point to any object head.object = head_tree assert head.object == head_tree # cannot query tree as commit - self.assertRaises(TypeError, getattr, head, 'commit') + self.assertRaises(TypeError, getattr, head, "commit") # set the commit directly using the head. This would never detach the head assert not cur_head.is_detached @@ -396,25 +412,25 @@ class TestRefs(TestBase): # checkout with force as we have a changed a file # clear file - open(new_head.commit.tree.blobs[-1].abspath, 'w').close() + open(new_head.commit.tree.blobs[-1].abspath, "w").close() assert len(new_head.commit.diff(None)) # create a new branch that is likely to touch the file we changed - far_away_head = rw_repo.create_head("far_head", 'HEAD~100') + far_away_head = rw_repo.create_head("far_head", "HEAD~100") self.assertRaises(GitCommandError, far_away_head.checkout) assert active_branch == active_branch.checkout(force=True) assert rw_repo.head.reference != far_away_head # test reference creation - partial_ref = 'sub/ref' - full_ref = 'refs/%s' % partial_ref + partial_ref = "sub/ref" + full_ref = "refs/%s" % partial_ref ref = Reference.create(rw_repo, partial_ref) assert ref.path == full_ref assert ref.object == rw_repo.head.commit - self.assertRaises(OSError, Reference.create, rw_repo, full_ref, 'HEAD~20') + self.assertRaises(OSError, Reference.create, rw_repo, full_ref, "HEAD~20") # it works if it is at the same spot though and points to the same reference - assert Reference.create(rw_repo, full_ref, 'HEAD').path == full_ref + assert Reference.create(rw_repo, full_ref, "HEAD").path == full_ref Reference.delete(rw_repo, full_ref) # recreate the reference using a full_ref @@ -423,13 +439,13 @@ class TestRefs(TestBase): assert ref.object == rw_repo.head.commit # recreate using force - ref = Reference.create(rw_repo, partial_ref, 'HEAD~1', force=True) + ref = Reference.create(rw_repo, partial_ref, "HEAD~1", force=True) assert ref.path == full_ref assert ref.object == rw_repo.head.commit.parents[0] # rename it orig_obj = ref.object - for name in ('refs/absname', 'rela_name', 'feature/rela_name'): + for name in ("refs/absname", "rela_name", "feature/rela_name"): ref_new_name = ref.rename(name) assert isinstance(ref_new_name, Reference) assert name in ref_new_name.path @@ -438,7 +454,9 @@ class TestRefs(TestBase): # END for each name type # References that don't exist trigger an error if we want to access them - self.assertRaises(ValueError, getattr, Reference(rw_repo, "refs/doesntexist"), 'commit') + self.assertRaises( + ValueError, getattr, Reference(rw_repo, "refs/doesntexist"), "commit" + ) # exists, fail unless we force ex_ref_path = far_away_head.path @@ -455,9 +473,18 @@ class TestRefs(TestBase): assert symref.path == symref_path assert symref.reference == cur_head.reference - self.assertRaises(OSError, SymbolicReference.create, rw_repo, symref_path, cur_head.reference.commit) + self.assertRaises( + OSError, + SymbolicReference.create, + rw_repo, + symref_path, + cur_head.reference.commit, + ) # it works if the new ref points to the same reference - assert SymbolicReference.create(rw_repo, symref.path, symref.reference).path == symref.path # @NoEffect + assert ( + SymbolicReference.create(rw_repo, symref.path, symref.reference).path + == symref.path + ) # @NoEffect SymbolicReference.delete(rw_repo, symref) # would raise if the symref wouldn't have been deletedpbl symref = SymbolicReference.create(rw_repo, symref_path, cur_head.reference) @@ -475,7 +502,7 @@ class TestRefs(TestBase): assert osp.isfile(symbol_ref_abspath) assert symref.commit == new_head.commit - for name in ('absname', 'folder/rela_name'): + for name in ("absname", "folder/rela_name"): symref_new_name = symref.rename(name) assert isinstance(symref_new_name, SymbolicReference) assert name in symref_new_name.path @@ -524,7 +551,7 @@ class TestRefs(TestBase): rw_repo.head.reference = Head.create(rw_repo, "master") # At least the head should still exist - assert osp.isfile(osp.join(rw_repo.git_dir, 'HEAD')) + assert osp.isfile(osp.join(rw_repo.git_dir, "HEAD")) refs = list(SymbolicReference.iter_items(rw_repo)) assert len(refs) == 1 @@ -545,7 +572,7 @@ class TestRefs(TestBase): # if the assignment raises, the ref doesn't exist Reference.delete(ref.repo, ref.path) assert not ref.is_valid() - self.assertRaises(ValueError, setattr, ref, 'commit', "nonsense") + self.assertRaises(ValueError, setattr, ref, "commit", "nonsense") assert not ref.is_valid() # I am sure I had my reason to make it a class method at first, but @@ -559,14 +586,14 @@ class TestRefs(TestBase): Reference.delete(ref.repo, ref.path) assert not ref.is_valid() - self.assertRaises(ValueError, setattr, ref, 'object', "nonsense") + self.assertRaises(ValueError, setattr, ref, "object", "nonsense") assert not ref.is_valid() # END for each path def test_dereference_recursive(self): # for now, just test the HEAD - assert SymbolicReference.dereference_recursive(self.rorepo, 'HEAD') + assert SymbolicReference.dereference_recursive(self.rorepo, "HEAD") def test_reflog(self): assert isinstance(self.rorepo.heads.master.log(), RefLog) diff --git a/test/test_remote.py b/test/test_remote.py index 761a7a3e..53f71e3d 100644 --- a/test/test_remote.py +++ b/test/test_remote.py @@ -20,7 +20,7 @@ from git import ( RemoteReference, TagReference, Remote, - GitCommandError + GitCommandError, ) from git.cmd import Git from test.lib import ( @@ -28,7 +28,7 @@ from test.lib import ( with_rw_repo, with_rw_and_rw_remote_repo, fixture, - GIT_DAEMON_PORT + GIT_DAEMON_PORT, ) from git.util import rmtree, HIDE_WINDOWS_FREEZE_ERRORS, IterableList import os.path as osp @@ -39,7 +39,7 @@ random.seed(0) class TestRemoteProgress(RemoteProgress): - __slots__ = ("_seen_lines", "_stages_per_op", '_num_progress_messages') + __slots__ = ("_seen_lines", "_stages_per_op", "_num_progress_messages") def __init__(self): super(TestRemoteProgress, self).__init__() @@ -60,21 +60,27 @@ class TestRemoteProgress(RemoteProgress): except ValueError: pass - def update(self, op_code, cur_count, max_count=None, message=''): + def update(self, op_code, cur_count, max_count=None, message=""): # check each stage only comes once op_id = op_code & self.OP_MASK assert op_id in (self.COUNTING, self.COMPRESSING, self.WRITING) if op_code & self.WRITING > 0: if op_code & self.BEGIN > 0: - assert not message, 'should not have message when remote begins writing' + assert not message, "should not have message when remote begins writing" elif op_code & self.END > 0: assert message - assert not message.startswith(', '), "Sanitize progress messages: '%s'" % message - assert not message.endswith(', '), "Sanitize progress messages: '%s'" % message + assert not message.startswith(", "), ( + "Sanitize progress messages: '%s'" % message + ) + assert not message.endswith(", "), ( + "Sanitize progress messages: '%s'" % message + ) self._stages_per_op.setdefault(op_id, 0) - self._stages_per_op[op_id] = self._stages_per_op[op_id] | (op_code & self.STAGE_MASK) + self._stages_per_op[op_id] = self._stages_per_op[op_id] | ( + op_code & self.STAGE_MASK + ) if op_code & (self.WRITING | self.END) == (self.WRITING | self.END): assert message @@ -101,9 +107,9 @@ class TestRemoteProgress(RemoteProgress): class TestRemote(TestBase): - def tearDown(self): import gc + gc.collect() def _print_fetchhead(self, repo): @@ -140,7 +146,11 @@ class TestRemote(TestBase): self.assertIsInstance(info.old_commit, Commit) if info.flags & info.ERROR: has_one = False - for bitflag in (info.REJECTED, info.REMOTE_REJECTED, info.REMOTE_FAILURE): + for bitflag in ( + info.REJECTED, + info.REMOTE_REJECTED, + info.REMOTE_FAILURE, + ): has_one |= bool(info.flags & bitflag) # END for each bitflag self.assertTrue(has_one) @@ -161,15 +171,22 @@ class TestRemote(TestBase): results.raise_if_error() def _do_test_fetch_info(self, repo): - self.assertRaises(ValueError, FetchInfo._from_line, repo, "nonsense", '') + self.assertRaises(ValueError, FetchInfo._from_line, repo, "nonsense", "") self.assertRaises( - ValueError, FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') + ValueError, + FetchInfo._from_line, + repo, + "? [up to date] 0.1.7RC -> origin/0.1.7RC", + "", + ) def _commit_random_file(self, repo): # Create a file with a random name and random data and commit it to repo. # Return the committed absolute file path index = repo.index - new_file = self._make_file(osp.basename(tempfile.mktemp()), str(random.random()), repo) + new_file = self._make_file( + osp.basename(tempfile.mktemp()), str(random.random()), repo + ) index.add([new_file]) index.commit("Committing %s" % new_file) return new_file @@ -180,11 +197,12 @@ class TestRemote(TestBase): def fetch_and_test(remote, **kwargs): progress = TestRemoteProgress() - kwargs['progress'] = progress + kwargs["progress"] = progress res = remote.fetch(**kwargs) progress.make_assertion() self._do_test_fetch_result(res, remote) return res + # END fetch and check def get_info(res, remote, name): @@ -204,7 +222,7 @@ class TestRemote(TestBase): remote_commit = rhead.commit rhead.reset("HEAD~2", index=False) res = fetch_and_test(remote) - mkey = "%s/%s" % (remote, 'master') + mkey = "%s/%s" % (remote, "master") master_info = res[mkey] self.assertTrue(master_info.flags & FetchInfo.FORCED_UPDATE) self.assertIsNotNone(master_info.note) @@ -241,10 +259,10 @@ class TestRemote(TestBase): # test single branch fetch with refspec including target remote res = fetch_and_test(remote, refspec="master:refs/remotes/%s/master" % remote) self.assertEqual(len(res), 1) - self.assertTrue(get_info(res, remote, 'master')) + self.assertTrue(get_info(res, remote, "master")) # ... with respec and no target - res = fetch_and_test(remote, refspec='master') + res = fetch_and_test(remote, refspec="master") self.assertEqual(len(res), 1) # ... multiple refspecs ... works, but git command returns with error if one ref is wrong without @@ -286,8 +304,12 @@ class TestRemote(TestBase): # must clone with a local path for the repo implementation not to freak out # as it wants local paths only ( which I can understand ) other_repo = remote_repo.clone(other_repo_dir, shared=False) - remote_repo_url = osp.basename(remote_repo.git_dir) # git-daemon runs with appropriate `--base-path`. - remote_repo_url = Git.polish_url("git://localhost:%s/%s" % (GIT_DAEMON_PORT, remote_repo_url)) + remote_repo_url = osp.basename( + remote_repo.git_dir + ) # git-daemon runs with appropriate `--base-path`. + remote_repo_url = Git.polish_url( + "git://localhost:%s/%s" % (GIT_DAEMON_PORT, remote_repo_url) + ) # put origin to git-url other_origin = other_repo.remotes.origin @@ -321,7 +343,7 @@ class TestRemote(TestBase): except AttributeError: # if the author is on a non-master branch, the clones might not have # a local master yet. We simply create it - lhead.reference = rw_repo.create_head('master') + lhead.reference = rw_repo.create_head("master") # END master handling lhead.reset(remote.refs.master, working_tree=True) @@ -345,7 +367,7 @@ class TestRemote(TestBase): self._do_test_push_result(res, remote) # force rejected pull - res = remote.push('+%s' % lhead.reference) + res = remote.push("+%s" % lhead.reference) self.assertEqual(res[0].flags & PushInfo.ERROR, 0) self.assertTrue(res[0].flags & PushInfo.FORCED_UPDATE) self._do_test_push_result(res, remote) @@ -357,7 +379,9 @@ class TestRemote(TestBase): progress = TestRemoteProgress() to_be_updated = "my_tag.1.0RV" new_tag = TagReference.create(rw_repo, to_be_updated) # @UnusedVariable - other_tag = TagReference.create(rw_repo, "my_obj_tag.2.1aRV", logmsg="my message") + other_tag = TagReference.create( + rw_repo, "my_obj_tag.2.1aRV", logmsg="my message" + ) res = remote.push(progress=progress, tags=True) self.assertTrue(res[-1].flags & PushInfo.NEW_TAG) progress.make_assertion() @@ -365,7 +389,9 @@ class TestRemote(TestBase): # update push new tags # Rejection is default - new_tag = TagReference.create(rw_repo, to_be_updated, reference='HEAD~1', force=True) + new_tag = TagReference.create( + rw_repo, to_be_updated, reference="HEAD~1", force=True + ) res = remote.push(tags=True) self._do_test_push_result(res, remote) self.assertTrue(res[-1].flags & PushInfo.REJECTED) @@ -411,7 +437,7 @@ class TestRemote(TestBase): res = remote.push(all=True) self._do_test_push_result(res, remote) - remote.pull('master', kill_after_timeout=10.0) + remote.pull("master", kill_after_timeout=10.0) # cleanup - delete created tags and branches as we are in an innerloop on # the same repository @@ -419,7 +445,7 @@ class TestRemote(TestBase): remote.push(":%s" % other_tag.path, kill_after_timeout=10.0) @skipIf(HIDE_WINDOWS_FREEZE_ERRORS, "FIXME: Freezes!") - @with_rw_and_rw_remote_repo('0.1.6') + @with_rw_and_rw_remote_repo("0.1.6") def test_base(self, rw_repo, remote_repo): num_remotes = 0 remote_set = set() @@ -477,8 +503,9 @@ class TestRemote(TestBase): # Only for remotes - local cases are the same or less complicated # as additional progress information will never be emitted if remote.name == "daemon_origin": - self._do_test_fetch(remote, rw_repo, remote_repo, - kill_after_timeout=10.0) + self._do_test_fetch( + remote, rw_repo, remote_repo, kill_after_timeout=10.0 + ) ran_fetch_test = True # END fetch test @@ -489,7 +516,7 @@ class TestRemote(TestBase): self.assertTrue(num_remotes) self.assertEqual(num_remotes, len(remote_set)) - origin = rw_repo.remote('origin') + origin = rw_repo.remote("origin") assert origin == rw_repo.remotes.origin # Verify we can handle prunes when fetching @@ -502,15 +529,19 @@ class TestRemote(TestBase): num_deleted = False for branch in remote_repo.heads: - if branch.name != 'master': + if branch.name != "master": branch.delete(remote_repo, branch, force=True) num_deleted += 1 # end # end for each branch self.assertGreater(num_deleted, 0) - self.assertEqual(len(rw_repo.remotes.origin.fetch(prune=True)), 1, "deleted everything but master") + self.assertEqual( + len(rw_repo.remotes.origin.fetch(prune=True)), + 1, + "deleted everything but master", + ) - @with_rw_repo('HEAD', bare=True) + @with_rw_repo("HEAD", bare=True) def test_creation_and_removal(self, bare_rw_repo): new_name = "test_new_one" arg_list = (new_name, "git@server:hello.git") @@ -523,7 +554,9 @@ class TestRemote(TestBase): self.assertRaises(GitCommandError, Remote.create, bare_rw_repo, *arg_list) Remote.remove(bare_rw_repo, new_name) - self.assertTrue(remote.exists()) # We still have a cache that doesn't know we were deleted by name + self.assertTrue( + remote.exists() + ) # We still have a cache that doesn't know we were deleted by name remote._clear_cache() assert not remote.exists() # Cache should be renewed now. This is an issue ... @@ -534,86 +567,108 @@ class TestRemote(TestBase): # END for each remote # Issue #262 - the next call would fail if bug wasn't fixed - bare_rw_repo.create_remote('bogus', '/bogus/path', mirror='push') + bare_rw_repo.create_remote("bogus", "/bogus/path", mirror="push") def test_fetch_info(self): # assure we can handle remote-tracking branches - fetch_info_line_fmt = "c437ee5deb8d00cf02f03720693e4c802e99f390 not-for-merge %s '0.3' of " + fetch_info_line_fmt = ( + "c437ee5deb8d00cf02f03720693e4c802e99f390 not-for-merge %s '0.3' of " + ) fetch_info_line_fmt += "git://github.com/gitpython-developers/GitPython" remote_info_line_fmt = "* [new branch] nomatter -> %s" - self.assertRaises(ValueError, FetchInfo._from_line, self.rorepo, - remote_info_line_fmt % "refs/something/branch", - "269c498e56feb93e408ed4558c8138d750de8893\t\t/Users/ben/test/foo\n") - - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % "local/master", - fetch_info_line_fmt % 'remote-tracking branch') + self.assertRaises( + ValueError, + FetchInfo._from_line, + self.rorepo, + remote_info_line_fmt % "refs/something/branch", + "269c498e56feb93e408ed4558c8138d750de8893\t\t/Users/ben/test/foo\n", + ) + + fi = FetchInfo._from_line( + self.rorepo, + remote_info_line_fmt % "local/master", + fetch_info_line_fmt % "remote-tracking branch", + ) assert not fi.ref.is_valid() self.assertEqual(fi.ref.name, "local/master") # handles non-default refspecs: One can specify a different path in refs/remotes # or a special path just in refs/something for instance - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % "subdir/tagname", - fetch_info_line_fmt % 'tag') + fi = FetchInfo._from_line( + self.rorepo, + remote_info_line_fmt % "subdir/tagname", + fetch_info_line_fmt % "tag", + ) self.assertIsInstance(fi.ref, TagReference) - assert fi.ref.path.startswith('refs/tags'), fi.ref.path + assert fi.ref.path.startswith("refs/tags"), fi.ref.path # it could be in a remote direcftory though - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % "remotename/tags/tagname", - fetch_info_line_fmt % 'tag') + fi = FetchInfo._from_line( + self.rorepo, + remote_info_line_fmt % "remotename/tags/tagname", + fetch_info_line_fmt % "tag", + ) self.assertIsInstance(fi.ref, TagReference) - assert fi.ref.path.startswith('refs/remotes/'), fi.ref.path + assert fi.ref.path.startswith("refs/remotes/"), fi.ref.path # it can also be anywhere ! tag_path = "refs/something/remotename/tags/tagname" - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % tag_path, - fetch_info_line_fmt % 'tag') + fi = FetchInfo._from_line( + self.rorepo, remote_info_line_fmt % tag_path, fetch_info_line_fmt % "tag" + ) self.assertIsInstance(fi.ref, TagReference) self.assertEqual(fi.ref.path, tag_path) # branches default to refs/remotes - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % "remotename/branch", - fetch_info_line_fmt % 'branch') + fi = FetchInfo._from_line( + self.rorepo, + remote_info_line_fmt % "remotename/branch", + fetch_info_line_fmt % "branch", + ) self.assertIsInstance(fi.ref, RemoteReference) - self.assertEqual(fi.ref.remote_name, 'remotename') + self.assertEqual(fi.ref.remote_name, "remotename") # but you can force it anywhere, in which case we only have a references - fi = FetchInfo._from_line(self.rorepo, - remote_info_line_fmt % "refs/something/branch", - fetch_info_line_fmt % 'branch') + fi = FetchInfo._from_line( + self.rorepo, + remote_info_line_fmt % "refs/something/branch", + fetch_info_line_fmt % "branch", + ) assert type(fi.ref) is Reference, type(fi.ref) self.assertEqual(fi.ref.path, "refs/something/branch") def test_uncommon_branch_names(self): - stderr_lines = fixture('uncommon_branch_prefix_stderr').decode('ascii').splitlines() - fetch_lines = fixture('uncommon_branch_prefix_FETCH_HEAD').decode('ascii').splitlines() + stderr_lines = ( + fixture("uncommon_branch_prefix_stderr").decode("ascii").splitlines() + ) + fetch_lines = ( + fixture("uncommon_branch_prefix_FETCH_HEAD").decode("ascii").splitlines() + ) # The contents of the files above must be fetched with a custom refspec: # +refs/pull/*:refs/heads/pull/* - res = [FetchInfo._from_line('ShouldntMatterRepo', stderr, fetch_line) - for stderr, fetch_line in zip(stderr_lines, fetch_lines)] + res = [ + FetchInfo._from_line("ShouldntMatterRepo", stderr, fetch_line) + for stderr, fetch_line in zip(stderr_lines, fetch_lines) + ] self.assertGreater(len(res), 0) - self.assertEqual(res[0].remote_ref_path, 'refs/pull/1/head') - self.assertEqual(res[0].ref.path, 'refs/heads/pull/1/head') + self.assertEqual(res[0].remote_ref_path, "refs/pull/1/head") + self.assertEqual(res[0].ref.path, "refs/heads/pull/1/head") self.assertIsInstance(res[0].ref, Head) - @with_rw_repo('HEAD', bare=False) + @with_rw_repo("HEAD", bare=False) def test_multiple_urls(self, rw_repo): # test addresses - test1 = 'https://github.com/gitpython-developers/GitPython' - test2 = 'https://github.com/gitpython-developers/gitdb' - test3 = 'https://github.com/gitpython-developers/smmap' + test1 = "https://github.com/gitpython-developers/GitPython" + test2 = "https://github.com/gitpython-developers/gitdb" + test3 = "https://github.com/gitpython-developers/smmap" remote = rw_repo.remotes[0] # Testing setting a single URL @@ -639,7 +694,7 @@ class TestRemote(TestBase): self.assertRaises(GitCommandError, remote.set_url, test2, add=True, delete=True) # Testing on another remote, with the add/delete URL - remote = rw_repo.create_remote('another', url=test1) + remote = rw_repo.create_remote("another", url=test1) remote.add_url(test2) self.assertEqual(list(remote.urls), [test1, test2]) remote.add_url(test3) @@ -653,19 +708,23 @@ class TestRemote(TestBase): self.assertRaises(GitCommandError, remote.delete_url, test3) def test_fetch_error(self): - rem = self.rorepo.remote('origin') - with self.assertRaisesRegex(GitCommandError, "[Cc]ouldn't find remote ref __BAD_REF__"): - rem.fetch('__BAD_REF__') + rem = self.rorepo.remote("origin") + with self.assertRaisesRegex( + GitCommandError, "[Cc]ouldn't find remote ref __BAD_REF__" + ): + rem.fetch("__BAD_REF__") - @with_rw_repo('0.1.6', bare=False) + @with_rw_repo("0.1.6", bare=False) def test_push_error(self, repo): - rem = repo.remote('origin') - with self.assertRaisesRegex(GitCommandError, "src refspec __BAD_REF__ does not match any"): - rem.push('__BAD_REF__') + rem = repo.remote("origin") + with self.assertRaisesRegex( + GitCommandError, "src refspec __BAD_REF__ does not match any" + ): + rem.push("__BAD_REF__") class TestTimeouts(TestBase): - @with_rw_repo('HEAD', bare=False) + @with_rw_repo("HEAD", bare=False) def test_timeout_funcs(self, repo): # Force error code to prevent a race condition if the python thread is # slow @@ -675,8 +734,7 @@ class TestTimeouts(TestBase): f = getattr(repo.remotes.origin, function) assert f is not None # Make sure these functions exist _ = f() # Make sure the function runs - with pytest.raises(GitCommandError, - match="kill_after_timeout=0 s"): + with pytest.raises(GitCommandError, match="kill_after_timeout=0 s"): f(kill_after_timeout=0) Git.AutoInterrupt._status_code_if_terminate = default diff --git a/test/test_repo.py b/test/test_repo.py index c5b2680d..7cffbbd8 100644 --- a/test/test_repo.py +++ b/test/test_repo.py @@ -30,17 +30,13 @@ from git import ( GitCmdObjectDB, Remote, BadName, - GitCommandError + GitCommandError, ) from git.exc import ( BadObject, ) from git.repo.fun import touch -from test.lib import ( - TestBase, - with_rw_repo, - fixture -) +from test.lib import TestBase, with_rw_repo, fixture from git.util import HIDE_WINDOWS_KNOWN_ERRORS, cygpath from test.lib import with_rw_directory from git.util import join_path_native, rmtree, rmfile, bin_to_hex @@ -58,7 +54,7 @@ def flatten(lol): return list(iter_flatten(lol)) -_tc_lock_fpaths = osp.join(osp.dirname(__file__), '../../.git/*.lock') +_tc_lock_fpaths = osp.join(osp.dirname(__file__), "../../.git/*.lock") def _rm_lock_files(): @@ -67,15 +63,17 @@ def _rm_lock_files(): class TestRepo(TestBase): - def setUp(self): _rm_lock_files() def tearDown(self): for lfp in glob.glob(_tc_lock_fpaths): if osp.isfile(lfp): - raise AssertionError('Previous TC left hanging git-lock file: {}'.format(lfp)) + raise AssertionError( + "Previous TC left hanging git-lock file: {}".format(lfp) + ) import gc + gc.collect() def test_new_should_raise_on_invalid_repo_location(self): @@ -84,15 +82,15 @@ class TestRepo(TestBase): def test_new_should_raise_on_non_existent_path(self): self.assertRaises(NoSuchPathError, Repo, "repos/foobar") - @with_rw_repo('0.3.2.1') + @with_rw_repo("0.3.2.1") def test_repo_creation_from_different_paths(self, rw_repo): r_from_gitdir = Repo(rw_repo.git_dir) self.assertEqual(r_from_gitdir.git_dir, rw_repo.git_dir) - assert r_from_gitdir.git_dir.endswith('.git') - assert not rw_repo.git.working_dir.endswith('.git') + assert r_from_gitdir.git_dir.endswith(".git") + assert not rw_repo.git.working_dir.endswith(".git") self.assertEqual(r_from_gitdir.git.working_dir, rw_repo.git.working_dir) - @with_rw_repo('0.3.2.1') + @with_rw_repo("0.3.2.1") def test_repo_creation_pathlib(self, rw_repo): r_from_gitdir = Repo(pathlib.Path(rw_repo.git_dir)) self.assertEqual(r_from_gitdir.git_dir, rw_repo.git_dir) @@ -113,33 +111,35 @@ class TestRepo(TestBase): # END for each head self.assertIsInstance(self.rorepo.heads.master, Head) - self.assertIsInstance(self.rorepo.heads['master'], Head) + self.assertIsInstance(self.rorepo.heads["master"], Head) def test_tree_from_revision(self): - tree = self.rorepo.tree('0.1.6') + tree = self.rorepo.tree("0.1.6") self.assertEqual(len(tree.hexsha), 40) self.assertEqual(tree.type, "tree") self.assertEqual(self.rorepo.tree(tree), tree) # try from invalid revision that does not exist - self.assertRaises(BadName, self.rorepo.tree, 'hello world') + self.assertRaises(BadName, self.rorepo.tree, "hello world") def test_pickleable(self): pickle.loads(pickle.dumps(self.rorepo)) def test_commit_from_revision(self): - commit = self.rorepo.commit('0.1.4') - self.assertEqual(commit.type, 'commit') + commit = self.rorepo.commit("0.1.4") + self.assertEqual(commit.type, "commit") self.assertEqual(self.rorepo.commit(commit), commit) def test_commits(self): mc = 10 - commits = list(self.rorepo.iter_commits('0.1.6', max_count=mc)) + commits = list(self.rorepo.iter_commits("0.1.6", max_count=mc)) self.assertEqual(len(commits), mc) c = commits[0] - self.assertEqual('9a4b1d4d11eee3c5362a4152216376e634bd14cf', c.hexsha) - self.assertEqual(["c76852d0bff115720af3f27acdb084c59361e5f6"], [p.hexsha for p in c.parents]) + self.assertEqual("9a4b1d4d11eee3c5362a4152216376e634bd14cf", c.hexsha) + self.assertEqual( + ["c76852d0bff115720af3f27acdb084c59361e5f6"], [p.hexsha for p in c.parents] + ) self.assertEqual("ce41fc29549042f1aa09cc03174896cf23f112e3", c.tree.hexsha) self.assertEqual("Michael Trier", c.author.name) self.assertEqual("mtrier@gmail.com", c.author.email) @@ -157,7 +157,7 @@ class TestRepo(TestBase): def test_trees(self): mc = 30 num_trees = 0 - for tree in self.rorepo.iter_trees('0.1.5', max_count=mc): + for tree in self.rorepo.iter_trees("0.1.5", max_count=mc): num_trees += 1 self.assertIsInstance(tree, Tree) # END for each tree @@ -176,7 +176,7 @@ class TestRepo(TestBase): assert not repo.head.is_valid() # we can change the head to some other ref - head_ref = Head.from_path(repo, Head.to_full_path('some_head')) + head_ref = Head.from_path(repo, Head.to_full_path("some_head")) assert not head_ref.is_valid() repo.head.ref = head_ref @@ -195,7 +195,9 @@ class TestRepo(TestBase): original_repo = Repo.init(osp.join(rw_dir, "repo")) environment = {"entry1": "value", "another_entry": "10"} - cloned = Repo.clone_from(original_repo.git_dir, osp.join(rw_dir, "clone"), env=environment) + cloned = Repo.clone_from( + original_repo.git_dir, osp.join(rw_dir, "clone"), env=environment + ) self.assertEqual(environment, cloned.git.environment()) @@ -215,20 +217,32 @@ class TestRepo(TestBase): def test_clone_from_pathlib_withConfig(self, rw_dir): original_repo = Repo.init(osp.join(rw_dir, "repo")) - cloned = Repo.clone_from(original_repo.git_dir, pathlib.Path(rw_dir) / "clone_pathlib_withConfig", - multi_options=["--recurse-submodules=repo", - "--config core.filemode=false", - "--config submodule.repo.update=checkout", - "--config filter.lfs.clean='git-lfs clean -- %f'"]) - - self.assertEqual(cloned.config_reader().get_value('submodule', 'active'), 'repo') - self.assertEqual(cloned.config_reader().get_value('core', 'filemode'), False) - self.assertEqual(cloned.config_reader().get_value('submodule "repo"', 'update'), 'checkout') - self.assertEqual(cloned.config_reader().get_value('filter "lfs"', 'clean'), 'git-lfs clean -- %f') + cloned = Repo.clone_from( + original_repo.git_dir, + pathlib.Path(rw_dir) / "clone_pathlib_withConfig", + multi_options=[ + "--recurse-submodules=repo", + "--config core.filemode=false", + "--config submodule.repo.update=checkout", + "--config filter.lfs.clean='git-lfs clean -- %f'", + ], + ) + + self.assertEqual( + cloned.config_reader().get_value("submodule", "active"), "repo" + ) + self.assertEqual(cloned.config_reader().get_value("core", "filemode"), False) + self.assertEqual( + cloned.config_reader().get_value('submodule "repo"', "update"), "checkout" + ) + self.assertEqual( + cloned.config_reader().get_value('filter "lfs"', "clean"), + "git-lfs clean -- %f", + ) def test_clone_from_with_path_contains_unicode(self): with tempfile.TemporaryDirectory() as tmpdir: - unicode_dir_name = '\u0394' + unicode_dir_name = "\u0394" path_with_unicode = os.path.join(tmpdir, unicode_dir_name) os.makedirs(path_with_unicode) @@ -238,7 +252,7 @@ class TestRepo(TestBase): to_path=path_with_unicode, ) except UnicodeEncodeError: - self.fail('Raised UnicodeEncodeError') + self.fail("Raised UnicodeEncodeError") @with_rw_directory def test_leaking_password_in_clone_logs(self, rw_dir): @@ -246,16 +260,21 @@ class TestRepo(TestBase): try: Repo.clone_from( url="https://fakeuser:{}@fakerepo.example.com/testrepo".format( - password), - to_path=rw_dir) + password + ), + to_path=rw_dir, + ) except GitCommandError as err: - assert password not in str(err), "The error message '%s' should not contain the password" % err + assert password not in str(err), ( + "The error message '%s' should not contain the password" % err + ) # Working example from a blank private project Repo.clone_from( url="https://gitlab+deploy-token-392045:mLWhVus7bjLsy8xj8q2V@gitlab.com/mercierm/test_git_python", - to_path=rw_dir) + to_path=rw_dir, + ) - @with_rw_repo('HEAD') + @with_rw_repo("HEAD") def test_max_chunk_size(self, repo): class TestOutputStream(TestBase): def __init__(self, max_chunk_size): @@ -265,10 +284,20 @@ class TestRepo(TestBase): self.assertTrue(len(b) <= self.max_chunk_size) for chunk_size in [16, 128, 1024]: - repo.git.status(output_stream=TestOutputStream(chunk_size), max_chunk_size=chunk_size) - - repo.git.log(n=100, output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE), max_chunk_size=None) - repo.git.log(n=100, output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE), max_chunk_size=-10) + repo.git.status( + output_stream=TestOutputStream(chunk_size), max_chunk_size=chunk_size + ) + + repo.git.log( + n=100, + output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE), + max_chunk_size=None, + ) + repo.git.log( + n=100, + output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE), + max_chunk_size=-10, + ) repo.git.log(n=100, output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE)) def test_init(self): @@ -352,7 +381,7 @@ class TestRepo(TestBase): self.rorepo.alternates = cur_alternates def test_repr(self): - assert repr(self.rorepo).startswith('<git.repo.base.Repo ') + assert repr(self.rorepo).startswith("<git.repo.base.Repo ") def test_is_dirty_with_bare_repository(self): orig_value = self.rorepo._bare @@ -365,7 +394,9 @@ class TestRepo(TestBase): for index in (0, 1): for working_tree in (0, 1): for untracked_files in (0, 1): - assert self.rorepo.is_dirty(index, working_tree, untracked_files) in (True, False) + assert self.rorepo.is_dirty( + index, working_tree, untracked_files + ) in (True, False) # END untracked files # END working tree # END index @@ -379,7 +410,9 @@ class TestRepo(TestBase): for index in (0, 1): for working_tree in (0, 1): for untracked_files in (0, 1): - assert self.rorepo.is_dirty(index, working_tree, untracked_files, path=':!foo') in (True, False) + assert self.rorepo.is_dirty( + index, working_tree, untracked_files, path=":!foo" + ) in (True, False) # END untracked files # END working tree # END index @@ -388,7 +421,7 @@ class TestRepo(TestBase): assert self.rorepo.is_dirty() is False self.rorepo._bare = orig_val - @with_rw_repo('HEAD') + @with_rw_repo("HEAD") def test_is_dirty_with_path(self, rwrepo): assert rwrepo.is_dirty(path="git") is False @@ -407,17 +440,19 @@ class TestRepo(TestBase): assert rwrepo.is_dirty(untracked_files=True, path="doc") is True def test_head(self): - self.assertEqual(self.rorepo.head.reference.object, self.rorepo.active_branch.object) + self.assertEqual( + self.rorepo.head.reference.object, self.rorepo.active_branch.object + ) def test_index(self): index = self.rorepo.index self.assertIsInstance(index, IndexFile) def test_tag(self): - assert self.rorepo.tag('refs/tags/0.1.5').commit + assert self.rorepo.tag("refs/tags/0.1.5").commit def test_tag_to_full_tag_path(self): - tags = ['0.1.5', 'tags/0.1.5', 'refs/tags/0.1.5'] + tags = ["0.1.5", "tags/0.1.5", "refs/tags/0.1.5"] value_errors = [] for tag in tags: try: @@ -427,16 +462,16 @@ class TestRepo(TestBase): self.assertEqual(value_errors, []) def test_archive(self): - tmpfile = tempfile.mktemp(suffix='archive-test') - with open(tmpfile, 'wb') as stream: - self.rorepo.archive(stream, '0.1.6', path='doc') + tmpfile = tempfile.mktemp(suffix="archive-test") + with open(tmpfile, "wb") as stream: + self.rorepo.archive(stream, "0.1.6", path="doc") assert stream.tell() os.remove(tmpfile) - @mock.patch.object(Git, '_call_process') + @mock.patch.object(Git, "_call_process") def test_should_display_blame_information(self, git): - git.return_value = fixture('blame') - b = self.rorepo.blame('master', 'lib/git.py') + git.return_value = fixture("blame") + b = self.rorepo.blame("master", "lib/git.py") self.assertEqual(13, len(b)) self.assertEqual(2, len(b[0])) # self.assertEqual(25, reduce(lambda acc, x: acc + len(x[-1]), b)) @@ -444,85 +479,127 @@ class TestRepo(TestBase): c = b[0][0] self.assertTrue(git.called) - self.assertEqual('634396b2f541a9f2d58b00be1a07f0c358b999b3', c.hexsha) - self.assertEqual('Tom Preston-Werner', c.author.name) - self.assertEqual('tom@mojombo.com', c.author.email) + self.assertEqual("634396b2f541a9f2d58b00be1a07f0c358b999b3", c.hexsha) + self.assertEqual("Tom Preston-Werner", c.author.name) + self.assertEqual("tom@mojombo.com", c.author.email) self.assertEqual(1191997100, c.authored_date) - self.assertEqual('Tom Preston-Werner', c.committer.name) - self.assertEqual('tom@mojombo.com', c.committer.email) + self.assertEqual("Tom Preston-Werner", c.committer.name) + self.assertEqual("tom@mojombo.com", c.committer.email) self.assertEqual(1191997100, c.committed_date) - self.assertRaisesRegex(ValueError, "634396b2f541a9f2d58b00be1a07f0c358b999b3 missing", lambda: c.message) + self.assertRaisesRegex( + ValueError, + "634396b2f541a9f2d58b00be1a07f0c358b999b3 missing", + lambda: c.message, + ) # test the 'lines per commit' entries tlist = b[0][1] self.assertTrue(tlist) self.assertTrue(isinstance(tlist[0], str)) - self.assertTrue(len(tlist) < sum(len(t) for t in tlist)) # test for single-char bug + self.assertTrue( + len(tlist) < sum(len(t) for t in tlist) + ) # test for single-char bug # BINARY BLAME - git.return_value = fixture('blame_binary') - blames = self.rorepo.blame('master', 'rps') + git.return_value = fixture("blame_binary") + blames = self.rorepo.blame("master", "rps") self.assertEqual(len(blames), 2) def test_blame_real(self): c = 0 - nml = 0 # amount of multi-lines per blame + nml = 0 # amount of multi-lines per blame for item in self.rorepo.head.commit.tree.traverse( - predicate=lambda i, d: i.type == 'blob' and i.path.endswith('.py')): + predicate=lambda i, d: i.type == "blob" and i.path.endswith(".py") + ): c += 1 for b in self.rorepo.blame(self.rorepo.head, item.path): nml += int(len(b[1]) > 1) # END for each item to traverse assert c, "Should have executed at least one blame command" - assert nml, "There should at least be one blame commit that contains multiple lines" + assert ( + nml + ), "There should at least be one blame commit that contains multiple lines" - @mock.patch.object(Git, '_call_process') + @mock.patch.object(Git, "_call_process") def test_blame_incremental(self, git): # loop over two fixtures, create a test fixture for 2.11.1+ syntax - for git_fixture in ('blame_incremental', 'blame_incremental_2.11.1_plus'): + for git_fixture in ("blame_incremental", "blame_incremental_2.11.1_plus"): git.return_value = fixture(git_fixture) - blame_output = self.rorepo.blame_incremental('9debf6b0aafb6f7781ea9d1383c86939a1aacde3', 'AUTHORS') + blame_output = self.rorepo.blame_incremental( + "9debf6b0aafb6f7781ea9d1383c86939a1aacde3", "AUTHORS" + ) blame_output = list(blame_output) self.assertEqual(len(blame_output), 5) # Check all outputted line numbers ranges = flatten([entry.linenos for entry in blame_output]) - self.assertEqual(ranges, flatten([range(2, 3), range(14, 15), range(1, 2), range(3, 14), range(15, 17)])) + self.assertEqual( + ranges, + flatten( + [ + range(2, 3), + range(14, 15), + range(1, 2), + range(3, 14), + range(15, 17), + ] + ), + ) commits = [entry.commit.hexsha[:7] for entry in blame_output] - self.assertEqual(commits, ['82b8902', '82b8902', 'c76852d', 'c76852d', 'c76852d']) + self.assertEqual( + commits, ["82b8902", "82b8902", "c76852d", "c76852d", "c76852d"] + ) # Original filenames - self.assertSequenceEqual([entry.orig_path for entry in blame_output], ['AUTHORS'] * len(blame_output)) + self.assertSequenceEqual( + [entry.orig_path for entry in blame_output], + ["AUTHORS"] * len(blame_output), + ) # Original line numbers orig_ranges = flatten([entry.orig_linenos for entry in blame_output]) - self.assertEqual(orig_ranges, flatten([range(2, 3), range(14, 15), range(1, 2), range(2, 13), range(13, 15)])) # noqa E501 - - @mock.patch.object(Git, '_call_process') + self.assertEqual( + orig_ranges, + flatten( + [ + range(2, 3), + range(14, 15), + range(1, 2), + range(2, 13), + range(13, 15), + ] + ), + ) # noqa E501 + + @mock.patch.object(Git, "_call_process") def test_blame_complex_revision(self, git): - git.return_value = fixture('blame_complex_revision') + git.return_value = fixture("blame_complex_revision") res = self.rorepo.blame("HEAD~10..HEAD", "README.md") self.assertEqual(len(res), 1) self.assertEqual(len(res[0][1]), 83, "Unexpected amount of parsed blame lines") - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(), - """FIXME: File "C:\\projects\\gitpython\\git\\cmd.py", line 671, in execute + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(), + """FIXME: File "C:\\projects\\gitpython\\git\\cmd.py", line 671, in execute raise GitCommandError(command, status, stderr_value, stdout_value) GitCommandError: Cmd('git') failed due to: exit code(128) cmdline: git add 1__��ava verb��ten 1_test _myfile 1_test_other_file 1_��ava-----verb��ten stderr: 'fatal: pathspec '"1__çava verböten"' did not match any files' - """) - @with_rw_repo('HEAD', bare=False) + """, + ) + @with_rw_repo("HEAD", bare=False) def test_untracked_files(self, rwrepo): for run, repo_add in enumerate((rwrepo.index.add, rwrepo.git.add)): base = rwrepo.working_tree_dir - files = (join_path_native(base, "%i_test _myfile" % run), - join_path_native(base, "%i_test_other_file" % run), - join_path_native(base, "%i__çava verböten" % run), - join_path_native(base, "%i_çava-----verböten" % run)) + files = ( + join_path_native(base, "%i_test _myfile" % run), + join_path_native(base, "%i_test_other_file" % run), + join_path_native(base, "%i__çava verböten" % run), + join_path_native(base, "%i_çava-----verböten" % run), + ) num_recently_untracked = 0 for fpath in files: @@ -538,13 +615,15 @@ class TestRepo(TestBase): self.assertEqual(len(files), num_test_untracked) repo_add(untracked_files) - self.assertEqual(len(rwrepo.untracked_files), (num_recently_untracked - len(files))) + self.assertEqual( + len(rwrepo.untracked_files), (num_recently_untracked - len(files)) + ) # end for each run def test_config_reader(self): - reader = self.rorepo.config_reader() # all config files + reader = self.rorepo.config_reader() # all config files assert reader.read_only - reader = self.rorepo.config_reader("repository") # single config file + reader = self.rorepo.config_reader("repository") # single config file assert reader.read_only def test_config_writer(self): @@ -586,17 +665,17 @@ class TestRepo(TestBase): @with_rw_directory def test_tilde_and_env_vars_in_repo_path(self, rw_dir): - ph = os.environ.get('HOME') + ph = os.environ.get("HOME") try: - os.environ['HOME'] = rw_dir - Repo.init(osp.join('~', 'test.git'), bare=True) + os.environ["HOME"] = rw_dir + Repo.init(osp.join("~", "test.git"), bare=True) - os.environ['FOO'] = rw_dir - Repo.init(osp.join('$FOO', 'test.git'), bare=True) + os.environ["FOO"] = rw_dir + Repo.init(osp.join("$FOO", "test.git"), bare=True) finally: if ph: - os.environ['HOME'] = ph - del os.environ['FOO'] + os.environ["HOME"] = ph + del os.environ["FOO"] # end assure HOME gets reset to what it was def test_git_cmd(self): @@ -623,7 +702,7 @@ class TestRepo(TestBase): s = mkfull() lines = s.readlines() self.assertEqual(len(lines), 3) - self.assertTrue(lines[-1].endswith(b'\n'), lines[-1]) + self.assertTrue(lines[-1].endswith(b"\n"), lines[-1]) self.assertEqual(s._stream.tell(), len(d)) # must have scrubbed to the end # realines line limit @@ -643,7 +722,7 @@ class TestRepo(TestBase): self.assertEqual(s.readline(), l1) self.assertEqual(s.readline(), l2) self.assertEqual(s.readline(), l3) - self.assertEqual(s.readline(), b'') + self.assertEqual(s.readline(), b"") self.assertEqual(s._stream.tell(), len(d)) # readline limit @@ -654,13 +733,13 @@ class TestRepo(TestBase): # readline on tiny section s = mktiny() self.assertEqual(s.readline(), l1p) - self.assertEqual(s.readline(), b'') + self.assertEqual(s.readline(), b"") self.assertEqual(s._stream.tell(), ts + 1) # read no limit s = mkfull() self.assertEqual(s.read(), d[:-1]) - self.assertEqual(s.read(), b'') + self.assertEqual(s.read(), b"") self.assertEqual(s._stream.tell(), len(d)) # read limit @@ -679,24 +758,24 @@ class TestRepo(TestBase): def _assert_rev_parse_types(self, name, rev_obj): rev_parse = self.rorepo.rev_parse - if rev_obj.type == 'tag': + if rev_obj.type == "tag": rev_obj = rev_obj.object # tree and blob type - obj = rev_parse(name + '^{tree}') + obj = rev_parse(name + "^{tree}") self.assertEqual(obj, rev_obj.tree) - obj = rev_parse(name + ':CHANGES') - self.assertEqual(obj.type, 'blob') - self.assertEqual(obj.path, 'CHANGES') - self.assertEqual(rev_obj.tree['CHANGES'], obj) + obj = rev_parse(name + ":CHANGES") + self.assertEqual(obj.type, "blob") + self.assertEqual(obj.path, "CHANGES") + self.assertEqual(rev_obj.tree["CHANGES"], obj) def _assert_rev_parse(self, name): """tries multiple different rev-parse syntaxes with the given name :return: parsed object""" rev_parse = self.rorepo.rev_parse orig_obj = rev_parse(name) - if orig_obj.type == 'tag': + if orig_obj.type == "tag": obj = orig_obj.object else: obj = orig_obj @@ -737,17 +816,19 @@ class TestRepo(TestBase): return orig_obj - @with_rw_repo('HEAD', bare=False) + @with_rw_repo("HEAD", bare=False) def test_rw_rev_parse(self, rwrepo): # verify it does not confuse branches with hexsha ids - ahead = rwrepo.create_head('aaaaaaaa') - assert(rwrepo.rev_parse(str(ahead)) == ahead.commit) + ahead = rwrepo.create_head("aaaaaaaa") + assert rwrepo.rev_parse(str(ahead)) == ahead.commit def test_rev_parse(self): rev_parse = self.rorepo.rev_parse # try special case: This one failed at some point, make sure its fixed - self.assertEqual(rev_parse("33ebe").hexsha, "33ebe7acec14b25c5f84f35a664803fcab2f7781") + self.assertEqual( + rev_parse("33ebe").hexsha, "33ebe7acec14b25c5f84f35a664803fcab2f7781" + ) # start from reference num_resolved = 0 @@ -755,7 +836,7 @@ class TestRepo(TestBase): for ref_no, ref in enumerate(Reference.iter_items(self.rorepo)): path_tokens = ref.path.split("/") for pt in range(len(path_tokens)): - path_section = '/'.join(path_tokens[-(pt + 1):]) + path_section = "/".join(path_tokens[-(pt + 1) :]) try: obj = self._assert_rev_parse(path_section) self.assertEqual(obj.type, ref.object.type) @@ -771,17 +852,17 @@ class TestRepo(TestBase): assert num_resolved # it works with tags ! - tag = self._assert_rev_parse('0.1.4') - self.assertEqual(tag.type, 'tag') + tag = self._assert_rev_parse("0.1.4") + self.assertEqual(tag.type, "tag") # try full sha directly ( including type conversion ) self.assertEqual(tag.object, rev_parse(tag.object.hexsha)) self._assert_rev_parse_types(tag.object.hexsha, tag.object) # multiple tree types result in the same tree: HEAD^{tree}^{tree}:CHANGES - rev = '0.1.4^{tree}^{tree}' + rev = "0.1.4^{tree}^{tree}" self.assertEqual(rev_parse(rev), tag.object.tree) - self.assertEqual(rev_parse(rev + ':CHANGES'), tag.object.tree['CHANGES']) + self.assertEqual(rev_parse(rev + ":CHANGES"), tag.object.tree["CHANGES"]) # try to get parents from first revision - it should fail as no such revision # exists @@ -802,15 +883,18 @@ class TestRepo(TestBase): # needs a tag which points to a blob # ref^0 returns commit being pointed to, same with ref~0, and ^{} - tag = rev_parse('0.1.4') - for token in (('~0', '^0', '^{}')): - self.assertEqual(tag.object, rev_parse('0.1.4%s' % token)) + tag = rev_parse("0.1.4") + for token in ("~0", "^0", "^{}"): + self.assertEqual(tag.object, rev_parse("0.1.4%s" % token)) # END handle multiple tokens # try partial parsing max_items = 40 for i, binsha in enumerate(self.rorepo.odb.sha_iter()): - self.assertEqual(rev_parse(bin_to_hex(binsha)[:8 - (i % 2)].decode('ascii')).binsha, binsha) + self.assertEqual( + rev_parse(bin_to_hex(binsha)[: 8 - (i % 2)].decode("ascii")).binsha, + binsha, + ) if i > max_items: # this is rather slow currently, as rev_parse returns an object # which requires accessing packs, it has some additional overhead @@ -818,10 +902,10 @@ class TestRepo(TestBase): # END for each binsha in repo # missing closing brace commit^{tree - self.assertRaises(ValueError, rev_parse, '0.1.4^{tree') + self.assertRaises(ValueError, rev_parse, "0.1.4^{tree") # missing starting brace - self.assertRaises(ValueError, rev_parse, '0.1.4^tree}') + self.assertRaises(ValueError, rev_parse, "0.1.4^tree}") # REVLOG ####### @@ -831,23 +915,23 @@ class TestRepo(TestBase): self.assertRaises(BadObject, rev_parse, "%s@{0}" % head.commit.hexsha) # uses HEAD.ref by default - self.assertEqual(rev_parse('@{0}'), head.commit) + self.assertEqual(rev_parse("@{0}"), head.commit) if not head.is_detached: - refspec = '%s@{0}' % head.ref.name + refspec = "%s@{0}" % head.ref.name self.assertEqual(rev_parse(refspec), head.ref.commit) # all additional specs work as well self.assertEqual(rev_parse(refspec + "^{tree}"), head.commit.tree) - self.assertEqual(rev_parse(refspec + ":CHANGES").type, 'blob') + self.assertEqual(rev_parse(refspec + ":CHANGES").type, "blob") # END operate on non-detached head # position doesn't exist - self.assertRaises(IndexError, rev_parse, '@{10000}') + self.assertRaises(IndexError, rev_parse, "@{10000}") # currently, nothing more is supported self.assertRaises(NotImplementedError, rev_parse, "@{1 week ago}") # the last position - assert rev_parse('@{1}') != head.commit + assert rev_parse("@{1}") != head.commit def test_repo_odbtype(self): target_type = GitCmdObjectDB @@ -860,7 +944,7 @@ class TestRepo(TestBase): self.assertIsInstance(self.rorepo.submodule("gitdb"), Submodule) self.assertRaises(ValueError, self.rorepo.submodule, "doesn't exist") - @with_rw_repo('HEAD', bare=False) + @with_rw_repo("HEAD", bare=False) def test_submodule_update(self, rwrepo): # fails in bare mode rwrepo._bare = True @@ -869,27 +953,31 @@ class TestRepo(TestBase): # test create submodule sm = rwrepo.submodules[0] - sm = rwrepo.create_submodule("my_new_sub", "some_path", join_path_native(self.rorepo.working_tree_dir, sm.path)) + sm = rwrepo.create_submodule( + "my_new_sub", + "some_path", + join_path_native(self.rorepo.working_tree_dir, sm.path), + ) self.assertIsInstance(sm, Submodule) # note: the rest of this functionality is tested in test_submodule - @with_rw_repo('HEAD') + @with_rw_repo("HEAD") def test_git_file(self, rwrepo): # Move the .git directory to another location and create the .git file. - real_path_abs = osp.abspath(join_path_native(rwrepo.working_tree_dir, '.real')) + real_path_abs = osp.abspath(join_path_native(rwrepo.working_tree_dir, ".real")) os.rename(rwrepo.git_dir, real_path_abs) - git_file_path = join_path_native(rwrepo.working_tree_dir, '.git') - with open(git_file_path, 'wb') as fp: - fp.write(fixture('git_file')) + git_file_path = join_path_native(rwrepo.working_tree_dir, ".git") + with open(git_file_path, "wb") as fp: + fp.write(fixture("git_file")) # Create a repo and make sure it's pointing to the relocated .git directory. git_file_repo = Repo(rwrepo.working_tree_dir) self.assertEqual(osp.abspath(git_file_repo.git_dir), real_path_abs) # Test using an absolute gitdir path in the .git file. - with open(git_file_path, 'wb') as fp: - fp.write(('gitdir: %s\n' % real_path_abs).encode('ascii')) + with open(git_file_path, "wb") as fp: + fp.write(("gitdir: %s\n" % real_path_abs).encode("ascii")) git_file_repo = Repo(rwrepo.working_tree_dir) self.assertEqual(osp.abspath(git_file_repo.git_dir), real_path_abs) @@ -906,13 +994,13 @@ class TestRepo(TestBase): for _ in range(64): for repo_type in (GitCmdObjectDB, GitDB): repo = Repo(self.rorepo.working_tree_dir, odbt=repo_type) - last_commit(repo, 'master', 'test/test_base.py') + last_commit(repo, "master", "test/test_base.py") # end for each repository type # end for each iteration def test_remote_method(self): - self.assertRaises(ValueError, self.rorepo.remote, 'foo-blue') - self.assertIsInstance(self.rorepo.remote(name='origin'), Remote) + self.assertRaises(ValueError, self.rorepo.remote, "foo-blue") + self.assertIsInstance(self.rorepo.remote(name="origin"), Remote) @with_rw_directory def test_empty_repo(self, rw_dir): @@ -920,13 +1008,13 @@ class TestRepo(TestBase): r = Repo.init(rw_dir, mkdir=False) # It's ok not to be able to iterate a commit, as there is none self.assertRaises(ValueError, r.iter_commits) - self.assertEqual(r.active_branch.name, 'master') + self.assertEqual(r.active_branch.name, "master") assert not r.active_branch.is_valid(), "Branch is yet to be born" # actually, when trying to create a new branch without a commit, git itself fails # We should, however, not fail ungracefully - self.assertRaises(BadName, r.create_head, 'foo') - self.assertRaises(BadName, r.create_head, 'master') + self.assertRaises(BadName, r.create_head, "foo") + self.assertRaises(BadName, r.create_head, "master") # It's expected to not be able to access a tree self.assertRaises(ValueError, r.tree) @@ -936,43 +1024,43 @@ class TestRepo(TestBase): r.index.commit("initial commit\nBAD MESSAGE 1\n") # Now a branch should be creatable - nb = r.create_head('foo') + nb = r.create_head("foo") assert nb.is_valid() - with open(new_file_path, 'w') as f: - f.write('Line 1\n') + with open(new_file_path, "w") as f: + f.write("Line 1\n") r.index.add([new_file_path]) r.index.commit("add line 1\nBAD MESSAGE 2\n") - with open('%s/.git/logs/refs/heads/master' % (rw_dir,), 'r') as f: + with open("%s/.git/logs/refs/heads/master" % (rw_dir,), "r") as f: contents = f.read() - assert 'BAD MESSAGE' not in contents, 'log is corrupt' + assert "BAD MESSAGE" not in contents, "log is corrupt" def test_merge_base(self): repo = self.rorepo - c1 = 'f6aa8d1' - c2 = repo.commit('d46e3fe') - c3 = '763ef75' + c1 = "f6aa8d1" + c2 = repo.commit("d46e3fe") + c3 = "763ef75" self.assertRaises(ValueError, repo.merge_base) - self.assertRaises(ValueError, repo.merge_base, 'foo') + self.assertRaises(ValueError, repo.merge_base, "foo") # two commit merge-base res = repo.merge_base(c1, c2) self.assertIsInstance(res, list) self.assertEqual(len(res), 1) self.assertIsInstance(res[0], Commit) - self.assertTrue(res[0].hexsha.startswith('3936084')) + self.assertTrue(res[0].hexsha.startswith("3936084")) - for kw in ('a', 'all'): + for kw in ("a", "all"): res = repo.merge_base(c1, c2, c3, **{kw: True}) self.assertIsInstance(res, list) self.assertEqual(len(res), 1) # end for each keyword signalling all merge-bases to be returned # Test for no merge base - can't do as we have - self.assertRaises(GitCommandError, repo.merge_base, c1, 'ffffff') + self.assertRaises(GitCommandError, repo.merge_base, c1, "ffffff") def test_is_ancestor(self): git = self.rorepo.git @@ -980,23 +1068,23 @@ class TestRepo(TestBase): raise SkipTest("git merge-base --is-ancestor feature unsupported") repo = self.rorepo - c1 = 'f6aa8d1' - c2 = '763ef75' + c1 = "f6aa8d1" + c2 = "763ef75" self.assertTrue(repo.is_ancestor(c1, c1)) self.assertTrue(repo.is_ancestor("master", "master")) self.assertTrue(repo.is_ancestor(c1, c2)) self.assertTrue(repo.is_ancestor(c1, "master")) self.assertFalse(repo.is_ancestor(c2, c1)) self.assertFalse(repo.is_ancestor("master", c1)) - for i, j in itertools.permutations([c1, 'ffffff', ''], r=2): + for i, j in itertools.permutations([c1, "ffffff", ""], r=2): self.assertRaises(GitCommandError, repo.is_ancestor, i, j) def test_is_valid_object(self): repo = self.rorepo - commit_sha = 'f6aa8d1' - blob_sha = '1fbe3e4375' - tree_sha = '960b40fe36' - tag_sha = '42c2f60c43' + commit_sha = "f6aa8d1" + blob_sha = "1fbe3e4375" + tree_sha = "960b40fe36" + tag_sha = "42c2f60c43" # Check for valid objects self.assertTrue(repo.is_valid_object(commit_sha)) @@ -1005,19 +1093,21 @@ class TestRepo(TestBase): self.assertTrue(repo.is_valid_object(tag_sha)) # Check for valid objects of specific type - self.assertTrue(repo.is_valid_object(commit_sha, 'commit')) - self.assertTrue(repo.is_valid_object(blob_sha, 'blob')) - self.assertTrue(repo.is_valid_object(tree_sha, 'tree')) - self.assertTrue(repo.is_valid_object(tag_sha, 'tag')) + self.assertTrue(repo.is_valid_object(commit_sha, "commit")) + self.assertTrue(repo.is_valid_object(blob_sha, "blob")) + self.assertTrue(repo.is_valid_object(tree_sha, "tree")) + self.assertTrue(repo.is_valid_object(tag_sha, "tag")) # Check for invalid objects - self.assertFalse(repo.is_valid_object(b'1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a', 'blob')) + self.assertFalse( + repo.is_valid_object(b"1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a", "blob") + ) # Check for invalid objects of specific type - self.assertFalse(repo.is_valid_object(commit_sha, 'blob')) - self.assertFalse(repo.is_valid_object(blob_sha, 'commit')) - self.assertFalse(repo.is_valid_object(tree_sha, 'commit')) - self.assertFalse(repo.is_valid_object(tag_sha, 'commit')) + self.assertFalse(repo.is_valid_object(commit_sha, "blob")) + self.assertFalse(repo.is_valid_object(blob_sha, "commit")) + self.assertFalse(repo.is_valid_object(tree_sha, "commit")) + self.assertFalse(repo.is_valid_object(tag_sha, "commit")) @with_rw_directory def test_git_work_tree_dotgit(self, rw_dir): @@ -1027,12 +1117,12 @@ class TestRepo(TestBase): if git.version_info[:3] < (2, 5, 1): raise SkipTest("worktree feature unsupported") - rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo')) - branch = rw_master.create_head('aaaaaaaa') - worktree_path = join_path_native(rw_dir, 'worktree_repo') + rw_master = self.rorepo.clone(join_path_native(rw_dir, "master_repo")) + branch = rw_master.create_head("aaaaaaaa") + worktree_path = join_path_native(rw_dir, "worktree_repo") if Git.is_cygwin(): worktree_path = cygpath(worktree_path) - rw_master.git.worktree('add', worktree_path, branch.name) + rw_master.git.worktree("add", worktree_path, branch.name) # this ensures that we can read the repo's gitdir correctly repo = Repo(worktree_path) @@ -1048,7 +1138,7 @@ class TestRepo(TestBase): origin = repo.remotes.origin self.assertIsInstance(origin, Remote) - self.assertIsInstance(repo.heads['aaaaaaaa'], Head) + self.assertIsInstance(repo.heads["aaaaaaaa"], Head) @with_rw_directory def test_git_work_tree_env(self, rw_dir): @@ -1057,18 +1147,18 @@ class TestRepo(TestBase): # move .git directory to a subdirectory # set GIT_DIR and GIT_WORK_TREE appropriately # check that repo.working_tree_dir == rw_dir - self.rorepo.clone(join_path_native(rw_dir, 'master_repo')) + self.rorepo.clone(join_path_native(rw_dir, "master_repo")) - repo_dir = join_path_native(rw_dir, 'master_repo') - old_git_dir = join_path_native(repo_dir, '.git') - new_subdir = join_path_native(repo_dir, 'gitdir') - new_git_dir = join_path_native(new_subdir, 'git') + repo_dir = join_path_native(rw_dir, "master_repo") + old_git_dir = join_path_native(repo_dir, ".git") + new_subdir = join_path_native(repo_dir, "gitdir") + new_git_dir = join_path_native(new_subdir, "git") os.mkdir(new_subdir) os.rename(old_git_dir, new_git_dir) oldenv = os.environ.copy() - os.environ['GIT_DIR'] = new_git_dir - os.environ['GIT_WORK_TREE'] = repo_dir + os.environ["GIT_DIR"] = new_git_dir + os.environ["GIT_WORK_TREE"] = repo_dir try: r = Repo() @@ -1080,15 +1170,18 @@ class TestRepo(TestBase): @with_rw_directory def test_rebasing(self, rw_dir): r = Repo.init(rw_dir) - fp = osp.join(rw_dir, 'hello.txt') - r.git.commit("--allow-empty", message="init",) - with open(fp, 'w') as fs: + fp = osp.join(rw_dir, "hello.txt") + r.git.commit( + "--allow-empty", + message="init", + ) + with open(fp, "w") as fs: fs.write("hello world") r.git.add(Git.polish_url(fp)) r.git.commit(message="English") self.assertEqual(r.currently_rebasing_on(), None) r.git.checkout("HEAD^1") - with open(fp, 'w') as fs: + with open(fp, "w") as fs: fs.write("Hola Mundo") r.git.add(Git.polish_url(fp)) r.git.commit(message="Spanish") @@ -1102,9 +1195,11 @@ class TestRepo(TestBase): @with_rw_directory def test_do_not_strip_newline_in_stdout(self, rw_dir): r = Repo.init(rw_dir) - fp = osp.join(rw_dir, 'hello.txt') - with open(fp, 'w') as fs: + fp = osp.join(rw_dir, "hello.txt") + with open(fp, "w") as fs: fs.write("hello\n") r.git.add(Git.polish_url(fp)) r.git.commit(message="init") - self.assertEqual(r.git.show("HEAD:hello.txt", strip_newline_in_stdout=False), 'hello\n') + self.assertEqual( + r.git.show("HEAD:hello.txt", strip_newline_in_stdout=False), "hello\n" + ) diff --git a/test/test_stats.py b/test/test_stats.py index 2759698a..1f689655 100644 --- a/test/test_stats.py +++ b/test/test_stats.py @@ -4,27 +4,23 @@ # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php -from test.lib import ( - TestBase, - fixture -) +from test.lib import TestBase, fixture from git import Stats from git.compat import defenc class TestStats(TestBase): - def test_list_from_string(self): - output = fixture('diff_numstat').decode(defenc) + output = fixture("diff_numstat").decode(defenc) stats = Stats._list_from_string(self.rorepo, output) - self.assertEqual(2, stats.total['files']) - self.assertEqual(52, stats.total['lines']) - self.assertEqual(29, stats.total['insertions']) - self.assertEqual(23, stats.total['deletions']) + self.assertEqual(2, stats.total["files"]) + self.assertEqual(52, stats.total["lines"]) + self.assertEqual(29, stats.total["insertions"]) + self.assertEqual(23, stats.total["deletions"]) - self.assertEqual(29, stats.files["a.txt"]['insertions']) - self.assertEqual(18, stats.files["a.txt"]['deletions']) + self.assertEqual(29, stats.files["a.txt"]["insertions"]) + self.assertEqual(18, stats.files["a.txt"]["deletions"]) - self.assertEqual(0, stats.files["b.txt"]['insertions']) - self.assertEqual(5, stats.files["b.txt"]['deletions']) + self.assertEqual(0, stats.files["b.txt"]["insertions"]) + self.assertEqual(5, stats.files["b.txt"]["deletions"]) diff --git a/test/test_submodule.py b/test/test_submodule.py index a79123dc..fc96391d 100644 --- a/test/test_submodule.py +++ b/test/test_submodule.py @@ -9,20 +9,11 @@ import git from git.cmd import Git from git.compat import is_win from git.config import GitConfigParser, cp -from git.exc import ( - InvalidGitRepositoryError, - RepositoryDirtyError -) +from git.exc import InvalidGitRepositoryError, RepositoryDirtyError from git.objects.submodule.base import Submodule from git.objects.submodule.root import RootModule, RootUpdateProgress -from git.repo.fun import ( - find_submodule_git_dir, - touch -) -from test.lib import ( - TestBase, - with_rw_repo -) +from git.repo.fun import find_submodule_git_dir, touch +from test.lib import TestBase, with_rw_repo from test.lib import with_rw_directory from git.util import HIDE_WINDOWS_KNOWN_ERRORS from git.util import to_native_path_linux, join_path_native @@ -32,7 +23,7 @@ import os.path as osp class TestRootProgress(RootUpdateProgress): """Just prints messages, for now without checking the correctness of the states""" - def update(self, op, cur_count, max_count, message=''): + def update(self, op, cur_count, max_count, message=""): print(op, cur_count, max_count, message) @@ -40,9 +31,9 @@ prog = TestRootProgress() class TestSubmodule(TestBase): - def tearDown(self): import gc + gc.collect() k_subm_current = "c15a6e1923a14bc760851913858a3942a4193cdb" @@ -54,7 +45,7 @@ class TestSubmodule(TestBase): # manual instantiation smm = Submodule(rwrepo, "\0" * 20) # name needs to be set in advance - self.assertRaises(AttributeError, getattr, smm, 'name') + self.assertRaises(AttributeError, getattr, smm, "name") # iterate - 1 submodule sms = Submodule.list_items(rwrepo, self.k_subm_current) @@ -64,11 +55,13 @@ class TestSubmodule(TestBase): # at a different time, there is None assert len(Submodule.list_items(rwrepo, self.k_no_subm_tag)) == 0 - assert sm.path == 'git/ext/gitdb' - assert sm.path != sm.name # in our case, we have ids there, which don't equal the path - assert sm.url.endswith('github.com/gitpython-developers/gitdb.git') - assert sm.branch_path == 'refs/heads/master' # the default ... - assert sm.branch_name == 'master' + assert sm.path == "git/ext/gitdb" + assert ( + sm.path != sm.name + ) # in our case, we have ids there, which don't equal the path + assert sm.url.endswith("github.com/gitpython-developers/gitdb.git") + assert sm.branch_path == "refs/heads/master" # the default ... + assert sm.branch_name == "master" assert sm.parent_commit == rwrepo.head.commit # size is always 0 assert sm.size == 0 @@ -76,7 +69,7 @@ class TestSubmodule(TestBase): self.assertRaises(InvalidGitRepositoryError, sm.module) # which is why we can't get the branch either - it points into the module() repository - self.assertRaises(InvalidGitRepositoryError, getattr, sm, 'branch') + self.assertRaises(InvalidGitRepositoryError, getattr, sm, "branch") # branch_path works, as its just a string assert isinstance(sm.branch_path, str) @@ -84,16 +77,16 @@ class TestSubmodule(TestBase): # some commits earlier we still have a submodule, but its at a different commit smold = next(Submodule.iter_items(rwrepo, self.k_subm_changed)) assert smold.binsha != sm.binsha - assert smold != sm # the name changed + assert smold != sm # the name changed # force it to reread its information - del(smold._url) + del smold._url smold.url == sm.url # @NoEffect # test config_reader/writer methods sm.config_reader() - new_smclone_path = None # keep custom paths for later - new_csmclone_path = None # + new_smclone_path = None # keep custom paths for later + new_csmclone_path = None # if rwrepo.bare: with self.assertRaises(InvalidGitRepositoryError): with sm.config_writer() as cw: @@ -101,10 +94,12 @@ class TestSubmodule(TestBase): else: with sm.config_writer() as writer: # for faster checkout, set the url to the local path - new_smclone_path = Git.polish_url(osp.join(self.rorepo.working_tree_dir, sm.path)) - writer.set_value('url', new_smclone_path) + new_smclone_path = Git.polish_url( + osp.join(self.rorepo.working_tree_dir, sm.path) + ) + writer.set_value("url", new_smclone_path) writer.release() - assert sm.config_reader().get_value('url') == new_smclone_path + assert sm.config_reader().get_value("url") == new_smclone_path assert sm.url == new_smclone_path # END handle bare repo smold.config_reader() @@ -134,7 +129,9 @@ class TestSubmodule(TestBase): if rwrepo.bare: self.assertRaises(InvalidGitRepositoryError, sm.module) self.assertRaises(InvalidGitRepositoryError, sm.remove) - self.assertRaises(InvalidGitRepositoryError, sm.add, rwrepo, 'here', 'there') + self.assertRaises( + InvalidGitRepositoryError, sm.add, rwrepo, "here", "there" + ) else: # its not checked out in our case self.assertRaises(InvalidGitRepositoryError, sm.module) @@ -152,13 +149,15 @@ class TestSubmodule(TestBase): assert sma.path == sm.path # no url and no module at path fails - self.assertRaises(ValueError, Submodule.add, rwrepo, "newsubm", "pathtorepo", url=None) + self.assertRaises( + ValueError, Submodule.add, rwrepo, "newsubm", "pathtorepo", url=None + ) # CONTINUE UPDATE ################# # lets update it - its a recursive one too - newdir = osp.join(sm.abspath, 'dir') + newdir = osp.join(sm.abspath, "dir") os.makedirs(newdir) # update fails if the path already exists non-empty @@ -170,7 +169,7 @@ class TestSubmodule(TestBase): assert not sm.module_exists() assert sm.update() is sm - sm_repopath = sm.path # cache for later + sm_repopath = sm.path # cache for later assert sm.module_exists() assert isinstance(sm.module(), git.Repo) assert sm.module().working_tree_dir == sm.abspath @@ -179,7 +178,14 @@ class TestSubmodule(TestBase): ##################### # url must match the one in the existing repository ( if submodule name suggests a new one ) # or we raise - self.assertRaises(ValueError, Submodule.add, rwrepo, "newsubm", sm.path, "git://someurl/repo.git") + self.assertRaises( + ValueError, + Submodule.add, + rwrepo, + "newsubm", + sm.path, + "git://someurl/repo.git", + ) # CONTINUE UPDATE ################# @@ -197,15 +203,17 @@ class TestSubmodule(TestBase): sm.update(recursive=False) assert len(list(rwrepo.iter_submodules())) == 2 - assert len(sm.children()) == 1 # its not checked out yet + assert len(sm.children()) == 1 # its not checked out yet csm = sm.children()[0] assert not csm.module_exists() csm_repopath = csm.path # adjust the path of the submodules module to point to the local destination - new_csmclone_path = Git.polish_url(osp.join(self.rorepo.working_tree_dir, sm.path, csm.path)) + new_csmclone_path = Git.polish_url( + osp.join(self.rorepo.working_tree_dir, sm.path, csm.path) + ) with csm.config_writer() as writer: - writer.set_value('url', new_csmclone_path) + writer.set_value("url", new_csmclone_path) assert csm.url == new_csmclone_path # dry-run does nothing @@ -226,26 +234,34 @@ class TestSubmodule(TestBase): # reset both heads to the previous version, verify that to_latest_revision works smods = (sm.module(), csm.module()) for repo in smods: - repo.head.reset('HEAD~2', working_tree=1) + repo.head.reset("HEAD~2", working_tree=1) # END for each repo to reset # dry run does nothing - self.assertRaises(RepositoryDirtyError, sm.update, recursive=True, dry_run=True, progress=prog) + self.assertRaises( + RepositoryDirtyError, + sm.update, + recursive=True, + dry_run=True, + progress=prog, + ) sm.update(recursive=True, dry_run=True, progress=prog, force=True) for repo in smods: assert repo.head.commit != repo.head.ref.tracking_branch().commit # END for each repo to check - self.assertRaises(RepositoryDirtyError, sm.update, recursive=True, to_latest_revision=True) + self.assertRaises( + RepositoryDirtyError, sm.update, recursive=True, to_latest_revision=True + ) sm.update(recursive=True, to_latest_revision=True, force=True) for repo in smods: assert repo.head.commit == repo.head.ref.tracking_branch().commit # END for each repo to check - del(smods) + del smods # if the head is detached, it still works ( but warns ) smref = sm.module().head.ref - sm.module().head.ref = 'HEAD~1' + sm.module().head.ref = "HEAD~1" # if there is no tracking branch, we get a warning as well csm_tracking_branch = csm.module().head.ref.tracking_branch() csm.module().head.ref.set_tracking_branch(None) @@ -268,8 +284,10 @@ class TestSubmodule(TestBase): # to GitHub. To save time, we will change it to csm.set_parent_commit(csm.repo.head.commit) with csm.config_writer() as cw: - cw.set_value('url', self._small_repo_url()) - csm.repo.index.commit("adjusted URL to point to local source, instead of the internet") + cw.set_value("url", self._small_repo_url()) + csm.repo.index.commit( + "adjusted URL to point to local source, instead of the internet" + ) # We have modified the configuration, hence the index is dirty, and the # deletion will fail @@ -301,7 +319,7 @@ class TestSubmodule(TestBase): # but ... we have untracked files in the child submodule fn = join_path_native(csm.module().working_tree_dir, "newfile") - with open(fn, 'w') as fd: + with open(fn, "w") as fd: fd.write("hi") self.assertRaises(InvalidGitRepositoryError, sm.remove) @@ -323,14 +341,14 @@ class TestSubmodule(TestBase): sm.remove(configuration=False, force=True) assert sm.exists() assert not sm.module_exists() - assert sm.config_reader().get_value('url') + assert sm.config_reader().get_value("url") # delete the rest sm_path = sm.path sm.remove() assert not sm.exists() assert not sm.module_exists() - self.assertRaises(ValueError, getattr, sm, 'path') + self.assertRaises(ValueError, getattr, sm, "path") assert len(rwrepo.submodules) == 0 @@ -339,20 +357,35 @@ class TestSubmodule(TestBase): # add a simple remote repo - trailing slashes are no problem smid = "newsub" osmid = "othersub" - nsm = Submodule.add(rwrepo, smid, sm_repopath, new_smclone_path + "/", None, no_checkout=True) + nsm = Submodule.add( + rwrepo, + smid, + sm_repopath, + new_smclone_path + "/", + None, + no_checkout=True, + ) assert nsm.name == smid assert nsm.module_exists() assert nsm.exists() # its not checked out - assert not osp.isfile(join_path_native(nsm.module().working_tree_dir, Submodule.k_modules_file)) + assert not osp.isfile( + join_path_native( + nsm.module().working_tree_dir, Submodule.k_modules_file + ) + ) assert len(rwrepo.submodules) == 1 # add another submodule, but into the root, not as submodule - osm = Submodule.add(rwrepo, osmid, csm_repopath, new_csmclone_path, Submodule.k_head_default) + osm = Submodule.add( + rwrepo, osmid, csm_repopath, new_csmclone_path, Submodule.k_head_default + ) assert osm != nsm assert osm.module_exists() assert osm.exists() - assert osp.isfile(join_path_native(osm.module().working_tree_dir, 'setup.py')) + assert osp.isfile( + join_path_native(osm.module().working_tree_dir, "setup.py") + ) assert len(rwrepo.submodules) == 2 @@ -368,7 +401,9 @@ class TestSubmodule(TestBase): # MOVE MODULE ############# # invalid input - self.assertRaises(ValueError, nsm.move, 'doesntmatter', module=False, configuration=False) + self.assertRaises( + ValueError, nsm.move, "doesntmatter", module=False, configuration=False + ) # renaming to the same path does nothing assert nsm.move(sm_path) is nsm @@ -377,14 +412,14 @@ class TestSubmodule(TestBase): nmp = join_path_native("new", "module", "dir") + "/" # new module path pmp = nsm.path assert nsm.move(nmp) is nsm - nmp = nmp[:-1] # cut last / + nmp = nmp[:-1] # cut last / nmpl = to_native_path_linux(nmp) assert nsm.path == nmpl assert rwrepo.submodules[0].path == nmpl - mpath = 'newsubmodule' + mpath = "newsubmodule" absmpath = join_path_native(rwrepo.working_tree_dir, mpath) - open(absmpath, 'w').write('') + open(absmpath, "w").write("") self.assertRaises(ValueError, nsm.move, mpath) os.remove(absmpath) @@ -402,11 +437,19 @@ class TestSubmodule(TestBase): for remote in osmod.remotes: remote.remove(osmod, remote.name) assert not osm.exists() - self.assertRaises(ValueError, Submodule.add, rwrepo, osmid, csm_repopath, url=None) + self.assertRaises( + ValueError, Submodule.add, rwrepo, osmid, csm_repopath, url=None + ) # END handle bare mode # Error if there is no submodule file here - self.assertRaises(IOError, Submodule._config_parser, rwrepo, rwrepo.commit(self.k_no_subm_tag), True) + self.assertRaises( + IOError, + Submodule._config_parser, + rwrepo, + rwrepo.commit(self.k_no_subm_tag), + True, + ) # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, ## ACTUALLY skipped by `git.submodule.base#L869`. # "FIXME: fails with: PermissionError: [WinError 32] The process cannot access the file because" @@ -420,11 +463,14 @@ class TestSubmodule(TestBase): def test_base_bare(self, rwrepo): self._do_base_tests(rwrepo) - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, """ + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS, + """ File "C:\\projects\\gitpython\\git\\cmd.py", line 559, in execute raise GitCommandNotFound(command, err) git.exc.GitCommandNotFound: Cmd('git') not found due to: OSError('[WinError 6] The handle is invalid') - cmdline: git clone -n --shared -v C:\\projects\\gitpython\\.git Users\\appveyor\\AppData\\Local\\Temp\\1\\tmplyp6kr_rnon_bare_test_root_module""") # noqa E501 + cmdline: git clone -n --shared -v C:\\projects\\gitpython\\.git Users\\appveyor\\AppData\\Local\\Temp\\1\\tmplyp6kr_rnon_bare_test_root_module""", + ) # noqa E501 @with_rw_repo(k_subm_current, bare=False) def test_root_module(self, rwrepo): # Can query everything without problems @@ -447,10 +493,12 @@ class TestSubmodule(TestBase): # deep traversal gitdb / async rsmsp = [sm.path for sm in rm.traverse()] - assert len(rsmsp) >= 2 # gitdb and async [and smmap], async being a child of gitdb + assert ( + len(rsmsp) >= 2 + ) # gitdb and async [and smmap], async being a child of gitdb # cannot set the parent commit as root module's path didn't exist - self.assertRaises(ValueError, rm.set_parent_commit, 'HEAD') + self.assertRaises(ValueError, rm.set_parent_commit, "HEAD") # TEST UPDATE ############# @@ -460,16 +508,18 @@ class TestSubmodule(TestBase): # modify path without modifying the index entry # ( which is what the move method would do properly ) - #================================================== + # ================================================== sm = rm.children()[0] pp = "path/prefix" fp = join_path_native(pp, sm.path) prep = sm.path - assert not sm.module_exists() # was never updated after rwrepo's clone + assert not sm.module_exists() # was never updated after rwrepo's clone # assure we clone from a local source with sm.config_writer() as writer: - writer.set_value('url', Git.polish_url(osp.join(self.rorepo.working_tree_dir, sm.path))) + writer.set_value( + "url", Git.polish_url(osp.join(self.rorepo.working_tree_dir, sm.path)) + ) # dry-run does nothing sm.update(recursive=False, dry_run=True, progress=prog) @@ -478,7 +528,9 @@ class TestSubmodule(TestBase): sm.update(recursive=False) assert sm.module_exists() with sm.config_writer() as writer: - writer.set_value('path', fp) # change path to something with prefix AFTER url change + writer.set_value( + "path", fp + ) # change path to something with prefix AFTER url change # update doesn't fail, because list_items ignores the wrong path in such situations. rm.update(recursive=False) @@ -488,7 +540,7 @@ class TestSubmodule(TestBase): self.assertRaises(InvalidGitRepositoryError, sm.move, pp) # reset the path(cache) to where it was, now it works sm.path = prep - sm.move(fp, module=False) # leave it at the old location + sm.move(fp, module=False) # leave it at the old location assert not sm.module_exists() cpathchange = rwrepo.index.commit("changed sm path") # finally we can commit @@ -499,12 +551,16 @@ class TestSubmodule(TestBase): assert sm.module_exists() # add submodule - #================ + # ================ nsmn = "newsubmodule" nsmp = "submrepo" - subrepo_url = Git.polish_url(osp.join(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1])) + subrepo_url = Git.polish_url( + osp.join(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1]) + ) nsm = Submodule.add(rwrepo, nsmn, nsmp, url=subrepo_url) - csmadded = rwrepo.index.commit("Added submodule").hexsha # make sure we don't keep the repo reference + csmadded = rwrepo.index.commit( + "Added submodule" + ).hexsha # make sure we don't keep the repo reference nsm.set_parent_commit(csmadded) assert nsm.module_exists() # in our case, the module should not exist, which happens if we update a parent @@ -520,11 +576,11 @@ class TestSubmodule(TestBase): assert nsm.module_exists() # remove submodule - the previous one - #==================================== + # ==================================== sm.set_parent_commit(csmadded) smp = sm.abspath assert not sm.remove(module=False).exists() - assert osp.isdir(smp) # module still exists + assert osp.isdir(smp) # module still exists csmremoved = rwrepo.index.commit("Removed submodule") # an update will remove the module @@ -535,37 +591,45 @@ class TestSubmodule(TestBase): # when removing submodules, we may get new commits as nested submodules are auto-committing changes # to allow deletions without force, as the index would be dirty otherwise. # QUESTION: Why does this seem to work in test_git_submodule_compatibility() ? - self.assertRaises(InvalidGitRepositoryError, rm.update, recursive=False, force_remove=False) + self.assertRaises( + InvalidGitRepositoryError, rm.update, recursive=False, force_remove=False + ) rm.update(recursive=False, force_remove=True) assert not osp.isdir(smp) # 'apply work' to the nested submodule and assure this is not removed/altered during updates # Need to commit first, otherwise submodule.update wouldn't have a reason to change the head - touch(osp.join(nsm.module().working_tree_dir, 'new-file')) + touch(osp.join(nsm.module().working_tree_dir, "new-file")) # We cannot expect is_dirty to even run as we wouldn't reset a head to the same location assert nsm.module().head.commit.hexsha == nsm.hexsha nsm.module().index.add([nsm]) nsm.module().index.commit("added new file") - rm.update(recursive=False, dry_run=True, progress=prog) # would not change head, and thus doesn't fail + rm.update( + recursive=False, dry_run=True, progress=prog + ) # would not change head, and thus doesn't fail # Everything we can do from now on will trigger the 'future' check, so no is_dirty() check will even run # This would only run if our local branch is in the past and we have uncommitted changes prev_commit = nsm.module().head.commit rm.update(recursive=False, dry_run=False, progress=prog) - assert prev_commit == nsm.module().head.commit, "head shouldn't change, as it is in future of remote branch" + assert ( + prev_commit == nsm.module().head.commit + ), "head shouldn't change, as it is in future of remote branch" # this kills the new file rm.update(recursive=True, progress=prog, force_reset=True) - assert prev_commit != nsm.module().head.commit, "head changed, as the remote url and its commit changed" + assert ( + prev_commit != nsm.module().head.commit + ), "head changed, as the remote url and its commit changed" # change url ... - #=============== + # =============== # ... to the first repository, this way we have a fast checkout, and a completely different # repository at the different url nsm.set_parent_commit(csmremoved) nsmurl = Git.polish_url(osp.join(self.rorepo.working_tree_dir, rsmsp[0])) with nsm.config_writer() as writer: - writer.set_value('url', nsmurl) + writer.set_value("url", nsmurl) csmpathchange = rwrepo.index.commit("changed url") nsm.set_parent_commit(csmpathchange) @@ -579,7 +643,9 @@ class TestSubmodule(TestBase): assert nsm.module().remotes.origin.url == nsmurl assert prev_commit != nsm.module().head.commit, "Should now point to gitdb" assert len(rwrepo.submodules) == 1 - assert not rwrepo.submodules[0].children()[0].module_exists(), "nested submodule should not be checked out" + assert ( + not rwrepo.submodules[0].children()[0].module_exists() + ), "nested submodule should not be checked out" # add the submodule's changed commit to the index, which is what the # user would do @@ -588,7 +654,7 @@ class TestSubmodule(TestBase): rwrepo.index.add([nsm]) # change branch - #================= + # ================= # we only have one branch, so we switch to a virtual one, and back # to the current one to trigger the difference cur_branch = nsm.branch @@ -603,7 +669,7 @@ class TestSubmodule(TestBase): # Lets remove our tracking branch to simulate some changes nsmmh = nsmm.head - assert nsmmh.ref.tracking_branch() is None # never set it up until now + assert nsmmh.ref.tracking_branch() is None # never set it up until now assert not nsmmh.is_detached # dry run does nothing @@ -625,8 +691,8 @@ class TestSubmodule(TestBase): # assure we pull locally only nsmc = nsm.children()[0] with nsmc.config_writer() as writer: - writer.set_value('url', subrepo_url) - rm.update(recursive=True, progress=prog, dry_run=True) # just to run the code + writer.set_value("url", subrepo_url) + rm.update(recursive=True, progress=prog, dry_run=True) # just to run the code rm.update(recursive=True, progress=prog) # gitdb: has either 1 or 2 submodules depending on the version @@ -636,41 +702,57 @@ class TestSubmodule(TestBase): def test_first_submodule(self, rwrepo): assert len(list(rwrepo.iter_submodules())) == 0 - for sm_name, sm_path in (('first', 'submodules/first'), - ('second', osp.join(rwrepo.working_tree_dir, 'submodules/second'))): - sm = rwrepo.create_submodule(sm_name, sm_path, rwrepo.git_dir, no_checkout=True) + for sm_name, sm_path in ( + ("first", "submodules/first"), + ("second", osp.join(rwrepo.working_tree_dir, "submodules/second")), + ): + sm = rwrepo.create_submodule( + sm_name, sm_path, rwrepo.git_dir, no_checkout=True + ) assert sm.exists() and sm.module_exists() rwrepo.index.commit("Added submodule " + sm_name) # end for each submodule path to add - self.assertRaises(ValueError, rwrepo.create_submodule, 'fail', osp.expanduser('~')) - self.assertRaises(ValueError, rwrepo.create_submodule, 'fail-too', - rwrepo.working_tree_dir + osp.sep) + self.assertRaises( + ValueError, rwrepo.create_submodule, "fail", osp.expanduser("~") + ) + self.assertRaises( + ValueError, + rwrepo.create_submodule, + "fail-too", + rwrepo.working_tree_dir + osp.sep, + ) @with_rw_directory def test_add_empty_repo(self, rwdir): - empty_repo_dir = osp.join(rwdir, 'empty-repo') + empty_repo_dir = osp.join(rwdir, "empty-repo") - parent = git.Repo.init(osp.join(rwdir, 'parent')) + parent = git.Repo.init(osp.join(rwdir, "parent")) git.Repo.init(empty_repo_dir) for checkout_mode in range(2): - name = 'empty' + str(checkout_mode) - self.assertRaises(ValueError, parent.create_submodule, name, name, - url=empty_repo_dir, no_checkout=checkout_mode and True or False) + name = "empty" + str(checkout_mode) + self.assertRaises( + ValueError, + parent.create_submodule, + name, + name, + url=empty_repo_dir, + no_checkout=checkout_mode and True or False, + ) # end for each checkout mode @with_rw_directory def test_list_only_valid_submodules(self, rwdir): - repo_path = osp.join(rwdir, 'parent') + repo_path = osp.join(rwdir, "parent") repo = git.Repo.init(repo_path) - repo.git.submodule('add', self._small_repo_url(), 'module') + repo.git.submodule("add", self._small_repo_url(), "module") repo.index.commit("add submodule") assert len(repo.submodules) == 1 # Delete the directory from submodule - submodule_path = osp.join(repo_path, 'module') + submodule_path = osp.join(repo_path, "module") shutil.rmtree(submodule_path) repo.git.add([submodule_path]) repo.index.commit("remove submodule") @@ -678,18 +760,20 @@ class TestSubmodule(TestBase): repo = git.Repo(repo_path) assert len(repo.submodules) == 0 - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, - """FIXME on cygwin: File "C:\\projects\\gitpython\\git\\cmd.py", line 671, in execute + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS, + """FIXME on cygwin: File "C:\\projects\\gitpython\\git\\cmd.py", line 671, in execute raise GitCommandError(command, status, stderr_value, stdout_value) GitCommandError: Cmd('git') failed due to: exit code(128) cmdline: git add 1__Xava verbXXten 1_test _myfile 1_test_other_file 1_XXava-----verbXXten stderr: 'fatal: pathspec '"1__çava verböten"' did not match any files' FIXME on appveyor: see https://ci.appveyor.com/project/Byron/gitpython/build/1.0.185 - """) + """, + ) @with_rw_directory def test_git_submodules_and_add_sm_with_new_commit(self, rwdir): - parent = git.Repo.init(osp.join(rwdir, 'parent')) - parent.git.submodule('add', self._small_repo_url(), 'module') + parent = git.Repo.init(osp.join(rwdir, "parent")) + parent.git.submodule("add", self._small_repo_url(), "module") parent.index.commit("added submodule") assert len(parent.submodules) == 1 @@ -697,9 +781,11 @@ class TestSubmodule(TestBase): assert sm.exists() and sm.module_exists() - clone = git.Repo.clone_from(self._small_repo_url(), - osp.join(parent.working_tree_dir, 'existing-subrepository')) - sm2 = parent.create_submodule('nongit-file-submodule', clone.working_tree_dir) + clone = git.Repo.clone_from( + self._small_repo_url(), + osp.join(parent.working_tree_dir, "existing-subrepository"), + ) + sm2 = parent.create_submodule("nongit-file-submodule", clone.working_tree_dir) assert len(parent.submodules) == 2 for _ in range(2): @@ -709,26 +795,28 @@ class TestSubmodule(TestBase): # end for each init state # end for each iteration - sm.move(sm.path + '_moved') - sm2.move(sm2.path + '_moved') + sm.move(sm.path + "_moved") + sm2.move(sm2.path + "_moved") parent.index.commit("moved submodules") with sm.config_writer() as writer: - writer.set_value('user.email', 'example@example.com') - writer.set_value('user.name', 'me') + writer.set_value("user.email", "example@example.com") + writer.set_value("user.name", "me") smm = sm.module() - fp = osp.join(smm.working_tree_dir, 'empty-file') - with open(fp, 'w'): + fp = osp.join(smm.working_tree_dir, "empty-file") + with open(fp, "w"): pass smm.git.add(Git.polish_url(fp)) smm.git.commit(m="new file added") # submodules are retrieved from the current commit's tree, therefore we can't really get a new submodule # object pointing to the new submodule commit - sm_too = parent.submodules['module_moved'] + sm_too = parent.submodules["module_moved"] assert parent.head.commit.tree[sm.path].binsha == sm.binsha - assert sm_too.binsha == sm.binsha, "cached submodule should point to the same commit as updated one" + assert ( + sm_too.binsha == sm.binsha + ), "cached submodule should point to the same commit as updated one" added_bies = parent.index.add([sm]) # added base-index-entries assert len(added_bies) == 1 @@ -751,21 +839,24 @@ class TestSubmodule(TestBase): # "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\test_work_tree_unsupportedryfa60di\\master_repo\\.git\\objects\\pack\\pack-bc9e0787aef9f69e1591ef38ea0a6f566ec66fe3.idx") # noqa E501 @with_rw_directory def test_git_submodule_compatibility(self, rwdir): - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_path = join_path_native('submodules', 'intermediate', 'one') - sm = parent.create_submodule('mymodules/myname', sm_path, url=self._small_repo_url()) + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_path = join_path_native("submodules", "intermediate", "one") + sm = parent.create_submodule( + "mymodules/myname", sm_path, url=self._small_repo_url() + ) parent.index.commit("added submodule") def assert_exists(sm, value=True): assert sm.exists() == value assert sm.module_exists() == value + # end # As git is backwards compatible itself, it would still recognize what we do here ... unless we really # muss it up. That's the only reason why the test is still here ... . assert len(parent.git.submodule().splitlines()) == 1 - module_repo_path = osp.join(sm.module().working_tree_dir, '.git') + module_repo_path = osp.join(sm.module().working_tree_dir, ".git") assert module_repo_path.startswith(osp.join(parent.working_tree_dir, sm_path)) if not sm._need_gitfile_submodules(parent.git): assert osp.isdir(module_repo_path) @@ -773,17 +864,22 @@ class TestSubmodule(TestBase): else: assert osp.isfile(module_repo_path) assert sm.module().has_separate_working_tree() - assert find_submodule_git_dir(module_repo_path) is not None, "module pointed to by .git file must be valid" + assert ( + find_submodule_git_dir(module_repo_path) is not None + ), "module pointed to by .git file must be valid" # end verify submodule 'style' # test move - new_sm_path = join_path_native('submodules', 'one') + new_sm_path = join_path_native("submodules", "one") sm.move(new_sm_path) assert_exists(sm) # Add additional submodule level - csm = sm.module().create_submodule('nested-submodule', join_path_native('nested-submodule', 'working-tree'), - url=self._small_repo_url()) + csm = sm.module().create_submodule( + "nested-submodule", + join_path_native("nested-submodule", "working-tree"), + url=self._small_repo_url(), + ) sm.module().index.commit("added nested submodule") sm_head_commit = sm.module().commit() assert_exists(csm) @@ -796,24 +892,36 @@ class TestSubmodule(TestBase): # rename nested submodule # This name would move itself one level deeper - needs special handling internally - new_name = csm.name + '/mine' + new_name = csm.name + "/mine" assert csm.rename(new_name).name == new_name assert_exists(csm) - assert csm.repo.is_dirty(index=True, working_tree=False), "index must contain changed .gitmodules file" + assert csm.repo.is_dirty( + index=True, working_tree=False + ), "index must contain changed .gitmodules file" csm.repo.index.commit("renamed module") # keep_going evaluation rsm = parent.submodule_update() assert_exists(sm) assert_exists(csm) - with csm.config_writer().set_value('url', 'bar'): + with csm.config_writer().set_value("url", "bar"): pass - csm.repo.index.commit("Have to commit submodule change for algorithm to pick it up") - assert csm.url == 'bar' - - self.assertRaises(Exception, rsm.update, recursive=True, to_latest_revision=True, progress=prog) + csm.repo.index.commit( + "Have to commit submodule change for algorithm to pick it up" + ) + assert csm.url == "bar" + + self.assertRaises( + Exception, + rsm.update, + recursive=True, + to_latest_revision=True, + progress=prog, + ) assert_exists(csm) - rsm.update(recursive=True, to_latest_revision=True, progress=prog, keep_going=True) + rsm.update( + recursive=True, to_latest_revision=True, progress=prog, keep_going=True + ) # remove sm_module_path = sm.module().git_dir @@ -826,8 +934,8 @@ class TestSubmodule(TestBase): @with_rw_directory def test_remove_norefs(self, rwdir): - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'mymodules/myname' + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "mymodules/myname" sm = parent.create_submodule(sm_name, sm_name, url=self._small_repo_url()) assert sm.exists() @@ -835,24 +943,26 @@ class TestSubmodule(TestBase): assert sm.repo is parent # yoh was surprised since expected sm repo!! # so created a new instance for submodule - smrepo = git.Repo(osp.join(rwdir, 'parent', sm.path)) + smrepo = git.Repo(osp.join(rwdir, "parent", sm.path)) # Adding a remote without fetching so would have no references - smrepo.create_remote('special', 'git@server-shouldnotmatter:repo.git') + smrepo.create_remote("special", "git@server-shouldnotmatter:repo.git") # And we should be able to remove it just fine sm.remove() assert not sm.exists() @with_rw_directory def test_rename(self, rwdir): - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'mymodules/myname' + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "mymodules/myname" sm = parent.create_submodule(sm_name, sm_name, url=self._small_repo_url()) parent.index.commit("Added submodule") assert sm.rename(sm_name) is sm and sm.name == sm_name - assert not sm.repo.is_dirty(index=True, working_tree=False, untracked_files=False) + assert not sm.repo.is_dirty( + index=True, working_tree=False, untracked_files=False + ) - new_path = 'renamed/myname' + new_path = "renamed/myname" assert sm.move(new_path).name == new_path new_sm_name = "shortname" @@ -861,8 +971,12 @@ class TestSubmodule(TestBase): assert sm.exists() sm_mod = sm.module() - if osp.isfile(osp.join(sm_mod.working_tree_dir, '.git')) == sm._need_gitfile_submodules(parent.git): - assert sm_mod.git_dir.endswith(join_path_native('.git', 'modules', new_sm_name)) + if osp.isfile( + osp.join(sm_mod.working_tree_dir, ".git") + ) == sm._need_gitfile_submodules(parent.git): + assert sm_mod.git_dir.endswith( + join_path_native(".git", "modules", new_sm_name) + ) # end @with_rw_directory @@ -870,33 +984,41 @@ class TestSubmodule(TestBase): # Setup initial sandbox: # parent repo has one submodule, which has all the latest changes source_url = self._small_repo_url() - sm_source_repo = git.Repo.clone_from(source_url, osp.join(rw_dir, 'sm-source'), b='master') - parent_repo = git.Repo.init(osp.join(rw_dir, 'parent')) - sm = parent_repo.create_submodule('mysubmodule', 'subdir/submodule', - sm_source_repo.working_tree_dir, branch='master') - parent_repo.index.commit('added submodule') + sm_source_repo = git.Repo.clone_from( + source_url, osp.join(rw_dir, "sm-source"), b="master" + ) + parent_repo = git.Repo.init(osp.join(rw_dir, "parent")) + sm = parent_repo.create_submodule( + "mysubmodule", + "subdir/submodule", + sm_source_repo.working_tree_dir, + branch="master", + ) + parent_repo.index.commit("added submodule") assert sm.exists() # Create feature branch with one new commit in submodule source - sm_fb = sm_source_repo.create_head('feature') + sm_fb = sm_source_repo.create_head("feature") sm_fb.checkout() - new_file = touch(osp.join(sm_source_repo.working_tree_dir, 'new-file')) + new_file = touch(osp.join(sm_source_repo.working_tree_dir, "new-file")) sm_source_repo.index.add([new_file]) sm.repo.index.commit("added new file") # change designated submodule checkout branch to the new upstream feature branch with sm.config_writer() as smcw: - smcw.set_value('branch', sm_fb.name) + smcw.set_value("branch", sm_fb.name) assert sm.repo.is_dirty(index=True, working_tree=False) sm.repo.index.commit("changed submodule branch to '%s'" % sm_fb) # verify submodule update with feature branch that leaves currently checked out branch in it's past sm_mod = sm.module() prev_commit = sm_mod.commit() - assert sm_mod.head.ref.name == 'master' + assert sm_mod.head.ref.name == "master" assert parent_repo.submodule_update() assert sm_mod.head.ref.name == sm_fb.name - assert sm_mod.commit() == prev_commit, "Without to_latest_revision, we don't change the commit" + assert ( + sm_mod.commit() == prev_commit + ), "Without to_latest_revision, we don't change the commit" assert parent_repo.submodule_update(to_latest_revision=True) assert sm_mod.head.ref.name == sm_fb.name @@ -904,25 +1026,29 @@ class TestSubmodule(TestBase): # Create new branch which is in our past, and thus seemingly unrelated to the currently checked out one # To make it even 'harder', we shall fork and create a new commit - sm_pfb = sm_source_repo.create_head('past-feature', commit='HEAD~20') + sm_pfb = sm_source_repo.create_head("past-feature", commit="HEAD~20") sm_pfb.checkout() - sm_source_repo.index.add([touch(osp.join(sm_source_repo.working_tree_dir, 'new-file'))]) + sm_source_repo.index.add( + [touch(osp.join(sm_source_repo.working_tree_dir, "new-file"))] + ) sm_source_repo.index.commit("new file added, to past of '%r'" % sm_fb) # Change designated submodule checkout branch to a new commit in its own past with sm.config_writer() as smcw: - smcw.set_value('branch', sm_pfb.path) + smcw.set_value("branch", sm_pfb.path) sm.repo.index.commit("changed submodule branch to '%s'" % sm_pfb) # Test submodule updates - must fail if submodule is dirty - touch(osp.join(sm_mod.working_tree_dir, 'unstaged file')) + touch(osp.join(sm_mod.working_tree_dir, "unstaged file")) # This doesn't fail as our own submodule binsha didn't change, and the reset is only triggered if # to latest revision is True. parent_repo.submodule_update(to_latest_revision=False) sm_mod.head.ref.name == sm_pfb.name, "should have been switched to past head" sm_mod.commit() == sm_fb.commit, "Head wasn't reset" - self.assertRaises(RepositoryDirtyError, parent_repo.submodule_update, to_latest_revision=True) + self.assertRaises( + RepositoryDirtyError, parent_repo.submodule_update, to_latest_revision=True + ) parent_repo.submodule_update(to_latest_revision=True, force_reset=True) assert sm_mod.commit() == sm_pfb.commit, "Now head should have been reset" assert sm_mod.head.ref.name == sm_pfb.name @@ -930,83 +1056,116 @@ class TestSubmodule(TestBase): @skipIf(not is_win, "Specifically for Windows.") def test_to_relative_path_with_super_at_root_drive(self): class Repo(object): - working_tree_dir = 'D:\\' + working_tree_dir = "D:\\" + super_repo = Repo() - submodule_path = 'D:\\submodule_path' + submodule_path = "D:\\submodule_path" relative_path = Submodule._to_relative_path(super_repo, submodule_path) - msg = '_to_relative_path should be "submodule_path" but was "%s"' % relative_path - assert relative_path == 'submodule_path', msg - - @skipIf(True, 'for some unknown reason the assertion fails, even though it in fact is working in more common setup') + msg = ( + '_to_relative_path should be "submodule_path" but was "%s"' % relative_path + ) + assert relative_path == "submodule_path", msg + + @skipIf( + True, + "for some unknown reason the assertion fails, even though it in fact is working in more common setup", + ) @with_rw_directory def test_depth(self, rwdir): - parent = git.Repo.init(osp.join(rwdir, 'test_depth')) - sm_name = 'mymodules/myname' + parent = git.Repo.init(osp.join(rwdir, "test_depth")) + sm_name = "mymodules/myname" sm_depth = 1 - sm = parent.create_submodule(sm_name, sm_name, url=self._small_repo_url(), depth=sm_depth) + sm = parent.create_submodule( + sm_name, sm_name, url=self._small_repo_url(), depth=sm_depth + ) self.assertEqual(len(list(sm.module().iter_commits())), sm_depth) @with_rw_directory def test_update_clone_multi_options_argument(self, rwdir): - #Arrange - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'foo' + # Arrange + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "foo" sm_url = self._small_repo_url() - sm_branch = 'refs/heads/master' + sm_branch = "refs/heads/master" sm_hexsha = git.Repo(self._small_repo_url()).head.commit.hexsha - sm = Submodule(parent, bytes.fromhex(sm_hexsha), name=sm_name, path=sm_name, url=sm_url, - branch_path=sm_branch) - - #Act - sm.update(init=True, clone_multi_options=['--config core.eol=true']) - - #Assert - sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, 'modules', sm_name, 'config')) - self.assertTrue(sm_config.get_value('core', 'eol')) + sm = Submodule( + parent, + bytes.fromhex(sm_hexsha), + name=sm_name, + path=sm_name, + url=sm_url, + branch_path=sm_branch, + ) + + # Act + sm.update(init=True, clone_multi_options=["--config core.eol=true"]) + + # Assert + sm_config = GitConfigParser( + file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config") + ) + self.assertTrue(sm_config.get_value("core", "eol")) @with_rw_directory def test_update_no_clone_multi_options_argument(self, rwdir): - #Arrange - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'foo' + # Arrange + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "foo" sm_url = self._small_repo_url() - sm_branch = 'refs/heads/master' + sm_branch = "refs/heads/master" sm_hexsha = git.Repo(self._small_repo_url()).head.commit.hexsha - sm = Submodule(parent, bytes.fromhex(sm_hexsha), name=sm_name, path=sm_name, url=sm_url, - branch_path=sm_branch) - - #Act + sm = Submodule( + parent, + bytes.fromhex(sm_hexsha), + name=sm_name, + path=sm_name, + url=sm_url, + branch_path=sm_branch, + ) + + # Act sm.update(init=True) - #Assert - sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, 'modules', sm_name, 'config')) + # Assert + sm_config = GitConfigParser( + file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config") + ) with self.assertRaises(cp.NoOptionError): - sm_config.get_value('core', 'eol') + sm_config.get_value("core", "eol") @with_rw_directory def test_add_clone_multi_options_argument(self, rwdir): - #Arrange - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'foo' - - #Act - Submodule.add(parent, sm_name, sm_name, url=self._small_repo_url(), - clone_multi_options=['--config core.eol=true']) - - #Assert - sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, 'modules', sm_name, 'config')) - self.assertTrue(sm_config.get_value('core', 'eol')) + # Arrange + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "foo" + + # Act + Submodule.add( + parent, + sm_name, + sm_name, + url=self._small_repo_url(), + clone_multi_options=["--config core.eol=true"], + ) + + # Assert + sm_config = GitConfigParser( + file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config") + ) + self.assertTrue(sm_config.get_value("core", "eol")) @with_rw_directory def test_add_no_clone_multi_options_argument(self, rwdir): - #Arrange - parent = git.Repo.init(osp.join(rwdir, 'parent')) - sm_name = 'foo' + # Arrange + parent = git.Repo.init(osp.join(rwdir, "parent")) + sm_name = "foo" - #Act + # Act Submodule.add(parent, sm_name, sm_name, url=self._small_repo_url()) - #Assert - sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, 'modules', sm_name, 'config')) + # Assert + sm_config = GitConfigParser( + file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config") + ) with self.assertRaises(cp.NoOptionError): - sm_config.get_value('core', 'eol') + sm_config.get_value("core", "eol") diff --git a/test/test_tree.py b/test/test_tree.py index 24c401cb..97067fb2 100644 --- a/test/test_tree.py +++ b/test/test_tree.py @@ -7,10 +7,7 @@ from io import BytesIO from unittest import skipIf -from git.objects import ( - Tree, - Blob -) +from git.objects import Tree, Blob from test.lib import TestBase from git.util import HIDE_WINDOWS_KNOWN_ERRORS @@ -18,22 +15,24 @@ import os.path as osp class TestTree(TestBase): - - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, """ + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS, + """ File "C:\\projects\\gitpython\\git\\cmd.py", line 559, in execute raise GitCommandNotFound(command, err) git.exc.GitCommandNotFound: Cmd('git') not found due to: OSError('[WinError 6] The handle is invalid') - cmdline: git cat-file --batch-check""") + cmdline: git cat-file --batch-check""", + ) def test_serializable(self): # tree at the given commit contains a submodule as well - roottree = self.rorepo.tree('6c1faef799095f3990e9970bc2cb10aa0221cf9c') + roottree = self.rorepo.tree("6c1faef799095f3990e9970bc2cb10aa0221cf9c") for item in roottree.traverse(ignore_self=False): if item.type != Tree.type: continue # END skip non-trees tree = item # trees have no dict - self.assertRaises(AttributeError, setattr, tree, 'someattr', 1) + self.assertRaises(AttributeError, setattr, tree, "someattr", 1) orig_data = tree.data_stream.read() orig_cache = tree._cache @@ -43,22 +42,25 @@ class TestTree(TestBase): assert stream.getvalue() == orig_data stream.seek(0) - testtree = Tree(self.rorepo, Tree.NULL_BIN_SHA, 0, '') + testtree = Tree(self.rorepo, Tree.NULL_BIN_SHA, 0, "") testtree._deserialize(stream) assert testtree._cache == orig_cache # replaces cache, but we make sure of it - del(testtree._cache) + del testtree._cache testtree._deserialize(stream) # END for each item in tree - @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, """ + @skipIf( + HIDE_WINDOWS_KNOWN_ERRORS, + """ File "C:\\projects\\gitpython\\git\\cmd.py", line 559, in execute raise GitCommandNotFound(command, err) git.exc.GitCommandNotFound: Cmd('git') not found due to: OSError('[WinError 6] The handle is invalid') - cmdline: git cat-file --batch-check""") + cmdline: git cat-file --batch-check""", + ) def test_traverse(self): - root = self.rorepo.tree('0.1.6') + root = self.rorepo.tree("0.1.6") num_recursive = 0 all_items = [] for obj in root.traverse(): @@ -72,7 +74,7 @@ class TestTree(TestBase): # limit recursion level to 0 - should be same as default iteration assert all_items - assert 'CHANGES' in root + assert "CHANGES" in root assert len(list(root)) == len(list(root.traverse(depth=1))) # only choose trees @@ -87,7 +89,9 @@ class TestTree(TestBase): # trees and blobs assert len(set(trees) | set(root.trees)) == len(trees) - assert len({b for b in root if isinstance(b, Blob)} | set(root.blobs)) == len(root.blobs) + assert len({b for b in root if isinstance(b, Blob)} | set(root.blobs)) == len( + root.blobs + ) subitem = trees[0][0] assert "/" in subitem.path assert subitem.name == osp.basename(subitem.path) @@ -96,7 +100,7 @@ class TestTree(TestBase): found_slash = False for item in root.traverse(): assert osp.isabs(item.abspath) - if '/' in item.path: + if "/" in item.path: found_slash = True # END check for slash diff --git a/test/test_util.py b/test/test_util.py index a213b46c..b2903620 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -21,7 +21,8 @@ from git.objects.util import ( verify_utctz, parse_date, tzoffset, - from_timestamp) + from_timestamp, +) from test.lib import ( TestBase, with_rw_repo, @@ -39,35 +40,31 @@ from git.util import ( _norm_cygpath_pairs = ( - (r'foo\bar', 'foo/bar'), - (r'foo/bar', 'foo/bar'), - - (r'C:\Users', '/cygdrive/c/Users'), - (r'C:\d/e', '/cygdrive/c/d/e'), - - ('C:\\', '/cygdrive/c/'), - - (r'\\server\C$\Users', '//server/C$/Users'), - (r'\\server\C$', '//server/C$'), - ('\\\\server\\c$\\', '//server/c$/'), - (r'\\server\BAR/', '//server/BAR/'), - - (r'D:/Apps', '/cygdrive/d/Apps'), - (r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'), - (r'D:\Apps/123', '/cygdrive/d/Apps/123'), + (r"foo\bar", "foo/bar"), + (r"foo/bar", "foo/bar"), + (r"C:\Users", "/cygdrive/c/Users"), + (r"C:\d/e", "/cygdrive/c/d/e"), + ("C:\\", "/cygdrive/c/"), + (r"\\server\C$\Users", "//server/C$/Users"), + (r"\\server\C$", "//server/C$"), + ("\\\\server\\c$\\", "//server/c$/"), + (r"\\server\BAR/", "//server/BAR/"), + (r"D:/Apps", "/cygdrive/d/Apps"), + (r"D:/Apps\fOO", "/cygdrive/d/Apps/fOO"), + (r"D:\Apps/123", "/cygdrive/d/Apps/123"), ) _unc_cygpath_pairs = ( - (r'\\?\a:\com', '/cygdrive/a/com'), - (r'\\?\a:/com', '/cygdrive/a/com'), - - (r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'), + (r"\\?\a:\com", "/cygdrive/a/com"), + (r"\\?\a:/com", "/cygdrive/a/com"), + (r"\\?\UNC\server\D$\Apps", "//server/D$/Apps"), ) class TestIterableMember(object): """A member of an iterable list""" + __slots__ = "name" def __init__(self, name): @@ -79,7 +76,6 @@ class TestIterableMember(object): @ddt.ddt class TestUtils(TestBase): - def setup(self): self.testdict = { "string": "42", @@ -96,11 +92,11 @@ class TestUtils(TestBase): @skipIf(not is_win, "Paths specifically for Windows.") @ddt.data( - (r'./bar', 'bar'), - (r'.\bar', 'bar'), - (r'../bar', '../bar'), - (r'..\bar', '../bar'), - (r'../bar/.\foo/../chu', '../bar/chu'), + (r"./bar", "bar"), + (r".\bar", "bar"), + (r"../bar", "../bar"), + (r"..\bar", "../bar"), + (r"../bar/.\foo/../chu", "../bar/chu"), ) def test_cygpath_norm_ok(self, case): wpath, cpath = case @@ -109,27 +105,27 @@ class TestUtils(TestBase): @skipIf(not is_win, "Paths specifically for Windows.") @ddt.data( - r'C:', - r'C:Relative', - r'D:Apps\123', - r'D:Apps/123', - r'\\?\a:rel', - r'\\share\a:rel', + r"C:", + r"C:Relative", + r"D:Apps\123", + r"D:Apps/123", + r"\\?\a:rel", + r"\\share\a:rel", ) def test_cygpath_invalids(self, wpath): cwpath = cygpath(wpath) - self.assertEqual(cwpath, wpath.replace('\\', '/'), wpath) + self.assertEqual(cwpath, wpath.replace("\\", "/"), wpath) @skipIf(not is_win, "Paths specifically for Windows.") @ddt.idata(_norm_cygpath_pairs) def test_decygpath(self, case): wpath, cpath = case wcpath = decygpath(cpath) - self.assertEqual(wcpath, wpath.replace('/', '\\'), cpath) + self.assertEqual(wcpath, wpath.replace("/", "\\"), cpath) def test_it_should_dashify(self): - self.assertEqual('this-is-my-argument', dashify('this_is_my_argument')) - self.assertEqual('foo', dashify('foo')) + self.assertEqual("this-is-my-argument", dashify("this_is_my_argument")) + self.assertEqual("foo", dashify("foo")) def test_lock_file(self): my_file = tempfile.mktemp() @@ -154,7 +150,7 @@ class TestUtils(TestBase): self.assertRaises(IOError, lock_file._obtain_lock_or_raise) # auto-release on destruction - del(other_lock_file) + del other_lock_file lock_file._obtain_lock_or_raise() lock_file._release_lock() @@ -176,12 +172,18 @@ class TestUtils(TestBase): self.assertLess(elapsed, wait_time + extra_time) def test_user_id(self): - self.assertIn('@', get_user_id()) + self.assertIn("@", get_user_id()) def test_parse_date(self): # parse_date(from_timestamp()) must return the tuple unchanged - for timestamp, offset in (1522827734, -7200), (1522827734, 0), (1522827734, +3600): - self.assertEqual(parse_date(from_timestamp(timestamp, offset)), (timestamp, offset)) + for timestamp, offset in ( + (1522827734, -7200), + (1522827734, 0), + (1522827734, +3600), + ): + self.assertEqual( + parse_date(from_timestamp(timestamp, offset)), (timestamp, offset) + ) # test all supported formats def assert_rval(rval, veri_time, offset=0): @@ -195,6 +197,7 @@ class TestUtils(TestBase): utctz = altz_to_utctz_str(offset) self.assertIsInstance(utctz, str) self.assertEqual(utctz_to_altz(verify_utctz(utctz)), offset) + # END assert rval utility rfc = ("Thu, 07 Apr 2005 22:13:11 +0000", 0) @@ -203,16 +206,16 @@ class TestUtils(TestBase): iso3 = ("2005.04.07 22:13:11 -0000", 0) alt = ("04/07/2005 22:13:11", 0) alt2 = ("07.04.2005 22:13:11", 0) - veri_time_utc = 1112911991 # the time this represents, in time since epoch, UTC + veri_time_utc = 1112911991 # the time this represents, in time since epoch, UTC for date, offset in (rfc, iso, iso2, iso3, alt, alt2): assert_rval(parse_date(date), veri_time_utc, offset) # END for each date type # and failure self.assertRaises(ValueError, parse_date, datetime.now()) # non-aware datetime - self.assertRaises(ValueError, parse_date, 'invalid format') - self.assertRaises(ValueError, parse_date, '123456789 -02000') - self.assertRaises(ValueError, parse_date, ' 123456789 -0200') + self.assertRaises(ValueError, parse_date, "invalid format") + self.assertRaises(ValueError, parse_date, "123456789 -02000") + self.assertRaises(ValueError, parse_date, " 123456789 -0200") def test_actor(self): for cr in (None, self.rorepo.config_reader()): @@ -220,23 +223,23 @@ class TestUtils(TestBase): self.assertIsInstance(Actor.author(cr), Actor) # END assure config reader is handled - @with_rw_repo('HEAD') + @with_rw_repo("HEAD") @mock.patch("getpass.getuser") def test_actor_get_uid_laziness_not_called(self, rwrepo, mock_get_uid): with rwrepo.config_writer() as cw: cw.set_value("user", "name", "John Config Doe") cw.set_value("user", "email", "jcdoe@example.com") - + cr = rwrepo.config_reader() committer = Actor.committer(cr) author = Actor.author(cr) - - self.assertEqual(committer.name, 'John Config Doe') - self.assertEqual(committer.email, 'jcdoe@example.com') - self.assertEqual(author.name, 'John Config Doe') - self.assertEqual(author.email, 'jcdoe@example.com') + + self.assertEqual(committer.name, "John Config Doe") + self.assertEqual(committer.email, "jcdoe@example.com") + self.assertEqual(author.name, "John Config Doe") + self.assertEqual(author.email, "jcdoe@example.com") self.assertFalse(mock_get_uid.called) - + env = { "GIT_AUTHOR_NAME": "John Doe", "GIT_AUTHOR_EMAIL": "jdoe@example.com", @@ -247,10 +250,10 @@ class TestUtils(TestBase): for cr in (None, rwrepo.config_reader()): committer = Actor.committer(cr) author = Actor.author(cr) - self.assertEqual(committer.name, 'Jane Doe') - self.assertEqual(committer.email, 'jane@example.com') - self.assertEqual(author.name, 'John Doe') - self.assertEqual(author.email, 'jdoe@example.com') + self.assertEqual(committer.name, "Jane Doe") + self.assertEqual(committer.email, "jane@example.com") + self.assertEqual(author.name, "John Doe") + self.assertEqual(author.email, "jdoe@example.com") self.assertFalse(mock_get_uid.called) @mock.patch("getpass.getuser") @@ -260,20 +263,22 @@ class TestUtils(TestBase): author = Actor.author(None) # We can't test with `self.rorepo.config_reader()` here, as the uuid laziness # depends on whether the user running the test has their global user.name config set. - self.assertEqual(committer.name, 'user') - self.assertTrue(committer.email.startswith('user@')) - self.assertEqual(author.name, 'user') - self.assertTrue(committer.email.startswith('user@')) + self.assertEqual(committer.name, "user") + self.assertTrue(committer.email.startswith("user@")) + self.assertEqual(author.name, "user") + self.assertTrue(committer.email.startswith("user@")) self.assertTrue(mock_get_uid.called) self.assertEqual(mock_get_uid.call_count, 2) def test_actor_from_string(self): self.assertEqual(Actor._from_string("name"), Actor("name", None)) self.assertEqual(Actor._from_string("name <>"), Actor("name", "")) - self.assertEqual(Actor._from_string("name last another <some-very-long-email@example.com>"), - Actor("name last another", "some-very-long-email@example.com")) + self.assertEqual( + Actor._from_string("name last another <some-very-long-email@example.com>"), + Actor("name last another", "some-very-long-email@example.com"), + ) - @ddt.data(('name', ''), ('name', 'prefix_')) + @ddt.data(("name", ""), ("name", "prefix_")) def test_iterable_list(self, case): name, prefix = case ilist = IterableList(name, prefix) @@ -292,7 +297,7 @@ class TestUtils(TestBase): self.assertIn(name2, ilist) self.assertIn(m2, ilist) self.assertIn(m2, ilist) - self.assertNotIn('invalid', ilist) + self.assertNotIn("invalid", ilist) # with string index self.assertIs(ilist[name1], m1) @@ -307,34 +312,43 @@ class TestUtils(TestBase): self.assertIs(ilist.two, m2) # test exceptions - self.assertRaises(AttributeError, getattr, ilist, 'something') - self.assertRaises(IndexError, ilist.__getitem__, 'something') + self.assertRaises(AttributeError, getattr, ilist, "something") + self.assertRaises(IndexError, ilist.__getitem__, "something") # delete by name and index - self.assertRaises(IndexError, ilist.__delitem__, 'something') - del(ilist[name2]) + self.assertRaises(IndexError, ilist.__delitem__, "something") + del ilist[name2] self.assertEqual(len(ilist), 1) self.assertNotIn(name2, ilist) self.assertIn(name1, ilist) - del(ilist[0]) + del ilist[0] self.assertNotIn(name1, ilist) self.assertEqual(len(ilist), 0) self.assertRaises(IndexError, ilist.__delitem__, 0) - self.assertRaises(IndexError, ilist.__delitem__, 'something') + self.assertRaises(IndexError, ilist.__delitem__, "something") def test_from_timestamp(self): # Correct offset: UTC+2, should return datetime + tzoffset(+2) - altz = utctz_to_altz('+0200') - self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(altz)), from_timestamp(1522827734, altz)) + altz = utctz_to_altz("+0200") + self.assertEqual( + datetime.fromtimestamp(1522827734, tzoffset(altz)), + from_timestamp(1522827734, altz), + ) # Wrong offset: UTC+58, should return datetime + tzoffset(UTC) - altz = utctz_to_altz('+5800') - self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(0)), from_timestamp(1522827734, altz)) + altz = utctz_to_altz("+5800") + self.assertEqual( + datetime.fromtimestamp(1522827734, tzoffset(0)), + from_timestamp(1522827734, altz), + ) # Wrong offset: UTC-9000, should return datetime + tzoffset(UTC) - altz = utctz_to_altz('-9000') - self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(0)), from_timestamp(1522827734, altz)) + altz = utctz_to_altz("-9000") + self.assertEqual( + datetime.fromtimestamp(1522827734, tzoffset(0)), + from_timestamp(1522827734, altz), + ) def test_pickle_tzoffset(self): t1 = tzoffset(555) @@ -345,7 +359,9 @@ class TestUtils(TestBase): def test_remove_password_from_command_line(self): username = "fakeuser" password = "fakepassword1234" - url_with_user_and_pass = "https://{}:{}@fakerepo.example.com/testrepo".format(username, password) + url_with_user_and_pass = "https://{}:{}@fakerepo.example.com/testrepo".format( + username, password + ) url_with_user = "https://{}@fakerepo.example.com/testrepo".format(username) url_with_pass = "https://:{}@fakerepo.example.com/testrepo".format(password) url_without_user_or_pass = "https://fakerepo.example.com/testrepo" diff --git a/test/tstrunner.py b/test/tstrunner.py index a3bcfa3c..441050c6 100644 --- a/test/tstrunner.py +++ b/test/tstrunner.py @@ -1,6 +1,7 @@ import unittest + loader = unittest.TestLoader() -start_dir = '.' +start_dir = "." suite = loader.discover(start_dir) runner = unittest.TextTestRunner() |