Codebase list python-git / 7b2dba6
New upstream version 3.0.7 TANIGUCHI Takaki 4 years ago
37 changed file(s) with 124 addition(s) and 469 deletion(s). Raw diff Collapse all Expand all
3636 -Anil Khatri <anil.soccer.khatri _at_ gmail.com>
3737 -JJ Graham <thetwoj _at_ gmail.com>
3838 -Ben Thayer <ben _at_ benthayer.com>
39
39 -Dries Kennes <admin _at_ dries007.net>
40 -Pratik Anurag <panurag247365 _at_ gmail.com>
41 -Harmon <harmon.public _at_ gmail.com>
4042 Portions derived from other open source works and are clearly marked.
00 Metadata-Version: 1.2
11 Name: GitPython
2 Version: 3.0.5
2 Version: 3.0.7
33 Summary: Python Git Library
44 Home-page: https://github.com/gitpython-developers/GitPython
55 Author: Sebastian Thiel, Michael Trier
2121 Classifier: Programming Language :: Python :: 3.5
2222 Classifier: Programming Language :: Python :: 3.6
2323 Classifier: Programming Language :: Python :: 3.7
24 Requires-Python: >=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
24 Requires-Python: >=3.4
00 Metadata-Version: 1.2
11 Name: GitPython
2 Version: 3.0.5
2 Version: 3.0.7
33 Summary: Python Git Library
44 Home-page: https://github.com/gitpython-developers/GitPython
55 Author: Sebastian Thiel, Michael Trier
2121 Classifier: Programming Language :: Python :: 3.5
2222 Classifier: Programming Language :: Python :: 3.6
2323 Classifier: Programming Language :: Python :: 3.7
24 Requires-Python: >=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
24 Requires-Python: >=3.4
6363
6464 #### Windows support
6565
66 For *Windows*, we do regularly test it on [Appveyor CI](https://www.appveyor.com/)
67 but not all test-cases pass - you may help improve them by exploring
68 [Issue #525](https://github.com/gitpython-developers/GitPython/issues/525).
66 See [Issue #525](https://github.com/gitpython-developers/GitPython/issues/525).
6967
7068 ### RUNNING TESTS
7169
189187
190188 [![codecov](https://codecov.io/gh/gitpython-developers/GitPython/branch/master/graph/badge.svg)](https://codecov.io/gh/gitpython-developers/GitPython)
191189 [![Build Status](https://travis-ci.org/gitpython-developers/GitPython.svg)](https://travis-ci.org/gitpython-developers/GitPython)
192 [![Build status](https://ci.appveyor.com/api/projects/status/0f3pi3c00hajlrsd/branch/master?svg=true&passingText=windows%20OK&failingText=windows%20failed)](https://ci.appveyor.com/project/Byron/gitpython/branch/master)
193190 [![Code Climate](https://codeclimate.com/github/gitpython-developers/GitPython/badges/gpa.svg)](https://codeclimate.com/github/gitpython-developers/GitPython)
194191 [![Documentation Status](https://readthedocs.org/projects/gitpython/badge/?version=stable)](https://readthedocs.org/projects/gitpython/?badge=stable)
195192 [![Stories in Ready](https://badge.waffle.io/gitpython-developers/GitPython.png?label=ready&title=Ready)](https://waffle.io/gitpython-developers/GitPython)
0 3.0.5
0 3.0.7
00 =========
11 Changelog
22 =========
3
4 3.0.7 - Bugfixes
5 =================================================
6
7 * removes python 2 compatibility shims, making GitPython a pure Python 3 library
8 with all of the python related legacy removed.
9 * Have a look at the PR, it is a good read on the mistakes made in the course of this,
10 https://github.com/gitpython-developers/GitPython/pull/979 , please help the maintainers
11 if you can to prevent accidents like these in future.
12
13 see the following for details:
14 https://github.com/gitpython-developers/gitpython/milestone/33?closed=1
15
16
17 3.0.6 - Bugfixes - unsigned/partial - do not use
18 =================================================
19
20 There was an issue with my setup, so things managed to slip to pypi without a signature.
21
22 Use 3.0.7 instead.
323
424 3.0.5 - Bugfixes
525 =============================================
1111 import os.path as osp
1212
1313
14 __version__ = '3.0.5'
14 __version__ = '3.0.7'
1515
1616
1717 #{ Initialization
1818 def _init_externals():
1919 """Initialize external projects by putting them into the path"""
20 if __version__ == '3.0.5':
20 if __version__ == '3.0.7':
2121 sys.path.insert(0, osp.join(osp.dirname(__file__), 'ext', 'gitdb'))
2222
2323 try:
2020 from textwrap import dedent
2121
2222 from git.compat import (
23 string_types,
2423 defenc,
2524 force_bytes,
26 PY3,
27 # just to satisfy flake8 on py3
28 unicode,
2925 safe_decode,
3026 is_posix,
3127 is_win,
4137 LazyMixin,
4238 stream_copy,
4339 )
44
45 try:
46 PermissionError
47 except NameError: # Python < 3.3
48 PermissionError = OSError
4940
5041 execute_kwargs = {'istream', 'with_extended_output',
5142 'with_exceptions', 'as_process', 'stdout_as_string',
917908 @classmethod
918909 def __unpack_args(cls, arg_list):
919910 if not isinstance(arg_list, (list, tuple)):
920 # This is just required for unicode conversion, as subprocess can't handle it
921 # However, in any other case, passing strings (usually utf-8 encoded) is totally fine
922 if not PY3 and isinstance(arg_list, unicode):
923 return [arg_list.encode(defenc)]
924911 return [str(arg_list)]
925912
926913 outlist = []
927914 for arg in arg_list:
928915 if isinstance(arg_list, (list, tuple)):
929916 outlist.extend(cls.__unpack_args(arg))
930 elif not PY3 and isinstance(arg_list, unicode):
931 outlist.append(arg_list.encode(defenc))
932917 # END recursion
933918 else:
934919 outlist.append(str(arg))
10461031 if isinstance(ref, bytes):
10471032 # Assume 40 bytes hexsha - bin-to-ascii for some reason returns bytes, not text
10481033 refstr = ref.decode('ascii')
1049 elif not isinstance(ref, string_types):
1034 elif not isinstance(ref, str):
10501035 refstr = str(ref) # could be ref-object
10511036
10521037 if not refstr.endswith("\n"):
99 import locale
1010 import os
1111 import sys
12 import codecs
1312
1413
15 from gitdb.utils.compat import (
16 xrange,
17 MAXSIZE, # @UnusedImport
18 izip, # @UnusedImport
19 )
2014 from gitdb.utils.encoding import (
21 string_types, # @UnusedImport
22 text_type, # @UnusedImport
2315 force_bytes, # @UnusedImport
2416 force_text # @UnusedImport
2517 )
2618
2719
28 PY3 = sys.version_info[0] >= 3
2920 is_win = (os.name == 'nt')
3021 is_posix = (os.name == 'posix')
3122 is_darwin = (os.name == 'darwin')
32 if hasattr(sys, 'getfilesystemencoding'):
33 defenc = sys.getfilesystemencoding()
34 if defenc is None:
35 defenc = sys.getdefaultencoding()
36
37 if PY3:
38 import io
39 FileType = io.IOBase
40
41 def byte_ord(b):
42 return b
43
44 def bchr(n):
45 return bytes([n])
46
47 def mviter(d):
48 return d.values()
49
50 range = xrange # @ReservedAssignment
51 unicode = str
52 binary_type = bytes
53 else:
54 FileType = file # @UndefinedVariable on PY3
55 # usually, this is just ascii, which might not enough for our encoding needs
56 # Unless it's set specifically, we override it to be utf-8
57 if defenc == 'ascii':
58 defenc = 'utf-8'
59 byte_ord = ord
60 bchr = chr
61 unicode = unicode
62 binary_type = str
63 range = xrange # @ReservedAssignment
64
65 def mviter(d):
66 return d.itervalues()
23 defenc = sys.getfilesystemencoding()
6724
6825
6926 def safe_decode(s):
7027 """Safely decodes a binary string to unicode"""
71 if isinstance(s, unicode):
28 if isinstance(s, str):
7229 return s
7330 elif isinstance(s, bytes):
7431 return s.decode(defenc, 'surrogateescape')
7835
7936 def safe_encode(s):
8037 """Safely decodes a binary string to unicode"""
81 if isinstance(s, unicode):
38 if isinstance(s, str):
8239 return s.encode(defenc)
8340 elif isinstance(s, bytes):
8441 return s
8845
8946 def win_encode(s):
9047 """Encode unicodes for process arguments on Windows."""
91 if isinstance(s, unicode):
48 if isinstance(s, str):
9249 return s.encode(locale.getpreferredencoding(False))
9350 elif isinstance(s, bytes):
9451 return s
10562 def __new__(cls, name, nbases, d):
10663 if nbases is None:
10764 return type.__new__(cls, name, (), d)
108 # There may be clients who rely on this attribute to be set to a reasonable value, which is why
109 # we set the __metaclass__ attribute explicitly
110 if not PY3 and '___metaclass__' not in d:
111 d['__metaclass__'] = meta
11265 return meta(name, bases, d)
11366 return metaclass(meta.__name__ + 'Helper', None, {})
114
115
116 ## From https://docs.python.org/3.3/howto/pyporting.html
117 class UnicodeMixin(object):
118
119 """Mixin class to handle defining the proper __str__/__unicode__
120 methods in Python 2 or 3."""
121
122 if PY3:
123 def __str__(self):
124 return self.__unicode__()
125 else: # Python 2
126 def __str__(self):
127 return self.__unicode__().encode(defenc)
128
129
130 """
131 This is Victor Stinner's pure-Python implementation of PEP 383: the "surrogateescape" error
132 handler of Python 3.
133 Source: misc/python/surrogateescape.py in https://bitbucket.org/haypo/misc
134 """
135
136 # This code is released under the Python license and the BSD 2-clause license
137
138
139 FS_ERRORS = 'surrogateescape'
140
141 # # -- Python 2/3 compatibility -------------------------------------
142 # FS_ERRORS = 'my_surrogateescape'
143
144 def u(text):
145 if PY3:
146 return text
147 return text.decode('unicode_escape')
148
149 def b(data):
150 if PY3:
151 return data.encode('latin1')
152 return data
153
154 if PY3:
155 _unichr = chr
156 bytes_chr = lambda code: bytes((code,))
157 else:
158 _unichr = unichr
159 bytes_chr = chr
160
161 def surrogateescape_handler(exc):
162 """
163 Pure Python implementation of the PEP 383: the "surrogateescape" error
164 handler of Python 3. Undecodable bytes will be replaced by a Unicode
165 character U+DCxx on decoding, and these are translated into the
166 original bytes on encoding.
167 """
168 mystring = exc.object[exc.start:exc.end]
169
170 try:
171 if isinstance(exc, UnicodeDecodeError):
172 # mystring is a byte-string in this case
173 decoded = replace_surrogate_decode(mystring)
174 elif isinstance(exc, UnicodeEncodeError):
175 # In the case of u'\udcc3'.encode('ascii',
176 # 'this_surrogateescape_handler'), both Python 2.x and 3.x raise an
177 # exception anyway after this function is called, even though I think
178 # it's doing what it should. It seems that the strict encoder is called
179 # to encode the unicode string that this function returns ...
180 decoded = replace_surrogate_encode(mystring, exc)
181 else:
182 raise exc
183 except NotASurrogateError:
184 raise exc
185 return (decoded, exc.end)
186
187
188 class NotASurrogateError(Exception):
189 pass
190
191
192 def replace_surrogate_encode(mystring, exc):
193 """
194 Returns a (unicode) string, not the more logical bytes, because the codecs
195 register_error functionality expects this.
196 """
197 decoded = []
198 for ch in mystring:
199 # if PY3:
200 # code = ch
201 # else:
202 code = ord(ch)
203
204 # The following magic comes from Py3.3's Python/codecs.c file:
205 if not 0xD800 <= code <= 0xDCFF:
206 # Not a surrogate. Fail with the original exception.
207 raise exc
208 # mybytes = [0xe0 | (code >> 12),
209 # 0x80 | ((code >> 6) & 0x3f),
210 # 0x80 | (code & 0x3f)]
211 # Is this a good idea?
212 if 0xDC00 <= code <= 0xDC7F:
213 decoded.append(_unichr(code - 0xDC00))
214 elif code <= 0xDCFF:
215 decoded.append(_unichr(code - 0xDC00))
216 else:
217 raise NotASurrogateError
218 return str().join(decoded)
219
220
221 def replace_surrogate_decode(mybytes):
222 """
223 Returns a (unicode) string
224 """
225 decoded = []
226 for ch in mybytes:
227 # We may be parsing newbytes (in which case ch is an int) or a native
228 # str on Py2
229 if isinstance(ch, int):
230 code = ch
231 else:
232 code = ord(ch)
233 if 0x80 <= code <= 0xFF:
234 decoded.append(_unichr(0xDC00 + code))
235 elif code <= 0x7F:
236 decoded.append(_unichr(code))
237 else:
238 # # It may be a bad byte
239 # # Try swallowing it.
240 # continue
241 # print("RAISE!")
242 raise NotASurrogateError
243 return str().join(decoded)
244
245
246 def encodefilename(fn):
247 if FS_ENCODING == 'ascii':
248 # ASCII encoder of Python 2 expects that the error handler returns a
249 # Unicode string encodable to ASCII, whereas our surrogateescape error
250 # handler has to return bytes in 0x80-0xFF range.
251 encoded = []
252 for index, ch in enumerate(fn):
253 code = ord(ch)
254 if code < 128:
255 ch = bytes_chr(code)
256 elif 0xDC80 <= code <= 0xDCFF:
257 ch = bytes_chr(code - 0xDC00)
258 else:
259 raise UnicodeEncodeError(FS_ENCODING,
260 fn, index, index+1,
261 'ordinal not in range(128)')
262 encoded.append(ch)
263 return bytes().join(encoded)
264 elif FS_ENCODING == 'utf-8':
265 # UTF-8 encoder of Python 2 encodes surrogates, so U+DC80-U+DCFF
266 # doesn't go through our error handler
267 encoded = []
268 for index, ch in enumerate(fn):
269 code = ord(ch)
270 if 0xD800 <= code <= 0xDFFF:
271 if 0xDC80 <= code <= 0xDCFF:
272 ch = bytes_chr(code - 0xDC00)
273 encoded.append(ch)
274 else:
275 raise UnicodeEncodeError(
276 FS_ENCODING,
277 fn, index, index+1, 'surrogates not allowed')
278 else:
279 ch_utf8 = ch.encode('utf-8')
280 encoded.append(ch_utf8)
281 return bytes().join(encoded)
282 return fn.encode(FS_ENCODING, FS_ERRORS)
283
284 def decodefilename(fn):
285 return fn.decode(FS_ENCODING, FS_ERRORS)
286
287 FS_ENCODING = 'ascii'; fn = b('[abc\xff]'); encoded = u('[abc\udcff]')
288 # FS_ENCODING = 'cp932'; fn = b('[abc\x81\x00]'); encoded = u('[abc\udc81\x00]')
289 # FS_ENCODING = 'UTF-8'; fn = b('[abc\xff]'); encoded = u('[abc\udcff]')
290
291
292 # normalize the filesystem encoding name.
293 # For example, we expect "utf-8", not "UTF8".
294 FS_ENCODING = codecs.lookup(FS_ENCODING).name
295
296
297 def register_surrogateescape():
298 """
299 Registers the surrogateescape error handler on Python 2 (only)
300 """
301 if PY3:
302 return
303 try:
304 codecs.lookup_error(FS_ERRORS)
305 except LookupError:
306 codecs.register_error(FS_ERRORS, surrogateescape_handler)
307
308
309 try:
310 b"100644 \x9f\0aaa".decode(defenc, "surrogateescape")
311 except Exception:
312 register_surrogateescape()
88 import abc
99 from functools import wraps
1010 import inspect
11 from io import IOBase
1112 import logging
1213 import os
1314 import re
1415 from collections import OrderedDict
1516
1617 from git.compat import (
17 string_types,
18 FileType,
1918 defenc,
2019 force_text,
2120 with_metaclass,
22 PY3,
2321 is_win,
2422 )
2523 from git.util import LockFile
2624
2725 import os.path as osp
2826
29
30 try:
31 import ConfigParser as cp
32 except ImportError:
33 # PY3
34 import configparser as cp
27 import configparser as cp
3528
3629
3730 __all__ = ('GitConfigParser', 'SectionConstraint')
302295 # END single file check
303296
304297 file_or_files = self._file_or_files
305 if not isinstance(self._file_or_files, string_types):
298 if not isinstance(self._file_or_files, str):
306299 file_or_files = self._file_or_files.name
307300 # END get filename from handle/stream
308301 # initialize lock base - we want to write
371364 v = v[:-1]
372365 # end cut trailing escapes to prevent decode error
373366
374 if PY3:
375 return v.encode(defenc).decode('unicode_escape')
376 return v.decode('string_escape')
367 return v.encode(defenc).decode('unicode_escape')
377368 # end
378369 # end
379370
580571 fp = self._file_or_files
581572
582573 # we have a physical file on disk, so get a lock
583 is_file_lock = isinstance(fp, string_types + (FileType, ))
574 is_file_lock = isinstance(fp, (str, IOBase))
584575 if is_file_lock:
585576 self._lock._obtain_lock()
586577 if not hasattr(fp, "seek"):
672663 if vl == 'true':
673664 return True
674665
675 if not isinstance(valuestr, string_types):
666 if not isinstance(valuestr, str):
676667 raise TypeError(
677668 "Invalid value type: only int, long, float and str are allowed",
678669 valuestr)
55 import re
66
77 from git.cmd import handle_process_output
8 from git.compat import (
9 defenc,
10 PY3
11 )
8 from git.compat import defenc
129 from git.util import finalize_process, hex_to_bin
1310
14 from .compat import binary_type
1511 from .objects.blob import Blob
1612 from .objects.util import mode_str_to_int
1713
2723 def _octal_repl(matchobj):
2824 value = matchobj.group(1)
2925 value = int(value, 8)
30 if PY3:
31 value = bytes(bytearray((value,)))
32 else:
33 value = chr(value)
26 value = bytes(bytearray((value,)))
3427 return value
3528
3629
267260 self.a_mode = a_mode
268261 self.b_mode = b_mode
269262
270 assert a_rawpath is None or isinstance(a_rawpath, binary_type)
271 assert b_rawpath is None or isinstance(b_rawpath, binary_type)
263 assert a_rawpath is None or isinstance(a_rawpath, bytes)
264 assert b_rawpath is None or isinstance(b_rawpath, bytes)
272265 self.a_rawpath = a_rawpath
273266 self.b_rawpath = b_rawpath
274267
301294 self.copied_file = copied_file
302295
303296 # be clear and use None instead of empty strings
304 assert raw_rename_from is None or isinstance(raw_rename_from, binary_type)
305 assert raw_rename_to is None or isinstance(raw_rename_to, binary_type)
297 assert raw_rename_from is None or isinstance(raw_rename_from, bytes)
298 assert raw_rename_to is None or isinstance(raw_rename_to, bytes)
306299 self.raw_rename_from = raw_rename_from or None
307300 self.raw_rename_to = raw_rename_to or None
308301
369362 # Python2 silliness: have to assure we convert our likely to be unicode object to a string with the
370363 # right encoding. Otherwise it tries to convert it using ascii, which may fail ungracefully
371364 res = h + msg
372 if not PY3:
373 res = res.encode(defenc)
374365 # end
375366 return res
376367
55 """ Module containing all exceptions thrown throughout the git package, """
66
77 from gitdb.exc import * # NOQA @UnusedWildImport skipcq: PYL-W0401, PYL-W0614
8 from git.compat import UnicodeMixin, safe_decode, string_types
8 from git.compat import safe_decode
99
1010
1111 class GitError(Exception):
2424 """ Thrown if a path could not be access by the system. """
2525
2626
27 class CommandError(UnicodeMixin, GitError):
27 class CommandError(GitError):
2828 """Base class for exceptions thrown at every stage of `Popen()` execution.
2929
3030 :param command:
4949 status = u'exit code(%s)' % int(status)
5050 except (ValueError, TypeError):
5151 s = safe_decode(str(status))
52 status = u"'%s'" % s if isinstance(status, string_types) else s
52 status = u"'%s'" % s if isinstance(status, str) else s
5353
5454 self._cmd = safe_decode(command[0])
5555 self._cmdline = u' '.join(safe_decode(i) for i in command)
5757 self.stdout = stdout and u"\n stdout: '%s'" % safe_decode(stdout) or ''
5858 self.stderr = stderr and u"\n stderr: '%s'" % safe_decode(stderr) or ''
5959
60 def __unicode__(self):
60 def __str__(self):
6161 return (self._msg + "\n cmdline: %s%s%s") % (
6262 self._cmd, self._cause, self._cmdline, self.stdout, self.stderr)
6363
1010 import tempfile
1111
1212 from git.compat import (
13 izip,
14 xrange,
15 string_types,
1613 force_bytes,
1714 defenc,
18 mviter,
1915 )
2016 from git.exc import (
2117 GitCommandError,
271267
272268 inst = cls(repo)
273269 # convert to entries dict
274 entries = dict(izip(((e.path, e.stage) for e in base_entries),
275 (IndexEntry.from_base(e) for e in base_entries)))
270 entries = dict(zip(((e.path, e.stage) for e in base_entries),
271 (IndexEntry.from_base(e) for e in base_entries)))
276272
277273 inst.entries = entries
278274 return inst
441437 Function(t) returning True if tuple(stage, Blob) should be yielded by the
442438 iterator. A default filter, the BlobFilter, allows you to yield blobs
443439 only if they match a given list of paths. """
444 for entry in mviter(self.entries):
440 for entry in self.entries.values():
445441 blob = entry.to_blob(self.repo)
446442 blob.size = entry.size
447443 output = (entry.stage, blob)
466462 for stage, blob in self.iter_blobs(is_unmerged_blob):
467463 path_map.setdefault(blob.path, []).append((stage, blob))
468464 # END for each unmerged blob
469 for l in mviter(path_map):
465 for l in path_map.values():
470466 l.sort()
471467 return path_map
472468
573569 items = [items]
574570
575571 for item in items:
576 if isinstance(item, string_types):
572 if isinstance(item, str):
577573 paths.append(self._to_relative_path(item))
578574 elif isinstance(item, (Blob, Submodule)):
579575 entries.append(BaseIndexEntry.from_blob(item))
810806 for item in items:
811807 if isinstance(item, (BaseIndexEntry, (Blob, Submodule))):
812808 paths.append(self._to_relative_path(item.path))
813 elif isinstance(item, string_types):
809 elif isinstance(item, str):
814810 paths.append(self._to_relative_path(item))
815811 else:
816812 raise TypeError("Invalid item type: %r" % item)
912908
913909 # parse result - first 0:n/2 lines are 'checking ', the remaining ones
914910 # are the 'renaming' ones which we parse
915 for ln in xrange(int(len(mvlines) / 2), len(mvlines)):
911 for ln in range(int(len(mvlines) / 2), len(mvlines)):
916912 tokens = mvlines[ln].split(' to ')
917913 assert len(tokens) == 2, "Too many tokens in %s" % mvlines[ln]
918914
10851081 proc = self.repo.git.checkout_index(*args, **kwargs)
10861082 proc.wait()
10871083 fprogress(None, True, None)
1088 rval_iter = (e.path for e in mviter(self.entries))
1084 rval_iter = (e.path for e in self.entries.values())
10891085 handle_stderr(proc, rval_iter)
10901086 return rval_iter
10911087 else:
1092 if isinstance(paths, string_types):
1088 if isinstance(paths, str):
10931089 paths = [paths]
10941090
10951091 # make sure we have our entries loaded before we start checkout_index
11161112 folder = co_path
11171113 if not folder.endswith('/'):
11181114 folder += '/'
1119 for entry in mviter(self.entries):
1115 for entry in self.entries.values():
11201116 if entry.path.startswith(folder):
11211117 p = entry.path
11221118 self._write_path_to_stdin(proc, p, p, make_exc,
12261222 # index against anything but None is a reverse diff with the respective
12271223 # item. Handle existing -R flags properly. Transform strings to the object
12281224 # so that we can call diff on it
1229 if isinstance(other, string_types):
1225 if isinstance(other, str):
12301226 other = self.repo.rev_parse(other)
12311227 # END object conversion
12321228
1414
1515 from git.cmd import PROC_CREATIONFLAGS, handle_process_output
1616 from git.compat import (
17 PY3,
1817 defenc,
1918 force_text,
2019 force_bytes,
2120 is_posix,
22 safe_encode,
2321 safe_decode,
2422 )
2523 from git.exc import (
7270 return
7371
7472 env = os.environ.copy()
75 env['GIT_INDEX_FILE'] = safe_decode(index.path) if PY3 else safe_encode(index.path)
73 env['GIT_INDEX_FILE'] = safe_decode(index.path)
7674 env['GIT_EDITOR'] = ':'
7775 try:
7876 cmd = subprocess.Popen([hp] + list(args),
2323 parse_actor_and_date,
2424 from_timestamp,
2525 )
26 from git.compat import text_type
2726
2827 from time import (
2928 time,
435434 write(b"\n")
436435
437436 # write plain bytes, be sure its encoded according to our encoding
438 if isinstance(self.message, text_type):
437 if isinstance(self.message, str):
439438 write(self.message.encode(self.encoding))
440439 else:
441440 write(self.message)
00 """Module with functions which are supposed to be as fast as possible"""
11 from stat import S_ISDIR
22 from git.compat import (
3 byte_ord,
43 safe_decode,
5 defenc,
6 xrange,
7 text_type,
8 bchr
4 defenc
95 )
106
117 __all__ = ('tree_to_stream', 'tree_entries_from_data', 'traverse_trees_recursive',
2117
2218 for binsha, mode, name in entries:
2319 mode_str = b''
24 for i in xrange(6):
25 mode_str = bchr(((mode >> (i * 3)) & bit_mask) + ord_zero) + mode_str
20 for i in range(6):
21 mode_str = bytes([((mode >> (i * 3)) & bit_mask) + ord_zero]) + mode_str
2622 # END for each 8 octal value
2723
2824 # git slices away the first octal if its zero
29 if byte_ord(mode_str[0]) == ord_zero:
25 if mode_str[0] == ord_zero:
3026 mode_str = mode_str[1:]
3127 # END save a byte
3228
3531 # hence we must convert to an utf8 string for it to work properly.
3632 # According to my tests, this is exactly what git does, that is it just
3733 # takes the input literally, which appears to be utf8 on linux.
38 if isinstance(name, text_type):
34 if isinstance(name, str):
3935 name = name.encode(defenc)
4036 write(b''.join((mode_str, b' ', name, b'\0', binsha)))
4137 # END for each item
5652 # read mode
5753 # Some git versions truncate the leading 0, some don't
5854 # The type will be extracted from the mode later
59 while byte_ord(data[i]) != space_ord:
55 while data[i] != space_ord:
6056 # move existing mode integer up one level being 3 bits
6157 # and add the actual ordinal value of the character
62 mode = (mode << 3) + (byte_ord(data[i]) - ord_zero)
58 mode = (mode << 3) + (data[i] - ord_zero)
6359 i += 1
6460 # END while reading mode
6561
6965 # parse name, it is NULL separated
7066
7167 ns = i
72 while byte_ord(data[i]) != 0:
68 while data[i] != 0:
7369 i += 1
7470 # END while not reached NULL
7571
88 import git
99 from git.cmd import Git
1010 from git.compat import (
11 string_types,
1211 defenc,
1312 is_win,
1413 )
109108 if url is not None:
110109 self._url = url
111110 if branch_path is not None:
112 assert isinstance(branch_path, string_types)
111 assert isinstance(branch_path, str)
113112 self._branch_path = branch_path
114113 if name is not None:
115114 self._name = name
1010 from .base import IndexObject
1111 from .blob import Blob
1212 from .submodule.base import Submodule
13 from git.compat import string_types
1413
1514 from .fun import (
1615 tree_entries_from_data,
1716 tree_to_stream
1817 )
1918
20 from git.compat import PY3
21
22 if PY3:
23 cmp = lambda a, b: (a > b) - (a < b)
19 cmp = lambda a, b: (a > b) - (a < b)
2420
2521 __all__ = ("TreeModifier", "Tree")
2622
292288 info = self._cache[item]
293289 return self._map_id_to_type[info[1] >> 12](self.repo, info[0], info[1], join_path(self.path, info[2]))
294290
295 if isinstance(item, string_types):
291 if isinstance(item, str):
296292 # compatibility
297293 return self.join(item)
298294 # END index is basestring
147147 try:
148148 if string_date.count(' ') == 1 and string_date.rfind(':') == -1:
149149 timestamp, offset = string_date.split()
150 if timestamp.startswith('@'):
151 timestamp = timestamp[1:]
150152 timestamp = int(timestamp)
151153 return timestamp, utctz_to_altz(verify_utctz(offset))
152154 else:
00 import re
11 import time
22
3 from git.compat import (
4 PY3,
5 xrange,
6 string_types,
7 defenc
8 )
3 from git.compat import defenc
94 from git.objects.util import (
105 parse_date,
116 Serializable,
3530
3631 def __repr__(self):
3732 """Representation of ourselves in git reflog format"""
38 res = self.format()
39 if PY3:
40 return res
41 # repr must return a string, which it will auto-encode from unicode using the default encoding.
42 # This usually fails, so we encode ourselves
43 return res.encode(defenc)
33 return self.format()
4434
4535 def format(self):
4636 """:return: a string suitable to be placed in a reflog file"""
191181 :param stream: file-like object containing the revlog in its native format
192182 or basestring instance pointing to a file to read"""
193183 new_entry = RefLogEntry.from_line
194 if isinstance(stream, string_types):
184 if isinstance(stream, str):
195185 stream = file_contents_ro_filepath(stream)
196186 # END handle stream type
197187 while True:
219209 if index < 0:
220210 return RefLogEntry.from_line(fp.readlines()[index].strip())
221211 # read until index is reached
222 for i in xrange(index + 1):
212 for i in range(index + 1):
223213 line = fp.readline()
224214 if not line:
225215 break
00 import os
11
2 from git.compat import (
3 string_types,
4 defenc
5 )
2 from git.compat import defenc
63 from git.objects import Object, Commit
74 from git.util import (
85 join_path,
299296 elif isinstance(ref, Object):
300297 obj = ref
301298 write_value = ref.hexsha
302 elif isinstance(ref, string_types):
299 elif isinstance(ref, str):
303300 try:
304301 obj = self.repo.rev_parse(ref + "^{}") # optionally deref tags
305302 write_value = obj.hexsha
33 # This module is part of GitPython and is released under
44 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
55
6 from builtins import str
76 from collections import namedtuple
87 import logging
98 import os
1514 handle_process_output
1615 )
1716 from git.compat import (
18 text_type,
1917 defenc,
20 PY3,
2118 safe_decode,
22 range,
2319 is_win,
2420 )
2521 from git.config import GitConfigParser
7672 re_whitespace = re.compile(r'\s+')
7773 re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
7874 re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{4,40}$')
75 re_envvars = re.compile(r'(\$(\{\s?)?[a-zA-Z_]\w*(\}\s?)?|%\s?[a-zA-Z_]\w*\s?%)')
7976 re_author_committer_start = re.compile(r'^(author|committer)')
8077 re_tab_full_line = re.compile(r'^\t(.*)$')
8178
124121 epath = epath or path or os.getcwd()
125122 if not isinstance(epath, str):
126123 epath = str(epath)
127 if expand_vars and ("%" in epath or "$" in epath):
124 if expand_vars and re.search(self.re_envvars, epath):
128125 warnings.warn("The use of environment variables in paths is deprecated" +
129126 "\nfor security reasons and may be removed in the future!!")
130127 epath = expand_path(epath, expand_vars)
477474 :return: ``git.Commit``"""
478475 if rev is None:
479476 return self.head.commit
480 return self.rev_parse(text_type(rev) + "^0")
477 return self.rev_parse(str(rev) + "^0")
481478
482479 def iter_trees(self, *args, **kwargs):
483480 """:return: Iterator yielding Tree objects
499496 operations might have unexpected results."""
500497 if rev is None:
501498 return self.head.commit.tree
502 return self.rev_parse(text_type(rev) + "^{tree}")
499 return self.rev_parse(str(rev) + "^{tree}")
503500
504501 def iter_commits(self, rev=None, paths='', **kwargs):
505502 """A list of Commit objects representing the history of a given ref/commit
691688 # Special characters are escaped
692689 if filename[0] == filename[-1] == '"':
693690 filename = filename[1:-1]
694 if PY3:
695 # WHATEVER ... it's a mess, but works for me
696 filename = filename.encode('ascii').decode('unicode_escape').encode('latin1').decode(defenc)
697 else:
698 filename = filename.decode('string_escape').decode(defenc)
691 # WHATEVER ... it's a mess, but works for me
692 filename = filename.encode('ascii').decode('unicode_escape').encode('latin1').decode(defenc)
699693 untracked_files.append(filename)
700694 finalize_process(proc)
701695 return untracked_files
22 import stat
33 from string import digits
44
5 from git.compat import xrange
65 from git.exc import WorkTreeRepositoryUnsupported
76 from git.objects import Object
87 from git.refs import SymbolicReference
306305 try:
307306 if token == "~":
308307 obj = to_commit(obj)
309 for _ in xrange(num):
308 for _ in range(num):
310309 obj = obj.parents[0]
311310 # END for each history item to walk
312311 elif token == "^":
1010 import io
1111 import logging
1212 import os
13 import sys
1413 import tempfile
1514 import textwrap
1615 import time
1716 import unittest
1817
19 from git.compat import string_types, is_win
18 from git.compat import is_win
2019 from git.util import rmtree, cwd
2120 import gitdb
2221
116115 To make working with relative paths easier, the cwd will be set to the working
117116 dir of the repository.
118117 """
119 assert isinstance(working_tree_ref, string_types), "Decorator requires ref name for working tree checkout"
118 assert isinstance(working_tree_ref, str), "Decorator requires ref name for working tree checkout"
120119
121120 def argument_passer(func):
122121 @wraps(func)
247246 """
248247 from git import Git, Remote # To avoid circular deps.
249248
250 assert isinstance(working_tree_ref, string_types), "Decorator requires ref name for working tree checkout"
249 assert isinstance(working_tree_ref, str), "Decorator requires ref name for working tree checkout"
251250
252251 def argument_passer(func):
253252
343342 of the project history ( to assure tests don't fail for others ).
344343 """
345344
346 # On py3, unittest has assertRaisesRegex
347 # On py27, we use unittest, which names it differently:
348 if sys.version_info[0:2] == (2, 7):
349 assertRaisesRegex = TestCase.assertRaisesRegexp
350
351345 def _small_repo_url(self):
352346 """:return" a path to a small, clonable repository"""
353347 from git.cmd import Git
1010 from .lib import TestBigRepoRW
1111 from git import Commit
1212 from gitdb import IStream
13 from git.compat import xrange
1413 from git.test.test_commit import assert_commit_serialization
1514
1615
8988
9089 nc = 5000
9190 st = time()
92 for i in xrange(nc):
91 for i in range(nc):
9392 cm = Commit(rwrepo, Commit.NULL_BIN_SHA, hc.tree,
9493 hc.author, hc.authored_date, hc.author_tz_offset,
9594 hc.committer, hc.committed_date, hc.committer_tz_offset,
1616 Actor,
1717 )
1818 from git import Repo
19 from git.compat import (
20 string_types,
21 text_type
22 )
2319 from git.objects.util import tzoffset, utc
2420 from git.repo.fun import touch
2521 from git.test.lib import (
144140 self.assertEqual(len(name), 9)
145141 special = Actor._from_string(u"%s <something@this.com>" % name)
146142 self.assertEqual(special.name, name)
147 assert isinstance(special.name, text_type)
143 assert isinstance(special.name, str)
148144
149145 def test_traversal(self):
150146 start = self.rorepo.commit("a4d06724202afccd2b5c54f81bcf2bf26dea7fff")
275271
276272 def test_name_rev(self):
277273 name_rev = self.rorepo.head.commit.name_rev
278 assert isinstance(name_rev, string_types)
274 assert isinstance(name_rev, str)
279275
280276 @with_rw_repo('HEAD', bare=True)
281277 def test_serialization(self, rwrepo):
288284 # create a commit with unicode in the message, and the author's name
289285 # Verify its serialization and deserialization
290286 cmt = self.rorepo.commit('0.1.6')
291 assert isinstance(cmt.message, text_type) # it automatically decodes it as such
292 assert isinstance(cmt.author.name, text_type) # same here
287 assert isinstance(cmt.message, str) # it automatically decodes it as such
288 assert isinstance(cmt.author.name, str) # same here
293289
294290 cmt.message = u"üäêèß"
295291 self.assertEqual(len(cmt.message), 5)
99 from git import (
1010 GitConfigParser
1111 )
12 from git.compat import string_types
1312 from git.config import _OMD, cp
1413 from git.test.lib import (
1514 TestCase,
156155 num_options += 1
157156 val = r_config.get(section, option)
158157 val_typed = r_config.get_value(section, option)
159 assert isinstance(val_typed, (bool, int, float, ) + string_types)
158 assert isinstance(val_typed, (bool, int, float, str))
160159 assert val
161160 assert "\n" not in option
162161 assert "\n" not in val
11 from stat import S_IFDIR, S_IFREG, S_IFLNK
22 from os import stat
33 import os.path as osp
4 from unittest import skipIf, SkipTest
4 from unittest import SkipTest
55
66 from git import Git
7 from git.compat import PY3
87 from git.index import IndexFile
98 from git.index.fun import (
109 aggressive_tree_merge
281280 statbuf = stat(gitdir)
282281 assert_true(statbuf.st_mode & S_IFDIR)
283282
284 @skipIf(PY3, 'odd types returned ... maybe figure it out one day')
285 def test_tree_entries_from_data_with_failing_name_decode_py2(self):
286 r = tree_entries_from_data(b'100644 \x9f\0aaa')
287 assert r == [('aaa', 33188, u'\udc9f')], r
288
289 @skipIf(not PY3, 'odd types returned ... maybe figure it out one day')
290283 def test_tree_entries_from_data_with_failing_name_decode_py3(self):
291284 r = tree_entries_from_data(b'100644 \x9f\0aaa')
292285 assert r == [(b'aaa', 33188, '\udc9f')], r
1616 Repo,
1717 cmd
1818 )
19 from git.compat import PY3, is_darwin
19 from git.compat import is_darwin
2020 from git.test.lib import (
2121 TestBase,
2222 patch,
6060
6161 def test_call_unpack_args_unicode(self):
6262 args = Git._Git__unpack_args(u'Unicode€™')
63 if PY3:
64 mangled_value = 'Unicode\u20ac\u2122'
65 else:
66 mangled_value = 'Unicode\xe2\x82\xac\xe2\x84\xa2'
63 mangled_value = 'Unicode\u20ac\u2122'
6764 assert_equal(args, [mangled_value])
6865
6966 def test_call_unpack_args(self):
7067 args = Git._Git__unpack_args(['git', 'log', '--', u'Unicode€™'])
71 if PY3:
72 mangled_value = 'Unicode\u20ac\u2122'
73 else:
74 mangled_value = 'Unicode\xe2\x82\xac\xe2\x84\xa2'
68 mangled_value = 'Unicode\u20ac\u2122'
7569 assert_equal(args, ['git', 'log', '--', mangled_value])
7670
7771 @raises(GitCommandError)
2424 GitCommandError,
2525 CheckoutError,
2626 )
27 from git.compat import string_types, is_win, PY3
27 from git.compat import is_win
2828 from git.exc import (
2929 HookExecutionError,
3030 InvalidGitRepositoryError
387387 self.assertEqual(len(e.failed_files), 1)
388388 self.assertEqual(e.failed_files[0], osp.basename(test_file))
389389 self.assertEqual(len(e.failed_files), len(e.failed_reasons))
390 self.assertIsInstance(e.failed_reasons[0], string_types)
390 self.assertIsInstance(e.failed_reasons[0], str)
391391 self.assertEqual(len(e.valid_files), 0)
392392 with open(test_file, 'rb') as fd:
393393 s = fd.read()
820820 asserted = True
821821 assert asserted, "Adding using a filename is not correctly asserted."
822822
823 @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and not PY3, r"""
824 FIXME: File "C:\projects\gitpython\git\util.py", line 125, in to_native_path_linux
825 return path.replace('\\', '/')
826 UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)""")
827823 @with_rw_directory
828824 def test_add_utf8P_path(self, rw_dir):
829825 # NOTE: fp is not a Unicode object in python 2 (which is the source of the problem)
2121 GitCommandError
2222 )
2323 from git.cmd import Git
24 from git.compat import string_types
2524 from git.test.lib import (
2625 TestBase,
2726 with_rw_repo,
115114 self.assertGreater(len(results), 0)
116115 self.assertIsInstance(results[0], FetchInfo)
117116 for info in results:
118 self.assertIsInstance(info.note, string_types)
117 self.assertIsInstance(info.note, str)
119118 if isinstance(info.ref, Reference):
120119 self.assertTrue(info.flags)
121120 # END reference type flags handling
132131 self.assertIsInstance(results[0], PushInfo)
133132 for info in results:
134133 self.assertTrue(info.flags)
135 self.assertIsInstance(info.summary, string_types)
134 self.assertIsInstance(info.summary, str)
136135 if info.old_commit is not None:
137136 self.assertIsInstance(info.old_commit, Commit)
138137 if info.flags & info.ERROR:
3535 BadName,
3636 GitCommandError
3737 )
38 from git.compat import (
39 PY3,
40 is_win,
41 string_types,
42 win_encode,
43 )
4438 from git.exc import (
4539 BadObject,
4640 )
5953 from git.test.lib import with_rw_directory
6054 from git.util import join_path_native, rmtree, rmfile, bin_to_hex
6155
62 import functools as fnt
6356 import os.path as osp
6457
6558
218211 cloned = Repo.clone_from(original_repo.git_dir, osp.join(rw_dir, "clone"), env=environment)
219212
220213 assert_equal(environment, cloned.git.environment())
214
215 @with_rw_directory
216 def test_date_format(self, rw_dir):
217 repo = Repo.init(osp.join(rw_dir, "repo"))
218 # @-timestamp is the format used by git commit hooks
219 repo.index.commit("Commit messages", commit_date="@1400000000 +0000")
221220
222221 @with_rw_directory
223222 def test_clone_from_pathlib(self, rw_dir):
435434 # test the 'lines per commit' entries
436435 tlist = b[0][1]
437436 assert_true(tlist)
438 assert_true(isinstance(tlist[0], string_types))
437 assert_true(isinstance(tlist[0], str))
439438 assert_true(len(tlist) < sum(len(t) for t in tlist)) # test for single-char bug
440439
441440 # BINARY BLAME
496495 """)
497496 @with_rw_repo('HEAD', bare=False)
498497 def test_untracked_files(self, rwrepo):
499 for run, (repo_add, is_invoking_git) in enumerate((
500 (rwrepo.index.add, False),
501 (rwrepo.git.add, True),
502 )):
498 for run, repo_add in enumerate((rwrepo.index.add, rwrepo.git.add)):
503499 base = rwrepo.working_tree_dir
504500 files = (join_path_native(base, u"%i_test _myfile" % run),
505501 join_path_native(base, "%i_test_other_file" % run),
519515 num_test_untracked += join_path_native(base, utfile) in files
520516 self.assertEqual(len(files), num_test_untracked)
521517
522 if is_win and not PY3 and is_invoking_git:
523 ## On Windows, shell needed when passing unicode cmd-args.
524 #
525 repo_add = fnt.partial(repo_add, shell=True)
526 untracked_files = [win_encode(f) for f in untracked_files]
527518 repo_add(untracked_files)
528519 self.assertEqual(len(rwrepo.untracked_files), (num_recently_untracked - len(files)))
529520 # end for each run
77
88 import git
99 from git.cmd import Git
10 from git.compat import string_types, is_win
10 from git.compat import is_win
1111 from git.exc import (
1212 InvalidGitRepositoryError,
1313 RepositoryDirtyError
7878 self.failUnlessRaises(InvalidGitRepositoryError, getattr, sm, 'branch')
7979
8080 # branch_path works, as its just a string
81 assert isinstance(sm.branch_path, string_types)
81 assert isinstance(sm.branch_path, str)
8282
8383 # some commits earlier we still have a submodule, but its at a different commit
8484 smold = next(Submodule.iter_items(rwrepo, self.k_subm_changed))
1212 import ddt
1313
1414 from git.cmd import dashify
15 from git.compat import string_types, is_win
15 from git.compat import is_win
1616 from git.objects.util import (
1717 altz_to_utctz_str,
1818 utctz_to_altz,
186186
187187 # now that we are here, test our conversion functions as well
188188 utctz = altz_to_utctz_str(offset)
189 self.assertIsInstance(utctz, string_types)
189 self.assertIsInstance(utctz, str)
190190 self.assertEqual(utctz_to_altz(verify_utctz(utctz)), offset)
191191 # END assert rval utility
192192
1212 import re
1313 import shutil
1414 import stat
15 from sys import maxsize
1516 import time
1617 from unittest import SkipTest
1718
3031 from git.compat import is_win
3132 import os.path as osp
3233
33 from .compat import (
34 MAXSIZE,
35 defenc,
36 PY3
37 )
3834 from .exc import InvalidGitRepositoryError
3935
4036
591587 ('email', env_email, cls.conf_email, default_email)):
592588 try:
593589 val = os.environ[evar]
594 if not PY3:
595 val = val.decode(defenc)
596 # end assure we don't get 'invalid strings'
597590 setattr(actor, attr, val)
598591 except KeyError:
599592 if config_reader is not None:
786779 can never be obtained."""
787780 __slots__ = ("_check_interval", "_max_block_time")
788781
789 def __init__(self, file_path, check_interval_s=0.3, max_block_time_s=MAXSIZE):
782 def __init__(self, file_path, check_interval_s=0.3, max_block_time_s=maxsize):
790783 """Configure the instance
791784
792785 :param check_interval_s:
939932 class NullHandler(logging.Handler):
940933 def emit(self, record):
941934 pass
942
943
944 # In Python 2.6, there is no NullHandler yet. Let's monkey-patch it for a workaround.
945 if not hasattr(logging, 'NullHandler'):
946 logging.NullHandler = NullHandler
0 gitdb2 (>=2.0.0)
0 gitdb2>=2.0.0
7777 py_modules=['git.' + f[:-3] for f in os.listdir('./git') if f.endswith('.py')],
7878 package_data={'git.test': ['fixtures/*']},
7979 package_dir={'git': 'git'},
80 python_requires='>=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
80 python_requires='>=3.4',
8181 install_requires=requirements,
8282 tests_require=requirements + test_requirements,
8383 zip_safe=False,