aboutsummaryrefslogtreecommitdiff
path: root/git
diff options
context:
space:
mode:
Diffstat (limited to 'git')
-rw-r--r--git/__init__.py24
-rw-r--r--git/cmd.py3
-rw-r--r--git/compat.py23
-rw-r--r--git/config.py29
-rw-r--r--git/db.py4
-rw-r--r--git/exc.py2
-rw-r--r--git/index/base.py13
-rw-r--r--git/index/fun.py2
-rw-r--r--git/index/util.py11
-rw-r--r--git/objects/__init__.py16
-rw-r--r--git/objects/base.py2
-rw-r--r--git/objects/commit.py4
-rw-r--r--git/objects/fun.py4
-rw-r--r--git/objects/submodule/base.py92
-rw-r--r--git/objects/tag.py6
-rw-r--r--git/refs/head.py21
-rw-r--r--git/refs/reference.py2
-rw-r--r--git/refs/symbolic.py6
-rw-r--r--git/remote.py8
-rw-r--r--git/repo/base.py14
-rw-r--r--git/repo/fun.py2
-rw-r--r--git/test/lib/asserts.py14
-rw-r--r--git/test/lib/helper.py44
-rw-r--r--git/test/performance/lib.py1
-rw-r--r--git/test/performance/test_odb.py6
-rw-r--r--git/test/performance/test_streams.py4
-rw-r--r--git/test/test_commit.py2
-rw-r--r--git/test/test_config.py38
-rw-r--r--git/test/test_docs.py23
-rw-r--r--git/test/test_exc.py14
-rw-r--r--git/test/test_git.py4
-rw-r--r--git/test/test_index.py61
-rw-r--r--git/test/test_refs.py20
-rw-r--r--git/test/test_remote.py22
-rw-r--r--git/test/test_repo.py20
-rw-r--r--git/test/test_submodule.py149
-rw-r--r--git/test/test_tree.py19
-rw-r--r--git/test/test_util.py122
-rw-r--r--git/util.py29
39 files changed, 489 insertions, 391 deletions
diff --git a/git/__init__.py b/git/__init__.py
index e8dae272..58e4e7b6 100644
--- a/git/__init__.py
+++ b/git/__init__.py
@@ -4,7 +4,7 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
# flake8: noqa
-
+#@PydevCodeAnalysisIgnore
import os
import sys
import inspect
@@ -32,17 +32,17 @@ _init_externals()
#{ Imports
-from git.config import GitConfigParser
-from git.objects import *
-from git.refs import *
-from git.diff import *
-from git.exc import *
-from git.db import *
-from git.cmd import Git
-from git.repo import Repo
-from git.remote import *
-from git.index import *
-from git.util import (
+from git.config import GitConfigParser # @NoMove @IgnorePep8
+from git.objects import * # @NoMove @IgnorePep8
+from git.refs import * # @NoMove @IgnorePep8
+from git.diff import * # @NoMove @IgnorePep8
+from git.exc import * # @NoMove @IgnorePep8
+from git.db import * # @NoMove @IgnorePep8
+from git.cmd import Git # @NoMove @IgnorePep8
+from git.repo import Repo # @NoMove @IgnorePep8
+from git.remote import * # @NoMove @IgnorePep8
+from git.index import * # @NoMove @IgnorePep8
+from git.util import ( # @NoMove @IgnorePep8
LockFile,
BlockingLockFile,
Stats,
diff --git a/git/cmd.py b/git/cmd.py
index f4f5f99a..88d62aa4 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -539,7 +539,8 @@ class Git(LazyMixin):
cmd_not_found_exception = OSError
# end handle
- log.debug("Popen(%s, cwd=%s, universal_newlines=%s", command, cwd, universal_newlines)
+ log.debug("Popen(%s, cwd=%s, universal_newlines=%s, shell=%s)",
+ command, cwd, universal_newlines, shell)
try:
proc = Popen(command,
env=env,
diff --git a/git/compat.py b/git/compat.py
index 441a3761..e7243e25 100644
--- a/git/compat.py
+++ b/git/compat.py
@@ -13,14 +13,14 @@ import sys
from gitdb.utils.compat import (
xrange,
- MAXSIZE,
- izip,
+ MAXSIZE, # @UnusedImport
+ izip, # @UnusedImport
)
from gitdb.utils.encoding import (
- string_types,
- text_type,
- force_bytes,
- force_text
+ string_types, # @UnusedImport
+ text_type, # @UnusedImport
+ force_bytes, # @UnusedImport
+ force_text # @UnusedImport
)
@@ -33,17 +33,21 @@ defenc = sys.getdefaultencoding()
if PY3:
import io
FileType = io.IOBase
+
def byte_ord(b):
return b
+
def bchr(n):
return bytes([n])
+
def mviter(d):
return d.values()
- range = xrange
+
+ range = xrange # @ReservedAssignment
unicode = str
binary_type = bytes
else:
- FileType = file
+ FileType = file # @UndefinedVariable on PY3
# usually, this is just ascii, which might not enough for our encoding needs
# Unless it's set specifically, we override it to be utf-8
if defenc == 'ascii':
@@ -52,7 +56,8 @@ else:
bchr = chr
unicode = unicode
binary_type = str
- range = xrange
+ range = xrange # @ReservedAssignment
+
def mviter(d):
return d.itervalues()
diff --git a/git/config.py b/git/config.py
index ad6192ff..eddfac15 100644
--- a/git/config.py
+++ b/git/config.py
@@ -17,6 +17,8 @@ import logging
import abc
import os
+from functools import wraps
+
from git.odict import OrderedDict
from git.util import LockFile
from git.compat import (
@@ -38,7 +40,7 @@ log.addHandler(logging.NullHandler())
class MetaParserBuilder(abc.ABCMeta):
"""Utlity class wrapping base-class methods into decorators that assure read-only properties"""
- def __new__(metacls, name, bases, clsdict):
+ def __new__(cls, name, bases, clsdict):
"""
Equip all base-class methods with a needs_values decorator, and all non-const methods
with a set_dirty_and_flush_changes decorator in addition to that."""
@@ -60,18 +62,18 @@ class MetaParserBuilder(abc.ABCMeta):
# END for each base
# END if mutating methods configuration is set
- new_type = super(MetaParserBuilder, metacls).__new__(metacls, name, bases, clsdict)
+ new_type = super(MetaParserBuilder, cls).__new__(cls, name, bases, clsdict)
return new_type
def needs_values(func):
"""Returns method assuring we read values (on demand) before we try to access them"""
+ @wraps(func)
def assure_data_present(self, *args, **kwargs):
self.read()
return func(self, *args, **kwargs)
# END wrapper method
- assure_data_present.__name__ = func.__name__
return assure_data_present
@@ -477,20 +479,15 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
is_file_lock = isinstance(fp, string_types + (FileType, ))
if is_file_lock:
self._lock._obtain_lock()
- try:
- if not hasattr(fp, "seek"):
- with open(self._file_or_files, "wb") as fp:
- self._write(fp)
- else:
- fp.seek(0)
- # make sure we do not overwrite into an existing file
- if hasattr(fp, 'truncate'):
- fp.truncate()
+ if not hasattr(fp, "seek"):
+ with open(self._file_or_files, "wb") as fp:
self._write(fp)
- finally:
- # we release the lock - it will not vanish automatically in PY3.5+
- if is_file_lock:
- self._lock._release_lock()
+ else:
+ fp.seek(0)
+ # make sure we do not overwrite into an existing file
+ if hasattr(fp, 'truncate'):
+ fp.truncate()
+ self._write(fp)
def _assure_writable(self, method_name):
if self.read_only:
diff --git a/git/db.py b/git/db.py
index c4e19858..39b9872a 100644
--- a/git/db.py
+++ b/git/db.py
@@ -7,7 +7,7 @@ from gitdb.util import (
bin_to_hex,
hex_to_bin
)
-from gitdb.db import GitDB
+from gitdb.db import GitDB # @UnusedImport
from gitdb.db import LooseObjectDB
from .exc import (
@@ -54,7 +54,7 @@ class GitCmdObjectDB(LooseObjectDB):
:note: currently we only raise BadObject as git does not communicate
AmbiguousObjects separately"""
try:
- hexsha, typename, size = self._git.get_object_header(partial_hexsha)
+ hexsha, typename, size = self._git.get_object_header(partial_hexsha) # @UnusedVariable
return hex_to_bin(hexsha)
except (GitCommandError, ValueError):
raise BadObject(partial_hexsha)
diff --git a/git/exc.py b/git/exc.py
index 47215c21..eb7c3c0e 100644
--- a/git/exc.py
+++ b/git/exc.py
@@ -5,7 +5,7 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
""" Module containing all exceptions thrown througout the git package, """
-from gitdb.exc import * # NOQA
+from gitdb.exc import * # NOQA @UnusedWildImport
from git.compat import UnicodeMixin, safe_decode, string_types
diff --git a/git/index/base.py b/git/index/base.py
index 9b6d28ab..ac2d3019 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -170,7 +170,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
def _deserialize(self, stream):
"""Initialize this instance with index values read from the given stream"""
- self.version, self.entries, self._extension_data, conten_sha = read_cache(stream)
+ self.version, self.entries, self._extension_data, conten_sha = read_cache(stream) # @UnusedVariable
return self
def _entries_sorted(self):
@@ -404,7 +404,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
continue
# END glob handling
try:
- for root, dirs, files in os.walk(abs_path, onerror=raise_exc):
+ for root, dirs, files in os.walk(abs_path, onerror=raise_exc): # @UnusedVariable
for rela_file in files:
# add relative paths only
yield os.path.join(root.replace(rs, ''), rela_file)
@@ -599,7 +599,6 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
"""Store file at filepath in the database and return the base index entry
Needs the git_working_dir decorator active ! This must be assured in the calling code"""
st = os.lstat(filepath) # handles non-symlinks as well
- stream = None
if S_ISLNK(st.st_mode):
# in PY3, readlink is string, but we need bytes. In PY2, it's just OS encoded bytes, we assume UTF-8
open_stream = lambda: BytesIO(force_bytes(os.readlink(filepath), encoding=defenc))
@@ -1102,11 +1101,11 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
try:
self.entries[(co_path, 0)]
except KeyError:
- dir = co_path
- if not dir.endswith('/'):
- dir += '/'
+ folder = co_path
+ if not folder.endswith('/'):
+ folder += '/'
for entry in mviter(self.entries):
- if entry.path.startswith(dir):
+ if entry.path.startswith(folder):
p = entry.path
self._write_path_to_stdin(proc, p, p, make_exc,
fprogress, read_from_stdout=False)
diff --git a/git/index/fun.py b/git/index/fun.py
index 74ac929e..7a7593fe 100644
--- a/git/index/fun.py
+++ b/git/index/fun.py
@@ -264,7 +264,7 @@ def write_tree_from_cache(entries, odb, sl, si=0):
# enter recursion
# ci - 1 as we want to count our current item as well
- sha, tree_entry_list = write_tree_from_cache(entries, odb, slice(ci - 1, xi), rbound + 1)
+ sha, tree_entry_list = write_tree_from_cache(entries, odb, slice(ci - 1, xi), rbound + 1) # @UnusedVariable
tree_items_append((sha, S_IFDIR, base))
# skip ahead
diff --git a/git/index/util.py b/git/index/util.py
index 0340500c..ce798851 100644
--- a/git/index/util.py
+++ b/git/index/util.py
@@ -2,6 +2,9 @@
import struct
import tempfile
import os
+
+from functools import wraps
+
from git.compat import is_win
__all__ = ('TemporaryFileSwap', 'post_clear_cache', 'default_index', 'git_working_dir')
@@ -48,13 +51,13 @@ def post_clear_cache(func):
natively which in fact is possible, but probably not feasible performance wise.
"""
+ @wraps(func)
def post_clear_cache_if_not_raised(self, *args, **kwargs):
rval = func(self, *args, **kwargs)
self._delete_entries_cache()
return rval
-
# END wrapper method
- post_clear_cache_if_not_raised.__name__ = func.__name__
+
return post_clear_cache_if_not_raised
@@ -63,6 +66,7 @@ def default_index(func):
repository index. This is as we rely on git commands that operate
on that index only. """
+ @wraps(func)
def check_default_index(self, *args, **kwargs):
if self._file_path != self._index_path():
raise AssertionError(
@@ -70,7 +74,6 @@ def default_index(func):
return func(self, *args, **kwargs)
# END wrpaper method
- check_default_index.__name__ = func.__name__
return check_default_index
@@ -78,6 +81,7 @@ def git_working_dir(func):
"""Decorator which changes the current working dir to the one of the git
repository in order to assure relative paths are handled correctly"""
+ @wraps(func)
def set_git_working_dir(self, *args, **kwargs):
cur_wd = os.getcwd()
os.chdir(self.repo.working_tree_dir)
@@ -88,7 +92,6 @@ def git_working_dir(func):
# END handle working dir
# END wrapper
- set_git_working_dir.__name__ = func.__name__
return set_git_working_dir
#} END decorators
diff --git a/git/objects/__init__.py b/git/objects/__init__.py
index ee642876..23b2416a 100644
--- a/git/objects/__init__.py
+++ b/git/objects/__init__.py
@@ -3,22 +3,24 @@ Import all submodules main classes into the package space
"""
# flake8: noqa
from __future__ import absolute_import
+
import inspect
+
from .base import *
+from .blob import *
+from .commit import *
+from .submodule import util as smutil
+from .submodule.base import *
+from .submodule.root import *
+from .tag import *
+from .tree import *
# Fix import dependency - add IndexObject to the util module, so that it can be
# imported by the submodule.base
-from .submodule import util as smutil
smutil.IndexObject = IndexObject
smutil.Object = Object
del(smutil)
-from .submodule.base import *
-from .submodule.root import *
# must come after submodule was made available
-from .tag import *
-from .blob import *
-from .commit import *
-from .tree import *
__all__ = [name for name, obj in locals().items()
if not (name.startswith('_') or inspect.ismodule(obj))]
diff --git a/git/objects/base.py b/git/objects/base.py
index 77d0ed63..0b849960 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -40,7 +40,7 @@ class Object(LazyMixin):
assert len(binsha) == 20, "Require 20 byte binary sha, got %r, len = %i" % (binsha, len(binsha))
@classmethod
- def new(cls, repo, id):
+ def new(cls, repo, id): # @ReservedAssignment
"""
:return: New Object instance of a type appropriate to the object type behind
id. The id of the newly created object will be a binsha even though
diff --git a/git/objects/commit.py b/git/objects/commit.py
index 000ab3d0..1534c552 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -140,7 +140,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
def _set_cache_(self, attr):
if attr in Commit.__slots__:
# read the data in a chunk, its faster - then provide a file wrapper
- binsha, typename, self.size, stream = self.repo.odb.stream(self.binsha)
+ binsha, typename, self.size, stream = self.repo.odb.stream(self.binsha) # @UnusedVariable
self._deserialize(BytesIO(stream.read()))
else:
super(Commit, self)._set_cache_(attr)
@@ -267,7 +267,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
hexsha = line.strip()
if len(hexsha) > 40:
# split additional information, as returned by bisect for instance
- hexsha, rest = line.split(None, 1)
+ hexsha, _ = line.split(None, 1)
# END handle extra info
assert len(hexsha) == 40, "Invalid line: %s" % hexsha
diff --git a/git/objects/fun.py b/git/objects/fun.py
index c04f80b5..5c0f4819 100644
--- a/git/objects/fun.py
+++ b/git/objects/fun.py
@@ -157,9 +157,9 @@ def traverse_trees_recursive(odb, tree_shas, path_prefix):
if not item:
continue
# END skip already done items
- entries = [None for n in range(nt)]
+ entries = [None for _ in range(nt)]
entries[ti] = item
- sha, mode, name = item # its faster to unpack
+ sha, mode, name = item # its faster to unpack @UnusedVariable
is_dir = S_ISDIR(mode) # type mode bits
# find this item in all other tree data items
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index c6c6d699..28802b35 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -1,4 +1,3 @@
-from . import util
from .util import (
mkhead,
sm_name,
@@ -39,6 +38,9 @@ import git
import os
import logging
import uuid
+from unittest.case import SkipTest
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
+from git.objects.base import IndexObject, Object
__all__ = ["Submodule", "UpdateProgress"]
@@ -67,7 +69,7 @@ UPDWKTREE = UpdateProgress.UPDWKTREE
# IndexObject comes via util module, its a 'hacky' fix thanks to pythons import
# mechanism which cause plenty of trouble of the only reason for packages and
# modules is refactoring - subpackages shoudn't depend on parent packages
-class Submodule(util.IndexObject, Iterable, Traversable):
+class Submodule(IndexObject, Iterable, Traversable):
"""Implements access to a git submodule. They are special in that their sha
represents a commit in the submodule's repository which is to be checked out
@@ -396,24 +398,20 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# otherwise there is a '-' character in front of the submodule listing
# a38efa84daef914e4de58d1905a500d8d14aaf45 mymodule (v0.9.0-1-ga38efa8)
# -a38efa84daef914e4de58d1905a500d8d14aaf45 submodules/intermediate/one
- writer = sm.repo.config_writer()
- writer.set_value(sm_section(name), 'url', url)
- writer.release()
+ with sm.repo.config_writer() as writer:
+ writer.set_value(sm_section(name), 'url', url)
# update configuration and index
index = sm.repo.index
- writer = sm.config_writer(index=index, write=False)
- writer.set_value('url', url)
- writer.set_value('path', path)
-
- sm._url = url
- if not branch_is_default:
- # store full path
- writer.set_value(cls.k_head_option, br.path)
- sm._branch_path = br.path
- # END handle path
- writer.release()
- del(writer)
+ with sm.config_writer(index=index, write=False) as writer:
+ writer.set_value('url', url)
+ writer.set_value('path', path)
+
+ sm._url = url
+ if not branch_is_default:
+ # store full path
+ writer.set_value(cls.k_head_option, br.path)
+ sm._branch_path = br.path
# we deliberatly assume that our head matches our index !
sm.binsha = mrepo.head.commit.binsha
@@ -526,7 +524,7 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# have a valid branch, but no checkout - make sure we can figure
# that out by marking the commit with a null_sha
- local_branch.set_object(util.Object(mrepo, self.NULL_BIN_SHA))
+ local_branch.set_object(Object(mrepo, self.NULL_BIN_SHA))
# END initial checkout + branch creation
# make sure HEAD is not detached
@@ -540,9 +538,8 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# the default implementation will be offended and not update the repository
# Maybe this is a good way to assure it doesn't get into our way, but
# we want to stay backwards compatible too ... . Its so redundant !
- writer = self.repo.config_writer()
- writer.set_value(sm_section(self.name), 'url', self.url)
- writer.release()
+ with self.repo.config_writer() as writer:
+ writer.set_value(sm_section(self.name), 'url', self.url)
# END handle dry_run
# END handle initalization
@@ -729,11 +726,9 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# END handle submodule doesn't exist
# update configuration
- writer = self.config_writer(index=index) # auto-write
- writer.set_value('path', module_checkout_path)
- self.path = module_checkout_path
- writer.release()
- del(writer)
+ with self.config_writer(index=index) as writer: # auto-write
+ writer.set_value('path', module_checkout_path)
+ self.path = module_checkout_path
# END handle configuration flag
except Exception:
if renamed_module:
@@ -836,7 +831,7 @@ class Submodule(util.IndexObject, Iterable, Traversable):
num_branches_with_new_commits += len(mod.git.cherry(rref)) != 0
# END for each remote ref
# not a single remote branch contained all our commits
- if num_branches_with_new_commits == len(rrefs):
+ if len(rrefs) and num_branches_with_new_commits == len(rrefs):
raise InvalidGitRepositoryError(
"Cannot delete module at %s as there are new commits" % mod.working_tree_dir)
# END handle new commits
@@ -856,13 +851,25 @@ class Submodule(util.IndexObject, Iterable, Traversable):
del(mod) # release file-handles (windows)
import gc
gc.collect()
- rmtree(wtd)
+ try:
+ rmtree(wtd)
+ except Exception as ex:
+ if HIDE_WINDOWS_KNOWN_ERRORS:
+ raise SkipTest("FIXME: fails with: PermissionError\n %s", ex)
+ else:
+ raise
# END delete tree if possible
# END handle force
if not dry_run and os.path.isdir(git_dir):
self._clear_cache()
- rmtree(git_dir)
+ try:
+ rmtree(git_dir)
+ except Exception as ex:
+ if HIDE_WINDOWS_KNOWN_ERRORS:
+ raise SkipTest("FIXME: fails with: PermissionError\n %s", ex)
+ else:
+ raise
# end handle separate bare repository
# END handle module deletion
@@ -884,13 +891,11 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# now git config - need the config intact, otherwise we can't query
# information anymore
- writer = self.repo.config_writer()
- writer.remove_section(sm_section(self.name))
- writer.release()
+ with self.repo.config_writer() as writer:
+ writer.remove_section(sm_section(self.name))
- writer = self.config_writer()
- writer.remove_section()
- writer.release()
+ with self.config_writer() as writer:
+ writer.remove_section()
# END delete configuration
return self
@@ -981,18 +986,15 @@ class Submodule(util.IndexObject, Iterable, Traversable):
return self
# .git/config
- pw = self.repo.config_writer()
- # As we ourselves didn't write anything about submodules into the parent .git/config, we will not require
- # it to exist, and just ignore missing entries
- if pw.has_section(sm_section(self.name)):
- pw.rename_section(sm_section(self.name), sm_section(new_name))
- # end
- pw.release()
+ with self.repo.config_writer() as pw:
+ # As we ourselves didn't write anything about submodules into the parent .git/config,
+ # we will not require it to exist, and just ignore missing entries.
+ if pw.has_section(sm_section(self.name)):
+ pw.rename_section(sm_section(self.name), sm_section(new_name))
# .gitmodules
- cw = self.config_writer(write=True).config
- cw.rename_section(sm_section(self.name), sm_section(new_name))
- cw.release()
+ with self.config_writer(write=True).config as cw:
+ cw.rename_section(sm_section(self.name), sm_section(new_name))
self._name = new_name
diff --git a/git/objects/tag.py b/git/objects/tag.py
index c8684447..cefff083 100644
--- a/git/objects/tag.py
+++ b/git/objects/tag.py
@@ -21,7 +21,7 @@ class TagObject(base.Object):
type = "tag"
__slots__ = ("object", "tag", "tagger", "tagged_date", "tagger_tz_offset", "message")
- def __init__(self, repo, binsha, object=None, tag=None,
+ def __init__(self, repo, binsha, object=None, tag=None, # @ReservedAssignment
tagger=None, tagged_date=None, tagger_tz_offset=None, message=None):
"""Initialize a tag object with additional data
@@ -55,8 +55,8 @@ class TagObject(base.Object):
ostream = self.repo.odb.stream(self.binsha)
lines = ostream.read().decode(defenc).splitlines()
- obj, hexsha = lines[0].split(" ") # object <hexsha>
- type_token, type_name = lines[1].split(" ") # type <type_name>
+ obj, hexsha = lines[0].split(" ") # object <hexsha> @UnusedVariable
+ type_token, type_name = lines[1].split(" ") # type <type_name> @UnusedVariable
self.object = \
get_object_type_by_name(type_name.encode('ascii'))(self.repo, hex_to_bin(hexsha))
diff --git a/git/refs/head.py b/git/refs/head.py
index fe820b10..a1d8ab46 100644
--- a/git/refs/head.py
+++ b/git/refs/head.py
@@ -133,18 +133,15 @@ class Head(Reference):
raise ValueError("Incorrect parameter type: %r" % remote_reference)
# END handle type
- writer = self.config_writer()
- if remote_reference is None:
- writer.remove_option(self.k_config_remote)
- writer.remove_option(self.k_config_remote_ref)
- if len(writer.options()) == 0:
- writer.remove_section()
- # END handle remove section
- else:
- writer.set_value(self.k_config_remote, remote_reference.remote_name)
- writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head))
- # END handle ref value
- writer.release()
+ with self.config_writer() as writer:
+ if remote_reference is None:
+ writer.remove_option(self.k_config_remote)
+ writer.remove_option(self.k_config_remote_ref)
+ if len(writer.options()) == 0:
+ writer.remove_section()
+ else:
+ writer.set_value(self.k_config_remote, remote_reference.remote_name)
+ writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head))
return self
diff --git a/git/refs/reference.py b/git/refs/reference.py
index 3e132aef..cc99dc26 100644
--- a/git/refs/reference.py
+++ b/git/refs/reference.py
@@ -50,7 +50,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
#{ Interface
- def set_object(self, object, logmsg=None):
+ def set_object(self, object, logmsg=None): # @ReservedAssignment
"""Special version which checks if the head-log needs an update as well
:return: self"""
oldbinsha = None
diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py
index 894b26d5..ebaff8ca 100644
--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -218,7 +218,7 @@ class SymbolicReference(object):
return self
- def set_object(self, object, logmsg=None):
+ def set_object(self, object, logmsg=None): # @ReservedAssignment
"""Set the object we point to, possibly dereference our symbolic reference first.
If the reference does not exist, it will be created
@@ -229,7 +229,7 @@ class SymbolicReference(object):
:note: plain SymbolicReferences may not actually point to objects by convention
:return: self"""
if isinstance(object, SymbolicReference):
- object = object.object
+ object = object.object # @ReservedAssignment
# END resolve references
is_detached = True
@@ -595,7 +595,7 @@ class SymbolicReference(object):
# END for each directory to walk
# read packed refs
- for sha, rela_path in cls._iter_packed_refs(repo):
+ for sha, rela_path in cls._iter_packed_refs(repo): # @UnusedVariable
if rela_path.startswith(common_path):
rela_paths.add(rela_path)
# END relative path matches common path
diff --git a/git/remote.py b/git/remote.py
index c2ffcc1a..d35e1fad 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -176,7 +176,7 @@ class PushInfo(object):
split_token = "..."
if control_character == " ":
split_token = ".."
- old_sha, new_sha = summary.split(' ')[0].split(split_token)
+ old_sha, new_sha = summary.split(' ')[0].split(split_token) # @UnusedVariable
# have to use constructor here as the sha usually is abbreviated
old_commit = old_sha
# END message handling
@@ -262,7 +262,7 @@ class FetchInfo(object):
# parse lines
control_character, operation, local_remote_ref, remote_local_ref, note = match.groups()
try:
- new_hex_sha, fetch_operation, fetch_note = fetch_line.split("\t")
+ new_hex_sha, fetch_operation, fetch_note = fetch_line.split("\t") # @UnusedVariable
ref_type_name, fetch_note = fetch_note.split(' ', 1)
except ValueError: # unpack error
raise ValueError("Failed to parse FETCH_HEAD line: %r" % fetch_line)
@@ -625,8 +625,8 @@ class Remote(LazyMixin, Iterable):
for pline in progress_handler(line):
# END handle special messages
for cmd in cmds:
- if len(line) > 1 and line[0] == ' ' and line[1] == cmd:
- fetch_info_lines.append(line)
+ if len(pline) > 1 and pline[0] == ' ' and pline[1] == cmd:
+ fetch_info_lines.append(pline)
continue
# end find command code
# end for each comand code we know
diff --git a/git/repo/base.py b/git/repo/base.py
index 947d77d2..8b68b5ff 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -899,8 +899,12 @@ class Repo(object):
try:
proc = git.clone(url, path, with_extended_output=True, as_process=True,
v=True, **add_progress(kwargs, git, progress))
- progress_handler = progress and progress.new_message_handler() or None
- handle_process_output(proc, None, progress_handler, finalize_process)
+ if progress:
+ handle_process_output(proc, None, progress.new_message_handler(), finalize_process)
+ else:
+ (stdout, stderr) = proc.communicate() # FIXME: Will block of outputs are big!
+ finalize_process(proc, stderr=stderr)
+ # end handle progress
finally:
if prev_cwd is not None:
os.chdir(prev_cwd)
@@ -920,10 +924,8 @@ class Repo(object):
# sure
repo = cls(os.path.abspath(path), odbt=odbt)
if repo.remotes:
- writer = repo.remotes[0].config_writer
- writer.set_value('url', repo.remotes[0].url.replace("\\\\", "\\").replace("\\", "/"))
- # PY3: be sure cleanup is performed and lock is released
- writer.release()
+ with repo.remotes[0].config_writer as writer:
+ writer.set_value('url', repo.remotes[0].url.replace("\\\\", "\\").replace("\\", "/"))
# END handle remote repo
return repo
diff --git a/git/repo/fun.py b/git/repo/fun.py
index 0483eaa9..320eb1c8 100644
--- a/git/repo/fun.py
+++ b/git/repo/fun.py
@@ -284,7 +284,7 @@ def rev_parse(repo, rev):
try:
if token == "~":
obj = to_commit(obj)
- for item in xrange(num):
+ for _ in xrange(num):
obj = obj.parents[0]
# END for each history item to walk
elif token == "^":
diff --git a/git/test/lib/asserts.py b/git/test/lib/asserts.py
index 9edc49e0..6f5ba714 100644
--- a/git/test/lib/asserts.py
+++ b/git/test/lib/asserts.py
@@ -8,18 +8,18 @@ import re
import stat
from nose.tools import (
- assert_equal,
- assert_not_equal,
- assert_raises,
- raises,
- assert_true,
- assert_false
+ assert_equal, # @UnusedImport
+ assert_not_equal, # @UnusedImport
+ assert_raises, # @UnusedImport
+ raises, # @UnusedImport
+ assert_true, # @UnusedImport
+ assert_false # @UnusedImport
)
try:
from unittest.mock import patch
except ImportError:
- from mock import patch
+ from mock import patch # @NoMove @UnusedImport
__all__ = ['assert_instance_of', 'assert_not_instance_of',
'assert_none', 'assert_not_none',
diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py
index a85ac2fd..e92ce8b4 100644
--- a/git/test/lib/helper.py
+++ b/git/test/lib/helper.py
@@ -12,7 +12,8 @@ import tempfile
import io
import logging
-from git import Repo, Remote, GitCommandError, Git
+from functools import wraps
+
from git.util import rmtree
from git.compat import string_types, is_win
import textwrap
@@ -30,6 +31,11 @@ __all__ = (
log = logging.getLogger('git.util')
+#: We need an easy way to see if Appveyor TCs start failing,
+#: so the errors marked with this var are considered "acknowledged" ones, awaiting remedy,
+#: till then, we wish to hide them.
+HIDE_WINDOWS_KNOWN_ERRORS = is_win and os.environ.get('HIDE_WINDOWS_KNOWN_ERRORS', True)
+
#{ Routines
@@ -86,6 +92,7 @@ def with_rw_directory(func):
"""Create a temporary directory which can be written to, remove it if the
test succeeds, but leave it otherwise to aid additional debugging"""
+ @wraps(func)
def wrapper(self):
path = tempfile.mktemp(prefix=func.__name__)
os.mkdir(path)
@@ -94,8 +101,8 @@ def with_rw_directory(func):
try:
return func(self, path)
except Exception:
- log.info.write("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:
@@ -108,6 +115,8 @@ def with_rw_directory(func):
if not keep:
rmtree(path)
+ return wrapper
+
def with_rw_repo(working_tree_ref, bare=False):
"""
@@ -122,6 +131,7 @@ def with_rw_repo(working_tree_ref, bare=False):
assert isinstance(working_tree_ref, string_types), "Decorator requires ref name for working tree checkout"
def argument_passer(func):
+ @wraps(func)
def repo_creator(self):
prefix = 'non_'
if bare:
@@ -155,13 +165,13 @@ def with_rw_repo(working_tree_ref, bare=False):
# END rm test repo if possible
# END cleanup
# END rw repo creator
- repo_creator.__name__ = func.__name__
return repo_creator
# END argument passer
return argument_passer
def launch_git_daemon(temp_dir, ip, port):
+ from git import Git
if is_win:
## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
# but if invoked as 'git daemon', it detaches from parent `git` cmd,
@@ -207,10 +217,12 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
See working dir info in with_rw_repo
:note: We attempt to launch our own invocation of git-daemon, which will be shutdown at the end of the test.
"""
+ from git import Remote, GitCommandError
assert isinstance(working_tree_ref, string_types), "Decorator requires ref name for working tree checkout"
def argument_passer(func):
+ @wraps(func)
def remote_repo_creator(self):
remote_repo_dir = _mktemp("remote_repo_%s" % func.__name__)
repo_dir = _mktemp("remote_clone_non_bare_repo")
@@ -225,16 +237,13 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
rw_remote_repo.daemon_export = True
# this thing is just annoying !
- crw = rw_remote_repo.config_writer()
- section = "daemon"
- try:
- crw.add_section(section)
- except Exception:
- pass
- crw.set(section, "receivepack", True)
- # release lock
- crw.release()
- del(crw)
+ with rw_remote_repo.config_writer() as crw:
+ section = "daemon"
+ try:
+ crw.add_section(section)
+ except Exception:
+ pass
+ crw.set(section, "receivepack", True)
# initialize the remote - first do it as local remote and pull, then
# we change the url to point to the daemon. The daemon should be started
@@ -243,7 +252,8 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
d_remote.fetch()
remote_repo_url = "git://localhost:%s%s" % (GIT_DAEMON_PORT, remote_repo_dir)
- d_remote.config_writer.set('url', remote_repo_url)
+ with d_remote.config_writer as cw:
+ cw.set('url', remote_repo_url)
temp_dir = osp(_mktemp())
gd = launch_git_daemon(temp_dir, '127.0.0.1', GIT_DAEMON_PORT)
@@ -319,10 +329,9 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
gd.proc.wait()
# END cleanup
# END bare repo creator
- remote_repo_creator.__name__ = func.__name__
return remote_repo_creator
# END remote repo creator
- # END argument parsser
+ # END argument parser
return argument_passer
@@ -358,6 +367,7 @@ class TestBase(TestCase):
Dynamically add a read-only repository to our actual type. This way
each test type has its own repository
"""
+ from git import Repo
import gc
gc.collect()
cls.rorepo = Repo(GIT_REPO)
diff --git a/git/test/performance/lib.py b/git/test/performance/lib.py
index eebbfd76..0c4c20a4 100644
--- a/git/test/performance/lib.py
+++ b/git/test/performance/lib.py
@@ -19,6 +19,7 @@ from git.util import rmtree
#{ Invvariants
k_env_git_repo = "GIT_PYTHON_TEST_GIT_REPO_BASE"
+
#} END invariants
diff --git a/git/test/performance/test_odb.py b/git/test/performance/test_odb.py
index 9abe2d42..6f07a615 100644
--- a/git/test/performance/test_odb.py
+++ b/git/test/performance/test_odb.py
@@ -5,7 +5,8 @@ import sys
from time import time
from unittest.case import skipIf
-from git.compat import is_win, PY3
+from git.compat import PY3
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
from .lib import (
TestBigRepoR
@@ -14,7 +15,8 @@ from .lib import (
class TestObjDBPerformance(TestBigRepoR):
- @skipIf(is_win and PY3, "FIXME: smmp fails with: TypeError: Can't convert 'bytes' object to str implicitly")
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and PY3,
+ "FIXME: smmp fails with: TypeError: Can't convert 'bytes' object to str implicitly")
def test_random_access(self):
results = [["Iterate Commits"], ["Iterate Blobs"], ["Retrieve Blob Data"]]
for repo in (self.gitrorepo, self.puregitrorepo):
diff --git a/git/test/performance/test_streams.py b/git/test/performance/test_streams.py
index 8194547c..42cbade5 100644
--- a/git/test/performance/test_streams.py
+++ b/git/test/performance/test_streams.py
@@ -120,7 +120,7 @@ class TestObjDBPerformance(TestBigRepoR):
# read all
st = time()
- s, t, size, data = rwrepo.git.get_object_data(gitsha)
+ hexsha, typename, size, data = rwrepo.git.get_object_data(gitsha) # @UnusedVariable
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)
@@ -131,7 +131,7 @@ class TestObjDBPerformance(TestBigRepoR):
# read chunks
st = time()
- s, t, size, stream = rwrepo.git.stream_object_data(gitsha)
+ hexsha, typename, size, stream = rwrepo.git.stream_object_data(gitsha) # @UnusedVariable
while True:
data = stream.read(cs)
if len(data) < cs:
diff --git a/git/test/test_commit.py b/git/test/test_commit.py
index 66d988a3..fd9777fb 100644
--- a/git/test/test_commit.py
+++ b/git/test/test_commit.py
@@ -123,7 +123,7 @@ class TestCommit(TestBase):
check_entries(stats.total)
assert "files" in stats.total
- for filepath, d in stats.files.items():
+ for filepath, d in stats.files.items(): # @UnusedVariable
check_entries(d)
# END for each stated file
diff --git a/git/test/test_config.py b/git/test/test_config.py
index 154aaa24..32873f24 100644
--- a/git/test/test_config.py
+++ b/git/test/test_config.py
@@ -60,7 +60,8 @@ class TestBase(TestCase):
self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path(filename)).getvalue())
# creating an additional config writer must fail due to exclusive access
- self.failUnlessRaises(IOError, GitConfigParser, file_obj, read_only=False)
+ with self.assertRaises(IOError):
+ GitConfigParser(file_obj, read_only=False)
# should still have a lock and be able to make changes
assert w_config._lock._has_lock()
@@ -91,18 +92,21 @@ class TestBase(TestCase):
@with_rw_directory
def test_lock_reentry(self, rw_dir):
fpl = os.path.join(rw_dir, 'l')
- with GitConfigParser(fpl, read_only=False) as gcp:
- gcp.set_value('include', 'some_value', 'a')
+ gcp = GitConfigParser(fpl, read_only=False)
+ with gcp as cw:
+ 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')
# ...so creating an additional config writer must fail due to exclusive access
- self.failUnlessRaises(IOError, GitConfigParser, fpl, read_only=False)
+ with self.assertRaises(IOError):
+ GitConfigParser(fpl, read_only=False)
# but work when the lock is removed
with GitConfigParser(fpl, read_only=False):
assert os.path.exists(fpl)
# reentering with an existing lock must fail due to exclusive access
- self.failUnlessRaises(IOError, gcp.__enter__)
+ with self.assertRaises(IOError):
+ gcp.__enter__()
def test_multi_line_config(self):
file_obj = self._to_memcache(fixture_path("git_config_with_comments"))
@@ -144,10 +148,13 @@ class TestBase(TestCase):
assert "\n" not in val
# writing must fail
- self.failUnlessRaises(IOError, r_config.set, section, option, None)
- self.failUnlessRaises(IOError, r_config.remove_option, section, option)
+ with self.assertRaises(IOError):
+ r_config.set(section, option, None)
+ with self.assertRaises(IOError):
+ r_config.remove_option(section, option)
# END for each option
- self.failUnlessRaises(IOError, r_config.remove_section, section)
+ with self.assertRaises(IOError):
+ r_config.remove_section(section)
# END for each section
assert num_sections and num_options
assert r_config._is_initialized is True
@@ -157,7 +164,8 @@ class TestBase(TestCase):
assert r_config.get_value("doesnt", "exist", default) == default
# it raises if there is no default though
- self.failUnlessRaises(cp.NoSectionError, r_config.get_value, "doesnt", "exist")
+ with self.assertRaises(cp.NoSectionError):
+ r_config.get_value("doesnt", "exist")
@with_rw_directory
def test_config_include(self, rw_dir):
@@ -206,7 +214,8 @@ class TestBase(TestCase):
write_test_value(cw, tv)
with GitConfigParser(fpa, read_only=True) as cr:
- self.failUnlessRaises(cp.NoSectionError, check_test_value, cr, tv)
+ with self.assertRaises(cp.NoSectionError):
+ check_test_value(cr, tv)
# But can make it skip includes alltogether, and thus allow write-backs
with GitConfigParser(fpa, read_only=False, merge_includes=False) as cw:
@@ -218,8 +227,10 @@ class TestBase(TestCase):
def test_rename(self):
file_obj = self._to_memcache(fixture_path('git_config'))
with GitConfigParser(file_obj, read_only=False, merge_includes=False) as cw:
- self.failUnlessRaises(ValueError, cw.rename_section, "doesntexist", "foo")
- self.failUnlessRaises(ValueError, cw.rename_section, "core", "include")
+ with self.assertRaises(ValueError):
+ cw.rename_section("doesntexist", "foo")
+ with self.assertRaises(ValueError):
+ cw.rename_section("core", "include")
nn = "bee"
assert cw.rename_section('core', nn) is cw
@@ -237,4 +248,5 @@ class TestBase(TestCase):
assert cr.get_value('core', 'filemode'), "Should read keys with values"
- self.failUnlessRaises(cp.NoOptionError, cr.get_value, 'color', 'ui')
+ with self.assertRaises(cp.NoOptionError):
+ cr.get_value('color', 'ui')
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index 8a2dff0f..e2bfcb21 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -16,6 +16,9 @@ class Tutorials(TestBase):
import gc
gc.collect()
+ # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
+ # "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
+ # "'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_init_repo_object(self, rw_dir):
# [1-test_init_repo_object]
@@ -36,8 +39,8 @@ class Tutorials(TestBase):
# [3-test_init_repo_object]
repo.config_reader() # get a config reader for read-only access
- cw = repo.config_writer() # get a config writer to change configuration
- cw.release() # call release() to be sure changes are written and locks are released
+ 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]
@@ -67,7 +70,8 @@ class Tutorials(TestBase):
# 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
+ 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 ...
@@ -239,9 +243,9 @@ class Tutorials(TestBase):
# [8-test_references_and_objects]
hc = repo.head.commit
hct = hc.tree
- hc != hct
- hc != repo.tags[0]
- hc == repo.head.reference.commit
+ hc != hct # @NoEffect
+ hc != repo.tags[0] # @NoEffect
+ hc == repo.head.reference.commit # @NoEffect
# ![8-test_references_and_objects]
# [9-test_references_and_objects]
@@ -344,7 +348,7 @@ class Tutorials(TestBase):
# 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'])
# Access blob objects
- for (path, stage), entry in index.entries.items():
+ for (path, stage), entry in index.entries.items(): # @UnusedVariable
pass
new_file_path = os.path.join(repo.working_tree_dir, 'new-file-name')
open(new_file_path, 'w').close()
@@ -394,9 +398,8 @@ class Tutorials(TestBase):
# [26-test_references_and_objects]
assert origin.url == repo.remotes.origin.url
- cw = origin.config_writer
- cw.set("pushurl", "other_url")
- cw.release()
+ with origin.config_writer as cw:
+ cw.set("pushurl", "other_url")
# Please note that in python 2, writing origin.config_writer.set(...) is totally safe.
# In py3 __del__ calls can be delayed, thus not writing changes in time.
diff --git a/git/test/test_exc.py b/git/test/test_exc.py
index 7e6b023e..33f44034 100644
--- a/git/test/test_exc.py
+++ b/git/test/test_exc.py
@@ -29,13 +29,13 @@ _cmd_argvs = (
('θνιψοδε', 'κι', 'αλλα', 'non-unicode', 'args'),
)
_causes_n_substrings = (
- (None, None), # noqa: E241
- (7, "exit code(7)"), # noqa: E241
- ('Some string', "'Some string'"), # noqa: E241
- ('παλιο string', "'παλιο string'"), # noqa: E241
- (Exception("An exc."), "Exception('An exc.')"), # noqa: E241
- (Exception("Κακια exc."), "Exception('Κακια exc.')"), # noqa: E241
- (object(), "<object object at "), # noqa: E241
+ (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', )
diff --git a/git/test/test_git.py b/git/test/test_git.py
index 94614cd1..58ee8e9c 100644
--- a/git/test/test_git.py
+++ b/git/test/test_git.py
@@ -121,7 +121,7 @@ class TestGit(TestBase):
# read data - have to read it in one large chunk
size = int(obj_info.split()[2])
- data = g.stdout.read(size)
+ g.stdout.read(size)
g.stdout.read(1)
# now we should be able to read a new object
@@ -131,7 +131,7 @@ class TestGit(TestBase):
# same can be achived using the respective command functions
hexsha, typename, size = self.git.get_object_header(hexsha)
- hexsha, typename_two, size_two, data = self.git.get_object_data(hexsha)
+ hexsha, typename_two, size_two, data = self.git.get_object_data(hexsha) # @UnusedVariable
self.assertEqual(typename, typename_two)
self.assertEqual(size, size_two)
diff --git a/git/test/test_index.py b/git/test/test_index.py
index 1ffbe9e2..34014064 100644
--- a/git/test/test_index.py
+++ b/git/test/test_index.py
@@ -5,17 +5,16 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-from git.test.lib import (
- TestBase,
- fixture_path,
- fixture,
- with_rw_repo
-)
-from git.util import Actor, rmtree
-from git.exc import (
- HookExecutionError,
- InvalidGitRepositoryError
+from io import BytesIO
+import os
+from stat import (
+ S_ISLNK,
+ ST_MODE
)
+import sys
+import tempfile
+from unittest.case import skipIf
+
from git import (
IndexFile,
Repo,
@@ -28,24 +27,27 @@ from git import (
CheckoutError,
)
from git.compat import string_types, is_win
-from gitdb.util import hex_to_bin
-import os
-import sys
-import tempfile
-from stat import (
- S_ISLNK,
- ST_MODE
+from git.exc import (
+ HookExecutionError,
+ InvalidGitRepositoryError
)
-
-from io import BytesIO
-from gitdb.base import IStream
-from git.objects import Blob
+from git.index.fun import hook_path
from git.index.typ import (
BaseIndexEntry,
IndexEntry
)
-from git.index.fun import hook_path
+from git.objects import Blob
+from git.test.lib import (
+ TestBase,
+ fixture_path,
+ fixture,
+ with_rw_repo
+)
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
from git.test.lib import with_rw_directory
+from git.util import Actor, rmtree
+from gitdb.base import IStream
+from gitdb.util import hex_to_bin
class TestIndex(TestBase):
@@ -56,7 +58,7 @@ class TestIndex(TestBase):
def _assert_fprogress(self, entries):
self.assertEqual(len(entries), len(self._fprogress_map))
- for path, call_count in self._fprogress_map.items():
+ for path, call_count in self._fprogress_map.items(): # @UnusedVariable
self.assertEqual(call_count, 2)
# END for each item in progress map
self._reset_progress()
@@ -186,7 +188,7 @@ class TestIndex(TestBase):
# test BlobFilter
prefix = 'lib/git'
- for stage, blob in base_index.iter_blobs(BlobFilter([prefix])):
+ for stage, blob in base_index.iter_blobs(BlobFilter([prefix])): # @UnusedVariable
assert blob.path.startswith(prefix)
# writing a tree should fail with an unmerged index
@@ -410,10 +412,9 @@ class TestIndex(TestBase):
uname = u"Thomas Müller"
umail = "sd@company.com"
- writer = rw_repo.config_writer()
- writer.set_value("user", "name", uname)
- writer.set_value("user", "email", umail)
- writer.release()
+ with rw_repo.config_writer() as writer:
+ writer.set_value("user", "name", uname)
+ writer.set_value("user", "email", umail)
self.assertEqual(writer.get_value("user", "name"), uname)
# remove all of the files, provide a wild mix of paths, BaseIndexEntries,
@@ -821,6 +822,10 @@ class TestIndex(TestBase):
asserted = True
assert asserted, "Adding using a filename is not correctly asserted."
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and sys.version_info[:2] == (2, 7), r"""
+ FIXME: File "C:\projects\gitpython\git\util.py", line 125, in to_native_path_linux
+ return path.replace('\\', '/')
+ UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)""")
@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)
diff --git a/git/test/test_refs.py b/git/test/test_refs.py
index 9816fb50..43f1dcc7 100644
--- a/git/test/test_refs.py
+++ b/git/test/test_refs.py
@@ -101,15 +101,13 @@ class TestRefs(TestBase):
assert prev_object == cur_object # represent the same git object
assert prev_object is not cur_object # but are different instances
- writer = head.config_writer()
- tv = "testopt"
- writer.set_value(tv, 1)
- assert writer.get_value(tv) == 1
- writer.release()
+ with head.config_writer() as writer:
+ tv = "testopt"
+ writer.set_value(tv, 1)
+ assert writer.get_value(tv) == 1
assert head.config_reader().get_value(tv) == 1
- writer = head.config_writer()
- writer.remove_option(tv)
- writer.release()
+ with head.config_writer() as writer:
+ writer.remove_option(tv)
# after the clone, we might still have a tracking branch setup
head.set_tracking_branch(None)
@@ -175,7 +173,7 @@ class TestRefs(TestBase):
def test_orig_head(self):
assert type(self.rorepo.head.orig_head()) == SymbolicReference
-
+
@with_rw_repo('0.1.6')
def test_head_checkout_detached_head(self, rw_repo):
res = rw_repo.remotes.origin.refs.master.checkout()
@@ -282,7 +280,7 @@ class TestRefs(TestBase):
# tag ref
tag_name = "5.0.2"
- light_tag = TagReference.create(rw_repo, tag_name)
+ TagReference.create(rw_repo, tag_name)
self.failUnlessRaises(GitCommandError, TagReference.create, rw_repo, tag_name)
light_tag = TagReference.create(rw_repo, tag_name, "HEAD~1", force=True)
assert isinstance(light_tag, TagReference)
@@ -442,7 +440,7 @@ class TestRefs(TestBase):
self.failUnlessRaises(OSError, SymbolicReference.create, rw_repo, symref_path, cur_head.reference.commit)
# it works if the new ref points to the same reference
- SymbolicReference.create(rw_repo, symref.path, symref.reference).path == symref.path
+ 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)
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index b99e49cf..7b52ccce 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -90,7 +90,7 @@ class TestRemoteProgress(RemoteProgress):
assert self._stages_per_op
# must have seen all stages
- for op, stages in self._stages_per_op.items():
+ for op, stages in self._stages_per_op.items(): # @UnusedVariable
assert stages & self.STAGE_MASK == self.STAGE_MASK
# END for each op/stage
@@ -267,7 +267,8 @@ class TestRemote(TestBase):
# put origin to git-url
other_origin = other_repo.remotes.origin
- other_origin.config_writer.set("url", remote_repo_url)
+ with other_origin.config_writer as cw:
+ cw.set("url", remote_repo_url)
# it automatically creates alternates as remote_repo is shared as well.
# It will use the transport though and ignore alternates when fetching
# assert not other_repo.alternates # this would fail
@@ -331,7 +332,7 @@ class TestRemote(TestBase):
# push new tags
progress = TestRemoteProgress()
to_be_updated = "my_tag.1.0RV"
- new_tag = TagReference.create(rw_repo, to_be_updated)
+ new_tag = TagReference.create(rw_repo, to_be_updated) # @UnusedVariable
other_tag = TagReference.create(rw_repo, "my_obj_tag.2.1aRV", message="my message")
res = remote.push(progress=progress, tags=True)
assert res[-1].flags & PushInfo.NEW_TAG
@@ -416,13 +417,12 @@ class TestRemote(TestBase):
self.failUnlessRaises(IOError, reader.set, opt, "test")
# change value
- writer = remote.config_writer
- new_val = "myval"
- writer.set(opt, new_val)
- assert writer.get(opt) == new_val
- writer.set(opt, val)
- assert writer.get(opt) == val
- del(writer)
+ with remote.config_writer as writer:
+ new_val = "myval"
+ writer.set(opt, new_val)
+ assert writer.get(opt) == new_val
+ writer.set(opt, val)
+ assert writer.get(opt) == val
assert getattr(remote, opt) == val
# END for each default option key
@@ -432,7 +432,7 @@ class TestRemote(TestBase):
assert remote.rename(other_name) == remote
assert prev_name != remote.name
# multiple times
- for time in range(2):
+ for _ in range(2):
assert remote.rename(prev_name).name == prev_name
# END for each rename ( back to prev_name )
diff --git a/git/test/test_repo.py b/git/test/test_repo.py
index ae2bf2f0..1d537e93 100644
--- a/git/test/test_repo.py
+++ b/git/test/test_repo.py
@@ -7,11 +7,11 @@
import glob
from io import BytesIO
import itertools
-import functools as fnt
import os
import pickle
import sys
import tempfile
+from unittest.case import skipIf
from git import (
InvalidGitRepositoryError,
@@ -50,13 +50,14 @@ from git.test.lib import (
assert_true,
raises
)
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
from git.test.lib import with_rw_directory
from git.util import join_path_native, rmtree, rmfile
from gitdb.util import bin_to_hex
from nose import SkipTest
+import functools as fnt
import os.path as osp
-from unittest.case import skipIf
def iter_flatten(lol):
@@ -486,7 +487,7 @@ class TestRepo(TestBase):
@with_rw_directory
def test_tilde_and_env_vars_in_repo_path(self, rw_dir):
- ph = os.environ['HOME']
+ ph = os.environ.get('HOME')
try:
os.environ['HOME'] = rw_dir
Repo.init(os.path.join('~', 'test.git'), bare=True)
@@ -494,8 +495,9 @@ class TestRepo(TestBase):
os.environ['FOO'] = rw_dir
Repo.init(os.path.join('$FOO', 'test.git'), bare=True)
finally:
- os.environ['HOME'] = ph
- del os.environ['FOO']
+ if ph:
+ os.environ['HOME'] = ph
+ del os.environ['FOO']
# end assure HOME gets reset to what it was
def test_git_cmd(self):
@@ -795,7 +797,8 @@ class TestRepo(TestBase):
git_file_repo = Repo(rwrepo.working_tree_dir)
self.assertEqual(os.path.abspath(git_file_repo.git_dir), real_path_abs)
- @skipIf(is_win and PY3, "FIXME: smmp fails with: TypeError: Can't convert 'bytes' object to str implicitly")
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and PY3,
+ "FIXME: smmp fails with: TypeError: Can't convert 'bytes' object to str implicitly")
def test_file_handle_leaks(self):
def last_commit(repo, rev, path):
commit = next(repo.iter_commits(rev, path, max_count=1))
@@ -806,7 +809,7 @@ class TestRepo(TestBase):
# And we expect to set max handles to a low value, like 64
# You should set ulimit -n X, see .travis.yml
# The loops below would easily create 500 handles if these would leak (4 pipes + multiple mapped files)
- for i in range(64):
+ for _ in range(64):
for repo_type in (GitCmdObjectDB, GitDB):
repo = Repo(self.rorepo.working_tree_dir, odbt=repo_type)
last_commit(repo, 'master', 'git/test/test_base.py')
@@ -894,6 +897,9 @@ class TestRepo(TestBase):
for i, j in itertools.permutations([c1, 'ffffff', ''], r=2):
self.assertRaises(GitCommandError, repo.is_ancestor, i, j)
+ # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
+ # "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
+ # "'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_work_tree_unsupported(self, rw_dir):
git = Git(rw_dir)
diff --git a/git/test/test_submodule.py b/git/test/test_submodule.py
index bfa0379d..46928f51 100644
--- a/git/test/test_submodule.py
+++ b/git/test/test_submodule.py
@@ -1,35 +1,36 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-import sys
import os
+import sys
+from unittest.case import skipIf
import git
-
-from git.test.lib import (
- TestBase,
- with_rw_repo
-)
-from git.test.lib import with_rw_directory
+from git.compat import string_types, is_win
from git.exc import (
InvalidGitRepositoryError,
RepositoryDirtyError
)
from git.objects.submodule.base import Submodule
from git.objects.submodule.root import RootModule, RootUpdateProgress
-from git.util import to_native_path_linux, join_path_native
-from git.compat import string_types, is_win
from git.repo.fun import (
find_git_dir,
touch
)
-from unittest.case import skipIf
+from git.test.lib import (
+ TestBase,
+ with_rw_repo
+)
+from git.test.lib import with_rw_directory
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
+from git.util import to_native_path_linux, join_path_native
+
# Change the configuration if possible to prevent the underlying memory manager
# to keep file handles open. On windows we get problems as they are not properly
# closed due to mmap bugs on windows (as it appears)
if is_win:
try:
- import smmap.util
+ import smmap.util # @UnusedImport
smmap.util.MapRegion._test_read_into_memory = True
except ImportError:
sys.stderr.write("The submodule tests will fail as some files cannot be removed due to open file handles.\n")
@@ -97,28 +98,32 @@ class TestSubmodule(TestBase):
# force it to reread its information
del(smold._url)
- smold.url == sm.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 #
if rwrepo.bare:
- self.failUnlessRaises(InvalidGitRepositoryError, sm.config_writer)
+ with self.assertRaises(InvalidGitRepositoryError):
+ with sm.config_writer() as cw:
+ pass
else:
- writer = sm.config_writer()
- # for faster checkout, set the url to the local path
- new_smclone_path = to_native_path_linux(join_path_native(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.url == new_smclone_path
+ with sm.config_writer() as writer:
+ # for faster checkout, set the url to the local path
+ new_smclone_path = to_native_path_linux(join_path_native(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.url == new_smclone_path
# END handle bare repo
smold.config_reader()
# cannot get a writer on historical submodules
if not rwrepo.bare:
- self.failUnlessRaises(ValueError, smold.config_writer)
+ with self.assertRaises(ValueError):
+ with smold.config_writer():
+ pass
# END handle bare repo
# make the old into a new - this doesn't work as the name changed
@@ -209,9 +214,8 @@ class TestSubmodule(TestBase):
# adjust the path of the submodules module to point to the local destination
new_csmclone_path = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path, csm.path))
- writer = csm.config_writer()
- writer.set_value('url', new_csmclone_path)
- writer.release()
+ with csm.config_writer() as writer:
+ writer.set_value('url', new_csmclone_path)
assert csm.url == new_csmclone_path
# dry-run does nothing
@@ -224,7 +228,7 @@ class TestSubmodule(TestBase):
assert csm.module_exists()
# tracking branch once again
- csm.module().head.ref.tracking_branch() is not None
+ csm.module().head.ref.tracking_branch() is not None # @NoEffect
# this flushed in a sub-submodule
assert len(list(rwrepo.iter_submodules())) == 2
@@ -273,9 +277,8 @@ class TestSubmodule(TestBase):
# module() is supposed to point to gitdb, which has a child-submodule whose URL is still pointing
# to github. To save time, we will change it to
csm.set_parent_commit(csm.repo.head.commit)
- cw = csm.config_writer()
- cw.set_value('url', self._small_repo_url())
- cw.release()
+ 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")
# We have modified the configuration, hence the index is dirty, and the
@@ -283,12 +286,10 @@ class TestSubmodule(TestBase):
# NOTE: As we did a few updates in the meanwhile, the indices were reset
# Hence we create some changes
csm.set_parent_commit(csm.repo.head.commit)
- writer = sm.config_writer()
- writer.set_value("somekey", "somevalue")
- writer.release()
- writer = csm.config_writer()
- writer.set_value("okey", "ovalue")
- writer.release()
+ with sm.config_writer() as writer:
+ writer.set_value("somekey", "somevalue")
+ with csm.config_writer() as writer:
+ writer.set_value("okey", "ovalue")
self.failUnlessRaises(InvalidGitRepositoryError, sm.remove)
# if we remove the dirty index, it would work
sm.module().index.reset()
@@ -317,8 +318,8 @@ class TestSubmodule(TestBase):
# forcibly delete the child repository
prev_count = len(sm.children())
self.failUnlessRaises(ValueError, csm.remove, force=True)
- # We removed sm, which removed all submodules. Howver, the instance we have
- # still points to the commit prior to that, where it still existed
+ # We removed sm, which removed all submodules. However, the instance we
+ # have still points to the commit prior to that, where it still existed
csm.set_parent_commit(csm.repo.commit(), check=False)
assert not csm.exists()
assert not csm.module_exists()
@@ -417,9 +418,10 @@ class TestSubmodule(TestBase):
# Error if there is no submodule file here
self.failUnlessRaises(IOError, Submodule._config_parser, rwrepo, rwrepo.commit(self.k_no_subm_tag), True)
- @skipIf(is_win, "FIXME: fails with: PermissionError: [WinError 32] The process cannot access the file because"
- "it is being used by another process: "
- "'C:\\Users\\ankostis\\AppData\\Local\\Temp\\tmp95c3z83bnon_bare_test_base_rw\\git\\ext\\gitdb\\gitdb\\ext\\smmap'") # noqa E501
+ # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
+ # "FIXME: fails with: PermissionError: [WinError 32] The process cannot access the file because"
+ # "it is being used by another process: "
+ # "'C:\\Users\\ankostis\\AppData\\Local\\Temp\\tmp95c3z83bnon_bare_test_base_rw\\git\\ext\\gitdb\\gitdb\\ext\\smmap'") # noqa E501
@with_rw_repo(k_subm_current)
def test_base_rw(self, rwrepo):
self._do_base_tests(rwrepo)
@@ -428,6 +430,11 @@ class TestSubmodule(TestBase):
def test_base_bare(self, rwrepo):
self._do_base_tests(rwrepo)
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and sys.version_info[:2] == (3, 5), """
+ 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
@with_rw_repo(k_subm_current, bare=False)
def test_root_module(self, rwrepo):
# Can query everything without problems
@@ -445,8 +452,8 @@ class TestSubmodule(TestBase):
assert len(rm.list_items(rm.module())) == 1
rm.config_reader()
- w = rm.config_writer()
- w.release()
+ with rm.config_writer():
+ pass
# deep traversal gitdb / async
rsmsp = [sm.path for sm in rm.traverse()]
@@ -471,9 +478,8 @@ class TestSubmodule(TestBase):
assert not sm.module_exists() # was never updated after rwrepo's clone
# assure we clone from a local source
- writer = sm.config_writer()
- writer.set_value('url', to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path)))
- writer.release()
+ with sm.config_writer() as writer:
+ writer.set_value('url', to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path)))
# dry-run does nothing
sm.update(recursive=False, dry_run=True, progress=prog)
@@ -481,9 +487,8 @@ class TestSubmodule(TestBase):
sm.update(recursive=False)
assert sm.module_exists()
- writer = sm.config_writer()
- writer.set_value('path', fp) # change path to something with prefix AFTER url change
- writer.release()
+ with sm.config_writer() as writer:
+ writer.set_value('path', fp) # change path to something with prefix AFTER url change
# update fails as list_items in such a situations cannot work, as it cannot
# find the entry at the changed path
@@ -570,9 +575,8 @@ class TestSubmodule(TestBase):
# repository at the different url
nsm.set_parent_commit(csmremoved)
nsmurl = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, rsmsp[0]))
- writer = nsm.config_writer()
- writer.set_value('url', nsmurl)
- writer.release()
+ with nsm.config_writer() as writer:
+ writer.set_value('url', nsmurl)
csmpathchange = rwrepo.index.commit("changed url")
nsm.set_parent_commit(csmpathchange)
@@ -602,9 +606,8 @@ class TestSubmodule(TestBase):
nsmm = nsm.module()
prev_commit = nsmm.head.commit
for branch in ("some_virtual_branch", cur_branch.name):
- writer = nsm.config_writer()
- writer.set_value(Submodule.k_head_option, git.Head.to_full_path(branch))
- writer.release()
+ with nsm.config_writer() as writer:
+ writer.set_value(Submodule.k_head_option, git.Head.to_full_path(branch))
csmbranchchange = rwrepo.index.commit("changed branch to %s" % branch)
nsm.set_parent_commit(csmbranchchange)
# END for each branch to change
@@ -632,9 +635,8 @@ class TestSubmodule(TestBase):
assert nsm.exists() and nsm.module_exists() and len(nsm.children()) >= 1
# assure we pull locally only
nsmc = nsm.children()[0]
- writer = nsmc.config_writer()
- writer.set_value('url', subrepo_url)
- writer.release()
+ 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
rm.update(recursive=True, progress=prog)
@@ -726,6 +728,9 @@ class TestSubmodule(TestBase):
assert commit_sm.binsha == sm_too.binsha
assert sm_too.binsha != sm.binsha
+ # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
+ # "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
+ # "'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(os.path.join(rwdir, 'parent'))
@@ -783,8 +788,8 @@ class TestSubmodule(TestBase):
rsm = parent.submodule_update()
assert_exists(sm)
assert_exists(csm)
- csm_writer = csm.config_writer().set_value('url', 'bar')
- csm_writer.release()
+ 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'
@@ -802,6 +807,24 @@ class TestSubmodule(TestBase):
# end for each dry-run mode
@with_rw_directory
+ def test_remove_norefs(self, rwdir):
+ parent = git.Repo.init(os.path.join(rwdir, 'parent'))
+ sm_name = 'mymodules/myname'
+ sm = parent.create_submodule(sm_name, sm_name, url=self._small_repo_url())
+ assert sm.exists()
+
+ parent.index.commit("Added submodule")
+
+ assert sm.repo is parent # yoh was surprised since expected sm repo!!
+ # so created a new instance for submodule
+ smrepo = git.Repo(os.path.join(rwdir, 'parent', sm.path))
+ # Adding a remote without fetching so would have no references
+ 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(os.path.join(rwdir, 'parent'))
sm_name = 'mymodules/myname'
@@ -844,9 +867,8 @@ class TestSubmodule(TestBase):
sm.repo.index.commit("added new file")
# change designated submodule checkout branch to the new upstream feature branch
- smcw = sm.config_writer()
- smcw.set_value('branch', sm_fb.name)
- smcw.release()
+ with sm.config_writer() as smcw:
+ 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)
@@ -870,9 +892,8 @@ class TestSubmodule(TestBase):
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
- smcw = sm.config_writer()
- smcw.set_value('branch', sm_pfb.path)
- smcw.release()
+ with sm.config_writer() as smcw:
+ 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
diff --git a/git/test/test_tree.py b/git/test/test_tree.py
index f9282411..bb62d9bf 100644
--- a/git/test/test_tree.py
+++ b/git/test/test_tree.py
@@ -4,18 +4,26 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
+from io import BytesIO
import os
-from git.test.lib import TestBase
+import sys
+from unittest.case import skipIf
+
from git import (
Tree,
Blob
)
-
-from io import BytesIO
+from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
+from git.test.lib import TestBase
class TestTree(TestBase):
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and sys.version_info[:2] == (3, 5), """
+ 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""")
def test_serializable(self):
# tree at the given commit contains a submodule as well
roottree = self.rorepo.tree('6c1faef799095f3990e9970bc2cb10aa0221cf9c')
@@ -44,6 +52,11 @@ class TestTree(TestBase):
testtree._deserialize(stream)
# END for each item in tree
+ @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and sys.version_info[:2] == (3, 5), """
+ 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""")
def test_traverse(self):
root = self.rorepo.tree('0.1.6')
num_recursive = 0
diff --git a/git/test/test_util.py b/git/test/test_util.py
index 36fb5be3..e07417b4 100644
--- a/git/test/test_util.py
+++ b/git/test/test_util.py
@@ -27,18 +27,22 @@ from git.cmd import dashify
from git.compat import string_types, is_win
import time
+import ddt
class TestIterableMember(object):
"""A member of an iterable list"""
- __slots__ = ("name", "prefix_name")
+ __slots__ = "name"
def __init__(self, name):
self.name = name
- self.prefix_name = name
+ def __repr__(self):
+ return "TestIterableMember(%r)" % self.name
+
+@ddt.ddt
class TestUtils(TestBase):
def setup(self):
@@ -97,20 +101,21 @@ class TestUtils(TestBase):
self.assertLess(elapsed, wait_time + extra_time)
def test_user_id(self):
- assert '@' in get_user_id()
+ self.assertIn('@', get_user_id())
def test_parse_date(self):
# test all supported formats
def assert_rval(rval, veri_time, offset=0):
- assert len(rval) == 2
- assert isinstance(rval[0], int) and isinstance(rval[1], int)
- assert rval[0] == veri_time
- assert rval[1] == offset
+ self.assertEqual(len(rval), 2)
+ self.assertIsInstance(rval[0], int)
+ self.assertIsInstance(rval[1], int)
+ self.assertEqual(rval[0], veri_time)
+ self.assertEqual(rval[1], offset)
# now that we are here, test our conversion functions as well
utctz = altz_to_utctz_str(offset)
- assert isinstance(utctz, string_types)
- assert utctz_to_altz(verify_utctz(utctz)) == offset
+ self.assertIsInstance(utctz, string_types)
+ self.assertEqual(utctz_to_altz(verify_utctz(utctz)), offset)
# END assert rval utility
rfc = ("Thu, 07 Apr 2005 22:13:11 +0000", 0)
@@ -131,53 +136,56 @@ class TestUtils(TestBase):
def test_actor(self):
for cr in (None, self.rorepo.config_reader()):
- assert isinstance(Actor.committer(cr), Actor)
- assert isinstance(Actor.author(cr), Actor)
+ self.assertIsInstance(Actor.committer(cr), Actor)
+ self.assertIsInstance(Actor.author(cr), Actor)
# END assure config reader is handled
- def test_iterable_list(self):
- for args in (('name',), ('name', 'prefix_')):
- l = IterableList('name')
-
- m1 = TestIterableMember('one')
- m2 = TestIterableMember('two')
-
- l.extend((m1, m2))
-
- assert len(l) == 2
-
- # contains works with name and identity
- assert m1.name in l
- assert m2.name in l
- assert m2 in l
- assert m2 in l
- assert 'invalid' not in l
-
- # with string index
- assert l[m1.name] is m1
- assert l[m2.name] is m2
-
- # with int index
- assert l[0] is m1
- assert l[1] is m2
-
- # with getattr
- assert l.one is m1
- assert l.two is m2
-
- # test exceptions
- self.failUnlessRaises(AttributeError, getattr, l, 'something')
- self.failUnlessRaises(IndexError, l.__getitem__, 'something')
-
- # delete by name and index
- self.failUnlessRaises(IndexError, l.__delitem__, 'something')
- del(l[m2.name])
- assert len(l) == 1
- assert m2.name not in l and m1.name in l
- del(l[0])
- assert m1.name not in l
- assert len(l) == 0
-
- self.failUnlessRaises(IndexError, l.__delitem__, 0)
- self.failUnlessRaises(IndexError, l.__delitem__, 'something')
- # END for each possible mode
+ @ddt.data(('name', ''), ('name', 'prefix_'))
+ def test_iterable_list(self, case):
+ name, prefix = case
+ l = IterableList(name, prefix)
+
+ name1 = "one"
+ name2 = "two"
+ m1 = TestIterableMember(prefix + name1)
+ m2 = TestIterableMember(prefix + name2)
+
+ l.extend((m1, m2))
+
+ self.assertEqual(len(l), 2)
+
+ # contains works with name and identity
+ self.assertIn(name1, l)
+ self.assertIn(name2, l)
+ self.assertIn(m2, l)
+ self.assertIn(m2, l)
+ self.assertNotIn('invalid', l)
+
+ # with string index
+ self.assertIs(l[name1], m1)
+ self.assertIs(l[name2], m2)
+
+ # with int index
+ self.assertIs(l[0], m1)
+ self.assertIs(l[1], m2)
+
+ # with getattr
+ self.assertIs(l.one, m1)
+ self.assertIs(l.two, m2)
+
+ # test exceptions
+ self.failUnlessRaises(AttributeError, getattr, l, 'something')
+ self.failUnlessRaises(IndexError, l.__getitem__, 'something')
+
+ # delete by name and index
+ self.failUnlessRaises(IndexError, l.__delitem__, 'something')
+ del(l[name2])
+ self.assertEqual(len(l), 1)
+ self.assertNotIn(name2, l)
+ self.assertIn(name1, l)
+ del(l[0])
+ self.assertNotIn(name1, l)
+ self.assertEqual(len(l), 0)
+
+ self.failUnlessRaises(IndexError, l.__delitem__, 0)
+ self.failUnlessRaises(IndexError, l.__delitem__, 'something')
diff --git a/git/util.py b/git/util.py
index 814cd7f4..c96a6b08 100644
--- a/git/util.py
+++ b/git/util.py
@@ -14,14 +14,16 @@ import shutil
import stat
import time
+from functools import wraps
+
from git.compat import is_win
-from gitdb.util import ( # NOQA
+from gitdb.util import ( # NOQA
make_sha,
- LockedFD,
- file_contents_ro,
- LazyMixin,
- to_hex_sha,
- to_bin_sha
+ LockedFD, # @UnusedImport
+ file_contents_ro, # @UnusedImport
+ LazyMixin, # @UnusedImport
+ to_hex_sha, # @UnusedImport
+ to_bin_sha # @UnusedImport
)
import os.path as osp
@@ -32,6 +34,7 @@ from .compat import (
PY3
)
from .exc import InvalidGitRepositoryError
+from unittest.case import SkipTest
# NOTE: Some of the unused imports might be used/imported by others.
@@ -50,13 +53,13 @@ def unbare_repo(func):
"""Methods with this decorator raise InvalidGitRepositoryError if they
encounter a bare repository"""
+ @wraps(func)
def wrapper(self, *args, **kwargs):
if self.repo.bare:
raise InvalidGitRepositoryError("Method '%s' cannot operate on bare repositories" % func.__name__)
# END bare method
return func(self, *args, **kwargs)
# END wrapper
- wrapper.__name__ = func.__name__
return wrapper
@@ -69,7 +72,15 @@ def rmtree(path):
def onerror(func, path, exc_info):
# Is the error an access error ?
os.chmod(path, stat.S_IWUSR)
- func(path) # Will scream if still not possible to delete.
+
+ try:
+ func(path) # Will scream if still not possible to delete.
+ except Exception as ex:
+ from git.test.lib.helper import HIDE_WINDOWS_KNOWN_ERRORS
+ if HIDE_WINDOWS_KNOWN_ERRORS:
+ raise SkipTest("FIXME: fails with: PermissionError\n %s", ex)
+ else:
+ raise
return shutil.rmtree(path, False, onerror)
@@ -240,7 +251,7 @@ class RemoteProgress(object):
# END could not get match
op_code = 0
- remote, op_name, percent, cur_count, max_count, message = match.groups()
+ remote, op_name, percent, cur_count, max_count, message = match.groups() # @UnusedVariable
# get operation id
if op_name == "Counting objects":