New upstream version 3.0.7
TANIGUCHI Takaki
4 years ago
36 | 36 | -Anil Khatri <anil.soccer.khatri _at_ gmail.com> |
37 | 37 | -JJ Graham <thetwoj _at_ gmail.com> |
38 | 38 | -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> | |
40 | 42 | Portions derived from other open source works and are clearly marked. |
0 | 0 | Metadata-Version: 1.2 |
1 | 1 | Name: GitPython |
2 | Version: 3.0.5 | |
2 | Version: 3.0.7 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: https://github.com/gitpython-developers/GitPython |
5 | 5 | Author: Sebastian Thiel, Michael Trier |
21 | 21 | Classifier: Programming Language :: Python :: 3.5 |
22 | 22 | Classifier: Programming Language :: Python :: 3.6 |
23 | 23 | Classifier: Programming Language :: Python :: 3.7 |
24 | Requires-Python: >=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* | |
24 | Requires-Python: >=3.4 |
0 | 0 | Metadata-Version: 1.2 |
1 | 1 | Name: GitPython |
2 | Version: 3.0.5 | |
2 | Version: 3.0.7 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: https://github.com/gitpython-developers/GitPython |
5 | 5 | Author: Sebastian Thiel, Michael Trier |
21 | 21 | Classifier: Programming Language :: Python :: 3.5 |
22 | 22 | Classifier: Programming Language :: Python :: 3.6 |
23 | 23 | Classifier: Programming Language :: Python :: 3.7 |
24 | Requires-Python: >=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* | |
24 | Requires-Python: >=3.4 |
63 | 63 | |
64 | 64 | #### Windows support |
65 | 65 | |
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). | |
69 | 67 | |
70 | 68 | ### RUNNING TESTS |
71 | 69 | |
189 | 187 | |
190 | 188 | [![codecov](https://codecov.io/gh/gitpython-developers/GitPython/branch/master/graph/badge.svg)](https://codecov.io/gh/gitpython-developers/GitPython) |
191 | 189 | [![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) | |
193 | 190 | [![Code Climate](https://codeclimate.com/github/gitpython-developers/GitPython/badges/gpa.svg)](https://codeclimate.com/github/gitpython-developers/GitPython) |
194 | 191 | [![Documentation Status](https://readthedocs.org/projects/gitpython/badge/?version=stable)](https://readthedocs.org/projects/gitpython/?badge=stable) |
195 | 192 | [![Stories in Ready](https://badge.waffle.io/gitpython-developers/GitPython.png?label=ready&title=Ready)](https://waffle.io/gitpython-developers/GitPython) |
0 | 0 | ========= |
1 | 1 | Changelog |
2 | 2 | ========= |
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. | |
3 | 23 | |
4 | 24 | 3.0.5 - Bugfixes |
5 | 25 | ============================================= |
11 | 11 | import os.path as osp |
12 | 12 | |
13 | 13 | |
14 | __version__ = '3.0.5' | |
14 | __version__ = '3.0.7' | |
15 | 15 | |
16 | 16 | |
17 | 17 | #{ Initialization |
18 | 18 | def _init_externals(): |
19 | 19 | """Initialize external projects by putting them into the path""" |
20 | if __version__ == '3.0.5': | |
20 | if __version__ == '3.0.7': | |
21 | 21 | sys.path.insert(0, osp.join(osp.dirname(__file__), 'ext', 'gitdb')) |
22 | 22 | |
23 | 23 | try: |
20 | 20 | from textwrap import dedent |
21 | 21 | |
22 | 22 | from git.compat import ( |
23 | string_types, | |
24 | 23 | defenc, |
25 | 24 | force_bytes, |
26 | PY3, | |
27 | # just to satisfy flake8 on py3 | |
28 | unicode, | |
29 | 25 | safe_decode, |
30 | 26 | is_posix, |
31 | 27 | is_win, |
41 | 37 | LazyMixin, |
42 | 38 | stream_copy, |
43 | 39 | ) |
44 | ||
45 | try: | |
46 | PermissionError | |
47 | except NameError: # Python < 3.3 | |
48 | PermissionError = OSError | |
49 | 40 | |
50 | 41 | execute_kwargs = {'istream', 'with_extended_output', |
51 | 42 | 'with_exceptions', 'as_process', 'stdout_as_string', |
917 | 908 | @classmethod |
918 | 909 | def __unpack_args(cls, arg_list): |
919 | 910 | 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)] | |
924 | 911 | return [str(arg_list)] |
925 | 912 | |
926 | 913 | outlist = [] |
927 | 914 | for arg in arg_list: |
928 | 915 | if isinstance(arg_list, (list, tuple)): |
929 | 916 | outlist.extend(cls.__unpack_args(arg)) |
930 | elif not PY3 and isinstance(arg_list, unicode): | |
931 | outlist.append(arg_list.encode(defenc)) | |
932 | 917 | # END recursion |
933 | 918 | else: |
934 | 919 | outlist.append(str(arg)) |
1046 | 1031 | if isinstance(ref, bytes): |
1047 | 1032 | # Assume 40 bytes hexsha - bin-to-ascii for some reason returns bytes, not text |
1048 | 1033 | refstr = ref.decode('ascii') |
1049 | elif not isinstance(ref, string_types): | |
1034 | elif not isinstance(ref, str): | |
1050 | 1035 | refstr = str(ref) # could be ref-object |
1051 | 1036 | |
1052 | 1037 | if not refstr.endswith("\n"): |
9 | 9 | import locale |
10 | 10 | import os |
11 | 11 | import sys |
12 | import codecs | |
13 | 12 | |
14 | 13 | |
15 | from gitdb.utils.compat import ( | |
16 | xrange, | |
17 | MAXSIZE, # @UnusedImport | |
18 | izip, # @UnusedImport | |
19 | ) | |
20 | 14 | from gitdb.utils.encoding import ( |
21 | string_types, # @UnusedImport | |
22 | text_type, # @UnusedImport | |
23 | 15 | force_bytes, # @UnusedImport |
24 | 16 | force_text # @UnusedImport |
25 | 17 | ) |
26 | 18 | |
27 | 19 | |
28 | PY3 = sys.version_info[0] >= 3 | |
29 | 20 | is_win = (os.name == 'nt') |
30 | 21 | is_posix = (os.name == 'posix') |
31 | 22 | 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() | |
67 | 24 | |
68 | 25 | |
69 | 26 | def safe_decode(s): |
70 | 27 | """Safely decodes a binary string to unicode""" |
71 | if isinstance(s, unicode): | |
28 | if isinstance(s, str): | |
72 | 29 | return s |
73 | 30 | elif isinstance(s, bytes): |
74 | 31 | return s.decode(defenc, 'surrogateescape') |
78 | 35 | |
79 | 36 | def safe_encode(s): |
80 | 37 | """Safely decodes a binary string to unicode""" |
81 | if isinstance(s, unicode): | |
38 | if isinstance(s, str): | |
82 | 39 | return s.encode(defenc) |
83 | 40 | elif isinstance(s, bytes): |
84 | 41 | return s |
88 | 45 | |
89 | 46 | def win_encode(s): |
90 | 47 | """Encode unicodes for process arguments on Windows.""" |
91 | if isinstance(s, unicode): | |
48 | if isinstance(s, str): | |
92 | 49 | return s.encode(locale.getpreferredencoding(False)) |
93 | 50 | elif isinstance(s, bytes): |
94 | 51 | return s |
105 | 62 | def __new__(cls, name, nbases, d): |
106 | 63 | if nbases is None: |
107 | 64 | 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 | |
112 | 65 | return meta(name, bases, d) |
113 | 66 | 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() |
8 | 8 | import abc |
9 | 9 | from functools import wraps |
10 | 10 | import inspect |
11 | from io import IOBase | |
11 | 12 | import logging |
12 | 13 | import os |
13 | 14 | import re |
14 | 15 | from collections import OrderedDict |
15 | 16 | |
16 | 17 | from git.compat import ( |
17 | string_types, | |
18 | FileType, | |
19 | 18 | defenc, |
20 | 19 | force_text, |
21 | 20 | with_metaclass, |
22 | PY3, | |
23 | 21 | is_win, |
24 | 22 | ) |
25 | 23 | from git.util import LockFile |
26 | 24 | |
27 | 25 | import os.path as osp |
28 | 26 | |
29 | ||
30 | try: | |
31 | import ConfigParser as cp | |
32 | except ImportError: | |
33 | # PY3 | |
34 | import configparser as cp | |
27 | import configparser as cp | |
35 | 28 | |
36 | 29 | |
37 | 30 | __all__ = ('GitConfigParser', 'SectionConstraint') |
302 | 295 | # END single file check |
303 | 296 | |
304 | 297 | 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): | |
306 | 299 | file_or_files = self._file_or_files.name |
307 | 300 | # END get filename from handle/stream |
308 | 301 | # initialize lock base - we want to write |
371 | 364 | v = v[:-1] |
372 | 365 | # end cut trailing escapes to prevent decode error |
373 | 366 | |
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') | |
377 | 368 | # end |
378 | 369 | # end |
379 | 370 | |
580 | 571 | fp = self._file_or_files |
581 | 572 | |
582 | 573 | # 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)) | |
584 | 575 | if is_file_lock: |
585 | 576 | self._lock._obtain_lock() |
586 | 577 | if not hasattr(fp, "seek"): |
672 | 663 | if vl == 'true': |
673 | 664 | return True |
674 | 665 | |
675 | if not isinstance(valuestr, string_types): | |
666 | if not isinstance(valuestr, str): | |
676 | 667 | raise TypeError( |
677 | 668 | "Invalid value type: only int, long, float and str are allowed", |
678 | 669 | valuestr) |
5 | 5 | import re |
6 | 6 | |
7 | 7 | from git.cmd import handle_process_output |
8 | from git.compat import ( | |
9 | defenc, | |
10 | PY3 | |
11 | ) | |
8 | from git.compat import defenc | |
12 | 9 | from git.util import finalize_process, hex_to_bin |
13 | 10 | |
14 | from .compat import binary_type | |
15 | 11 | from .objects.blob import Blob |
16 | 12 | from .objects.util import mode_str_to_int |
17 | 13 | |
27 | 23 | def _octal_repl(matchobj): |
28 | 24 | value = matchobj.group(1) |
29 | 25 | value = int(value, 8) |
30 | if PY3: | |
31 | value = bytes(bytearray((value,))) | |
32 | else: | |
33 | value = chr(value) | |
26 | value = bytes(bytearray((value,))) | |
34 | 27 | return value |
35 | 28 | |
36 | 29 | |
267 | 260 | self.a_mode = a_mode |
268 | 261 | self.b_mode = b_mode |
269 | 262 | |
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) | |
272 | 265 | self.a_rawpath = a_rawpath |
273 | 266 | self.b_rawpath = b_rawpath |
274 | 267 | |
301 | 294 | self.copied_file = copied_file |
302 | 295 | |
303 | 296 | # 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) | |
306 | 299 | self.raw_rename_from = raw_rename_from or None |
307 | 300 | self.raw_rename_to = raw_rename_to or None |
308 | 301 | |
369 | 362 | # Python2 silliness: have to assure we convert our likely to be unicode object to a string with the |
370 | 363 | # right encoding. Otherwise it tries to convert it using ascii, which may fail ungracefully |
371 | 364 | res = h + msg |
372 | if not PY3: | |
373 | res = res.encode(defenc) | |
374 | 365 | # end |
375 | 366 | return res |
376 | 367 |
5 | 5 | """ Module containing all exceptions thrown throughout the git package, """ |
6 | 6 | |
7 | 7 | 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 | |
9 | 9 | |
10 | 10 | |
11 | 11 | class GitError(Exception): |
24 | 24 | """ Thrown if a path could not be access by the system. """ |
25 | 25 | |
26 | 26 | |
27 | class CommandError(UnicodeMixin, GitError): | |
27 | class CommandError(GitError): | |
28 | 28 | """Base class for exceptions thrown at every stage of `Popen()` execution. |
29 | 29 | |
30 | 30 | :param command: |
49 | 49 | status = u'exit code(%s)' % int(status) |
50 | 50 | except (ValueError, TypeError): |
51 | 51 | 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 | |
53 | 53 | |
54 | 54 | self._cmd = safe_decode(command[0]) |
55 | 55 | self._cmdline = u' '.join(safe_decode(i) for i in command) |
57 | 57 | self.stdout = stdout and u"\n stdout: '%s'" % safe_decode(stdout) or '' |
58 | 58 | self.stderr = stderr and u"\n stderr: '%s'" % safe_decode(stderr) or '' |
59 | 59 | |
60 | def __unicode__(self): | |
60 | def __str__(self): | |
61 | 61 | return (self._msg + "\n cmdline: %s%s%s") % ( |
62 | 62 | self._cmd, self._cause, self._cmdline, self.stdout, self.stderr) |
63 | 63 |
10 | 10 | import tempfile |
11 | 11 | |
12 | 12 | from git.compat import ( |
13 | izip, | |
14 | xrange, | |
15 | string_types, | |
16 | 13 | force_bytes, |
17 | 14 | defenc, |
18 | mviter, | |
19 | 15 | ) |
20 | 16 | from git.exc import ( |
21 | 17 | GitCommandError, |
271 | 267 | |
272 | 268 | inst = cls(repo) |
273 | 269 | # 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))) | |
276 | 272 | |
277 | 273 | inst.entries = entries |
278 | 274 | return inst |
441 | 437 | Function(t) returning True if tuple(stage, Blob) should be yielded by the |
442 | 438 | iterator. A default filter, the BlobFilter, allows you to yield blobs |
443 | 439 | only if they match a given list of paths. """ |
444 | for entry in mviter(self.entries): | |
440 | for entry in self.entries.values(): | |
445 | 441 | blob = entry.to_blob(self.repo) |
446 | 442 | blob.size = entry.size |
447 | 443 | output = (entry.stage, blob) |
466 | 462 | for stage, blob in self.iter_blobs(is_unmerged_blob): |
467 | 463 | path_map.setdefault(blob.path, []).append((stage, blob)) |
468 | 464 | # END for each unmerged blob |
469 | for l in mviter(path_map): | |
465 | for l in path_map.values(): | |
470 | 466 | l.sort() |
471 | 467 | return path_map |
472 | 468 | |
573 | 569 | items = [items] |
574 | 570 | |
575 | 571 | for item in items: |
576 | if isinstance(item, string_types): | |
572 | if isinstance(item, str): | |
577 | 573 | paths.append(self._to_relative_path(item)) |
578 | 574 | elif isinstance(item, (Blob, Submodule)): |
579 | 575 | entries.append(BaseIndexEntry.from_blob(item)) |
810 | 806 | for item in items: |
811 | 807 | if isinstance(item, (BaseIndexEntry, (Blob, Submodule))): |
812 | 808 | paths.append(self._to_relative_path(item.path)) |
813 | elif isinstance(item, string_types): | |
809 | elif isinstance(item, str): | |
814 | 810 | paths.append(self._to_relative_path(item)) |
815 | 811 | else: |
816 | 812 | raise TypeError("Invalid item type: %r" % item) |
912 | 908 | |
913 | 909 | # parse result - first 0:n/2 lines are 'checking ', the remaining ones |
914 | 910 | # 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)): | |
916 | 912 | tokens = mvlines[ln].split(' to ') |
917 | 913 | assert len(tokens) == 2, "Too many tokens in %s" % mvlines[ln] |
918 | 914 | |
1085 | 1081 | proc = self.repo.git.checkout_index(*args, **kwargs) |
1086 | 1082 | proc.wait() |
1087 | 1083 | 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()) | |
1089 | 1085 | handle_stderr(proc, rval_iter) |
1090 | 1086 | return rval_iter |
1091 | 1087 | else: |
1092 | if isinstance(paths, string_types): | |
1088 | if isinstance(paths, str): | |
1093 | 1089 | paths = [paths] |
1094 | 1090 | |
1095 | 1091 | # make sure we have our entries loaded before we start checkout_index |
1116 | 1112 | folder = co_path |
1117 | 1113 | if not folder.endswith('/'): |
1118 | 1114 | folder += '/' |
1119 | for entry in mviter(self.entries): | |
1115 | for entry in self.entries.values(): | |
1120 | 1116 | if entry.path.startswith(folder): |
1121 | 1117 | p = entry.path |
1122 | 1118 | self._write_path_to_stdin(proc, p, p, make_exc, |
1226 | 1222 | # index against anything but None is a reverse diff with the respective |
1227 | 1223 | # item. Handle existing -R flags properly. Transform strings to the object |
1228 | 1224 | # so that we can call diff on it |
1229 | if isinstance(other, string_types): | |
1225 | if isinstance(other, str): | |
1230 | 1226 | other = self.repo.rev_parse(other) |
1231 | 1227 | # END object conversion |
1232 | 1228 |
14 | 14 | |
15 | 15 | from git.cmd import PROC_CREATIONFLAGS, handle_process_output |
16 | 16 | from git.compat import ( |
17 | PY3, | |
18 | 17 | defenc, |
19 | 18 | force_text, |
20 | 19 | force_bytes, |
21 | 20 | is_posix, |
22 | safe_encode, | |
23 | 21 | safe_decode, |
24 | 22 | ) |
25 | 23 | from git.exc import ( |
72 | 70 | return |
73 | 71 | |
74 | 72 | 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) | |
76 | 74 | env['GIT_EDITOR'] = ':' |
77 | 75 | try: |
78 | 76 | cmd = subprocess.Popen([hp] + list(args), |
23 | 23 | parse_actor_and_date, |
24 | 24 | from_timestamp, |
25 | 25 | ) |
26 | from git.compat import text_type | |
27 | 26 | |
28 | 27 | from time import ( |
29 | 28 | time, |
435 | 434 | write(b"\n") |
436 | 435 | |
437 | 436 | # write plain bytes, be sure its encoded according to our encoding |
438 | if isinstance(self.message, text_type): | |
437 | if isinstance(self.message, str): | |
439 | 438 | write(self.message.encode(self.encoding)) |
440 | 439 | else: |
441 | 440 | write(self.message) |
0 | 0 | """Module with functions which are supposed to be as fast as possible""" |
1 | 1 | from stat import S_ISDIR |
2 | 2 | from git.compat import ( |
3 | byte_ord, | |
4 | 3 | safe_decode, |
5 | defenc, | |
6 | xrange, | |
7 | text_type, | |
8 | bchr | |
4 | defenc | |
9 | 5 | ) |
10 | 6 | |
11 | 7 | __all__ = ('tree_to_stream', 'tree_entries_from_data', 'traverse_trees_recursive', |
21 | 17 | |
22 | 18 | for binsha, mode, name in entries: |
23 | 19 | 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 | |
26 | 22 | # END for each 8 octal value |
27 | 23 | |
28 | 24 | # 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: | |
30 | 26 | mode_str = mode_str[1:] |
31 | 27 | # END save a byte |
32 | 28 | |
35 | 31 | # hence we must convert to an utf8 string for it to work properly. |
36 | 32 | # According to my tests, this is exactly what git does, that is it just |
37 | 33 | # takes the input literally, which appears to be utf8 on linux. |
38 | if isinstance(name, text_type): | |
34 | if isinstance(name, str): | |
39 | 35 | name = name.encode(defenc) |
40 | 36 | write(b''.join((mode_str, b' ', name, b'\0', binsha))) |
41 | 37 | # END for each item |
56 | 52 | # read mode |
57 | 53 | # Some git versions truncate the leading 0, some don't |
58 | 54 | # The type will be extracted from the mode later |
59 | while byte_ord(data[i]) != space_ord: | |
55 | while data[i] != space_ord: | |
60 | 56 | # move existing mode integer up one level being 3 bits |
61 | 57 | # 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) | |
63 | 59 | i += 1 |
64 | 60 | # END while reading mode |
65 | 61 | |
69 | 65 | # parse name, it is NULL separated |
70 | 66 | |
71 | 67 | ns = i |
72 | while byte_ord(data[i]) != 0: | |
68 | while data[i] != 0: | |
73 | 69 | i += 1 |
74 | 70 | # END while not reached NULL |
75 | 71 |
8 | 8 | import git |
9 | 9 | from git.cmd import Git |
10 | 10 | from git.compat import ( |
11 | string_types, | |
12 | 11 | defenc, |
13 | 12 | is_win, |
14 | 13 | ) |
109 | 108 | if url is not None: |
110 | 109 | self._url = url |
111 | 110 | if branch_path is not None: |
112 | assert isinstance(branch_path, string_types) | |
111 | assert isinstance(branch_path, str) | |
113 | 112 | self._branch_path = branch_path |
114 | 113 | if name is not None: |
115 | 114 | self._name = name |
10 | 10 | from .base import IndexObject |
11 | 11 | from .blob import Blob |
12 | 12 | from .submodule.base import Submodule |
13 | from git.compat import string_types | |
14 | 13 | |
15 | 14 | from .fun import ( |
16 | 15 | tree_entries_from_data, |
17 | 16 | tree_to_stream |
18 | 17 | ) |
19 | 18 | |
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) | |
24 | 20 | |
25 | 21 | __all__ = ("TreeModifier", "Tree") |
26 | 22 | |
292 | 288 | info = self._cache[item] |
293 | 289 | return self._map_id_to_type[info[1] >> 12](self.repo, info[0], info[1], join_path(self.path, info[2])) |
294 | 290 | |
295 | if isinstance(item, string_types): | |
291 | if isinstance(item, str): | |
296 | 292 | # compatibility |
297 | 293 | return self.join(item) |
298 | 294 | # END index is basestring |
147 | 147 | try: |
148 | 148 | if string_date.count(' ') == 1 and string_date.rfind(':') == -1: |
149 | 149 | timestamp, offset = string_date.split() |
150 | if timestamp.startswith('@'): | |
151 | timestamp = timestamp[1:] | |
150 | 152 | timestamp = int(timestamp) |
151 | 153 | return timestamp, utctz_to_altz(verify_utctz(offset)) |
152 | 154 | else: |
0 | 0 | import re |
1 | 1 | import time |
2 | 2 | |
3 | from git.compat import ( | |
4 | PY3, | |
5 | xrange, | |
6 | string_types, | |
7 | defenc | |
8 | ) | |
3 | from git.compat import defenc | |
9 | 4 | from git.objects.util import ( |
10 | 5 | parse_date, |
11 | 6 | Serializable, |
35 | 30 | |
36 | 31 | def __repr__(self): |
37 | 32 | """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() | |
44 | 34 | |
45 | 35 | def format(self): |
46 | 36 | """:return: a string suitable to be placed in a reflog file""" |
191 | 181 | :param stream: file-like object containing the revlog in its native format |
192 | 182 | or basestring instance pointing to a file to read""" |
193 | 183 | new_entry = RefLogEntry.from_line |
194 | if isinstance(stream, string_types): | |
184 | if isinstance(stream, str): | |
195 | 185 | stream = file_contents_ro_filepath(stream) |
196 | 186 | # END handle stream type |
197 | 187 | while True: |
219 | 209 | if index < 0: |
220 | 210 | return RefLogEntry.from_line(fp.readlines()[index].strip()) |
221 | 211 | # read until index is reached |
222 | for i in xrange(index + 1): | |
212 | for i in range(index + 1): | |
223 | 213 | line = fp.readline() |
224 | 214 | if not line: |
225 | 215 | break |
0 | 0 | import os |
1 | 1 | |
2 | from git.compat import ( | |
3 | string_types, | |
4 | defenc | |
5 | ) | |
2 | from git.compat import defenc | |
6 | 3 | from git.objects import Object, Commit |
7 | 4 | from git.util import ( |
8 | 5 | join_path, |
299 | 296 | elif isinstance(ref, Object): |
300 | 297 | obj = ref |
301 | 298 | write_value = ref.hexsha |
302 | elif isinstance(ref, string_types): | |
299 | elif isinstance(ref, str): | |
303 | 300 | try: |
304 | 301 | obj = self.repo.rev_parse(ref + "^{}") # optionally deref tags |
305 | 302 | write_value = obj.hexsha |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
5 | 5 | |
6 | from builtins import str | |
7 | 6 | from collections import namedtuple |
8 | 7 | import logging |
9 | 8 | import os |
15 | 14 | handle_process_output |
16 | 15 | ) |
17 | 16 | from git.compat import ( |
18 | text_type, | |
19 | 17 | defenc, |
20 | PY3, | |
21 | 18 | safe_decode, |
22 | range, | |
23 | 19 | is_win, |
24 | 20 | ) |
25 | 21 | from git.config import GitConfigParser |
76 | 72 | re_whitespace = re.compile(r'\s+') |
77 | 73 | re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') |
78 | 74 | 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?%)') | |
79 | 76 | re_author_committer_start = re.compile(r'^(author|committer)') |
80 | 77 | re_tab_full_line = re.compile(r'^\t(.*)$') |
81 | 78 | |
124 | 121 | epath = epath or path or os.getcwd() |
125 | 122 | if not isinstance(epath, str): |
126 | 123 | epath = str(epath) |
127 | if expand_vars and ("%" in epath or "$" in epath): | |
124 | if expand_vars and re.search(self.re_envvars, epath): | |
128 | 125 | warnings.warn("The use of environment variables in paths is deprecated" + |
129 | 126 | "\nfor security reasons and may be removed in the future!!") |
130 | 127 | epath = expand_path(epath, expand_vars) |
477 | 474 | :return: ``git.Commit``""" |
478 | 475 | if rev is None: |
479 | 476 | return self.head.commit |
480 | return self.rev_parse(text_type(rev) + "^0") | |
477 | return self.rev_parse(str(rev) + "^0") | |
481 | 478 | |
482 | 479 | def iter_trees(self, *args, **kwargs): |
483 | 480 | """:return: Iterator yielding Tree objects |
499 | 496 | operations might have unexpected results.""" |
500 | 497 | if rev is None: |
501 | 498 | return self.head.commit.tree |
502 | return self.rev_parse(text_type(rev) + "^{tree}") | |
499 | return self.rev_parse(str(rev) + "^{tree}") | |
503 | 500 | |
504 | 501 | def iter_commits(self, rev=None, paths='', **kwargs): |
505 | 502 | """A list of Commit objects representing the history of a given ref/commit |
691 | 688 | # Special characters are escaped |
692 | 689 | if filename[0] == filename[-1] == '"': |
693 | 690 | 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) | |
699 | 693 | untracked_files.append(filename) |
700 | 694 | finalize_process(proc) |
701 | 695 | return untracked_files |
2 | 2 | import stat |
3 | 3 | from string import digits |
4 | 4 | |
5 | from git.compat import xrange | |
6 | 5 | from git.exc import WorkTreeRepositoryUnsupported |
7 | 6 | from git.objects import Object |
8 | 7 | from git.refs import SymbolicReference |
306 | 305 | try: |
307 | 306 | if token == "~": |
308 | 307 | obj = to_commit(obj) |
309 | for _ in xrange(num): | |
308 | for _ in range(num): | |
310 | 309 | obj = obj.parents[0] |
311 | 310 | # END for each history item to walk |
312 | 311 | elif token == "^": |
10 | 10 | import io |
11 | 11 | import logging |
12 | 12 | import os |
13 | import sys | |
14 | 13 | import tempfile |
15 | 14 | import textwrap |
16 | 15 | import time |
17 | 16 | import unittest |
18 | 17 | |
19 | from git.compat import string_types, is_win | |
18 | from git.compat import is_win | |
20 | 19 | from git.util import rmtree, cwd |
21 | 20 | import gitdb |
22 | 21 | |
116 | 115 | To make working with relative paths easier, the cwd will be set to the working |
117 | 116 | dir of the repository. |
118 | 117 | """ |
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" | |
120 | 119 | |
121 | 120 | def argument_passer(func): |
122 | 121 | @wraps(func) |
247 | 246 | """ |
248 | 247 | from git import Git, Remote # To avoid circular deps. |
249 | 248 | |
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" | |
251 | 250 | |
252 | 251 | def argument_passer(func): |
253 | 252 | |
343 | 342 | of the project history ( to assure tests don't fail for others ). |
344 | 343 | """ |
345 | 344 | |
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 | ||
351 | 345 | def _small_repo_url(self): |
352 | 346 | """:return" a path to a small, clonable repository""" |
353 | 347 | from git.cmd import Git |
10 | 10 | from .lib import TestBigRepoRW |
11 | 11 | from git import Commit |
12 | 12 | from gitdb import IStream |
13 | from git.compat import xrange | |
14 | 13 | from git.test.test_commit import assert_commit_serialization |
15 | 14 | |
16 | 15 | |
89 | 88 | |
90 | 89 | nc = 5000 |
91 | 90 | st = time() |
92 | for i in xrange(nc): | |
91 | for i in range(nc): | |
93 | 92 | cm = Commit(rwrepo, Commit.NULL_BIN_SHA, hc.tree, |
94 | 93 | hc.author, hc.authored_date, hc.author_tz_offset, |
95 | 94 | hc.committer, hc.committed_date, hc.committer_tz_offset, |
16 | 16 | Actor, |
17 | 17 | ) |
18 | 18 | from git import Repo |
19 | from git.compat import ( | |
20 | string_types, | |
21 | text_type | |
22 | ) | |
23 | 19 | from git.objects.util import tzoffset, utc |
24 | 20 | from git.repo.fun import touch |
25 | 21 | from git.test.lib import ( |
144 | 140 | self.assertEqual(len(name), 9) |
145 | 141 | special = Actor._from_string(u"%s <something@this.com>" % name) |
146 | 142 | self.assertEqual(special.name, name) |
147 | assert isinstance(special.name, text_type) | |
143 | assert isinstance(special.name, str) | |
148 | 144 | |
149 | 145 | def test_traversal(self): |
150 | 146 | start = self.rorepo.commit("a4d06724202afccd2b5c54f81bcf2bf26dea7fff") |
275 | 271 | |
276 | 272 | def test_name_rev(self): |
277 | 273 | name_rev = self.rorepo.head.commit.name_rev |
278 | assert isinstance(name_rev, string_types) | |
274 | assert isinstance(name_rev, str) | |
279 | 275 | |
280 | 276 | @with_rw_repo('HEAD', bare=True) |
281 | 277 | def test_serialization(self, rwrepo): |
288 | 284 | # create a commit with unicode in the message, and the author's name |
289 | 285 | # Verify its serialization and deserialization |
290 | 286 | 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 | |
293 | 289 | |
294 | 290 | cmt.message = u"üäêèß" |
295 | 291 | self.assertEqual(len(cmt.message), 5) |
9 | 9 | from git import ( |
10 | 10 | GitConfigParser |
11 | 11 | ) |
12 | from git.compat import string_types | |
13 | 12 | from git.config import _OMD, cp |
14 | 13 | from git.test.lib import ( |
15 | 14 | TestCase, |
156 | 155 | num_options += 1 |
157 | 156 | val = r_config.get(section, option) |
158 | 157 | 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)) | |
160 | 159 | assert val |
161 | 160 | assert "\n" not in option |
162 | 161 | assert "\n" not in val |
1 | 1 | from stat import S_IFDIR, S_IFREG, S_IFLNK |
2 | 2 | from os import stat |
3 | 3 | import os.path as osp |
4 | from unittest import skipIf, SkipTest | |
4 | from unittest import SkipTest | |
5 | 5 | |
6 | 6 | from git import Git |
7 | from git.compat import PY3 | |
8 | 7 | from git.index import IndexFile |
9 | 8 | from git.index.fun import ( |
10 | 9 | aggressive_tree_merge |
281 | 280 | statbuf = stat(gitdir) |
282 | 281 | assert_true(statbuf.st_mode & S_IFDIR) |
283 | 282 | |
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') | |
290 | 283 | def test_tree_entries_from_data_with_failing_name_decode_py3(self): |
291 | 284 | r = tree_entries_from_data(b'100644 \x9f\0aaa') |
292 | 285 | assert r == [(b'aaa', 33188, '\udc9f')], r |
16 | 16 | Repo, |
17 | 17 | cmd |
18 | 18 | ) |
19 | from git.compat import PY3, is_darwin | |
19 | from git.compat import is_darwin | |
20 | 20 | from git.test.lib import ( |
21 | 21 | TestBase, |
22 | 22 | patch, |
60 | 60 | |
61 | 61 | def test_call_unpack_args_unicode(self): |
62 | 62 | 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' | |
67 | 64 | assert_equal(args, [mangled_value]) |
68 | 65 | |
69 | 66 | def test_call_unpack_args(self): |
70 | 67 | 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' | |
75 | 69 | assert_equal(args, ['git', 'log', '--', mangled_value]) |
76 | 70 | |
77 | 71 | @raises(GitCommandError) |
24 | 24 | GitCommandError, |
25 | 25 | CheckoutError, |
26 | 26 | ) |
27 | from git.compat import string_types, is_win, PY3 | |
27 | from git.compat import is_win | |
28 | 28 | from git.exc import ( |
29 | 29 | HookExecutionError, |
30 | 30 | InvalidGitRepositoryError |
387 | 387 | self.assertEqual(len(e.failed_files), 1) |
388 | 388 | self.assertEqual(e.failed_files[0], osp.basename(test_file)) |
389 | 389 | 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) | |
391 | 391 | self.assertEqual(len(e.valid_files), 0) |
392 | 392 | with open(test_file, 'rb') as fd: |
393 | 393 | s = fd.read() |
820 | 820 | asserted = True |
821 | 821 | assert asserted, "Adding using a filename is not correctly asserted." |
822 | 822 | |
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)""") | |
827 | 823 | @with_rw_directory |
828 | 824 | def test_add_utf8P_path(self, rw_dir): |
829 | 825 | # NOTE: fp is not a Unicode object in python 2 (which is the source of the problem) |
21 | 21 | GitCommandError |
22 | 22 | ) |
23 | 23 | from git.cmd import Git |
24 | from git.compat import string_types | |
25 | 24 | from git.test.lib import ( |
26 | 25 | TestBase, |
27 | 26 | with_rw_repo, |
115 | 114 | self.assertGreater(len(results), 0) |
116 | 115 | self.assertIsInstance(results[0], FetchInfo) |
117 | 116 | for info in results: |
118 | self.assertIsInstance(info.note, string_types) | |
117 | self.assertIsInstance(info.note, str) | |
119 | 118 | if isinstance(info.ref, Reference): |
120 | 119 | self.assertTrue(info.flags) |
121 | 120 | # END reference type flags handling |
132 | 131 | self.assertIsInstance(results[0], PushInfo) |
133 | 132 | for info in results: |
134 | 133 | self.assertTrue(info.flags) |
135 | self.assertIsInstance(info.summary, string_types) | |
134 | self.assertIsInstance(info.summary, str) | |
136 | 135 | if info.old_commit is not None: |
137 | 136 | self.assertIsInstance(info.old_commit, Commit) |
138 | 137 | if info.flags & info.ERROR: |
35 | 35 | BadName, |
36 | 36 | GitCommandError |
37 | 37 | ) |
38 | from git.compat import ( | |
39 | PY3, | |
40 | is_win, | |
41 | string_types, | |
42 | win_encode, | |
43 | ) | |
44 | 38 | from git.exc import ( |
45 | 39 | BadObject, |
46 | 40 | ) |
59 | 53 | from git.test.lib import with_rw_directory |
60 | 54 | from git.util import join_path_native, rmtree, rmfile, bin_to_hex |
61 | 55 | |
62 | import functools as fnt | |
63 | 56 | import os.path as osp |
64 | 57 | |
65 | 58 | |
218 | 211 | cloned = Repo.clone_from(original_repo.git_dir, osp.join(rw_dir, "clone"), env=environment) |
219 | 212 | |
220 | 213 | 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") | |
221 | 220 | |
222 | 221 | @with_rw_directory |
223 | 222 | def test_clone_from_pathlib(self, rw_dir): |
435 | 434 | # test the 'lines per commit' entries |
436 | 435 | tlist = b[0][1] |
437 | 436 | assert_true(tlist) |
438 | assert_true(isinstance(tlist[0], string_types)) | |
437 | assert_true(isinstance(tlist[0], str)) | |
439 | 438 | assert_true(len(tlist) < sum(len(t) for t in tlist)) # test for single-char bug |
440 | 439 | |
441 | 440 | # BINARY BLAME |
496 | 495 | """) |
497 | 496 | @with_rw_repo('HEAD', bare=False) |
498 | 497 | 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)): | |
503 | 499 | base = rwrepo.working_tree_dir |
504 | 500 | files = (join_path_native(base, u"%i_test _myfile" % run), |
505 | 501 | join_path_native(base, "%i_test_other_file" % run), |
519 | 515 | num_test_untracked += join_path_native(base, utfile) in files |
520 | 516 | self.assertEqual(len(files), num_test_untracked) |
521 | 517 | |
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] | |
527 | 518 | repo_add(untracked_files) |
528 | 519 | self.assertEqual(len(rwrepo.untracked_files), (num_recently_untracked - len(files))) |
529 | 520 | # end for each run |
7 | 7 | |
8 | 8 | import git |
9 | 9 | from git.cmd import Git |
10 | from git.compat import string_types, is_win | |
10 | from git.compat import is_win | |
11 | 11 | from git.exc import ( |
12 | 12 | InvalidGitRepositoryError, |
13 | 13 | RepositoryDirtyError |
78 | 78 | self.failUnlessRaises(InvalidGitRepositoryError, getattr, sm, 'branch') |
79 | 79 | |
80 | 80 | # branch_path works, as its just a string |
81 | assert isinstance(sm.branch_path, string_types) | |
81 | assert isinstance(sm.branch_path, str) | |
82 | 82 | |
83 | 83 | # some commits earlier we still have a submodule, but its at a different commit |
84 | 84 | smold = next(Submodule.iter_items(rwrepo, self.k_subm_changed)) |
12 | 12 | import ddt |
13 | 13 | |
14 | 14 | from git.cmd import dashify |
15 | from git.compat import string_types, is_win | |
15 | from git.compat import is_win | |
16 | 16 | from git.objects.util import ( |
17 | 17 | altz_to_utctz_str, |
18 | 18 | utctz_to_altz, |
186 | 186 | |
187 | 187 | # now that we are here, test our conversion functions as well |
188 | 188 | utctz = altz_to_utctz_str(offset) |
189 | self.assertIsInstance(utctz, string_types) | |
189 | self.assertIsInstance(utctz, str) | |
190 | 190 | self.assertEqual(utctz_to_altz(verify_utctz(utctz)), offset) |
191 | 191 | # END assert rval utility |
192 | 192 |
12 | 12 | import re |
13 | 13 | import shutil |
14 | 14 | import stat |
15 | from sys import maxsize | |
15 | 16 | import time |
16 | 17 | from unittest import SkipTest |
17 | 18 | |
30 | 31 | from git.compat import is_win |
31 | 32 | import os.path as osp |
32 | 33 | |
33 | from .compat import ( | |
34 | MAXSIZE, | |
35 | defenc, | |
36 | PY3 | |
37 | ) | |
38 | 34 | from .exc import InvalidGitRepositoryError |
39 | 35 | |
40 | 36 | |
591 | 587 | ('email', env_email, cls.conf_email, default_email)): |
592 | 588 | try: |
593 | 589 | val = os.environ[evar] |
594 | if not PY3: | |
595 | val = val.decode(defenc) | |
596 | # end assure we don't get 'invalid strings' | |
597 | 590 | setattr(actor, attr, val) |
598 | 591 | except KeyError: |
599 | 592 | if config_reader is not None: |
786 | 779 | can never be obtained.""" |
787 | 780 | __slots__ = ("_check_interval", "_max_block_time") |
788 | 781 | |
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): | |
790 | 783 | """Configure the instance |
791 | 784 | |
792 | 785 | :param check_interval_s: |
939 | 932 | class NullHandler(logging.Handler): |
940 | 933 | def emit(self, record): |
941 | 934 | 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 |
77 | 77 | py_modules=['git.' + f[:-3] for f in os.listdir('./git') if f.endswith('.py')], |
78 | 78 | package_data={'git.test': ['fixtures/*']}, |
79 | 79 | package_dir={'git': 'git'}, |
80 | python_requires='>=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', | |
80 | python_requires='>=3.4', | |
81 | 81 | install_requires=requirements, |
82 | 82 | tests_require=requirements + test_requirements, |
83 | 83 | zip_safe=False, |